onReceive method of BroadcastReceiver does not get called - java

I am using AlarmManager to create an alarm by playing a sound. To do this, I first create a PendingIntent, for which I have to create a class called AlarmReceiver, which extends BroadcastReceiver. In this new class, I override the onReceive method, in which I also start the sound. However, from what I've tested, the onReceive method is not even called from the MainActivity.
After some research, I found out that I should declare the receiver in the manifest file. Thus, I declare it, but it doesn't recognize the name of the class, AlarmReceiver, it shows it in red. I don't fully understand how to properly declare in the manifest file. I know there are other similar SO questions and I've checked them all, but I am still not able to get it work.
The code for the MainActivity is:
package com.example.alarmsound;
public class MainActivity extends AppCompatActivity {
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
final MediaPlayer mp = MediaPlayer.create(context, R.raw.music);
Log.d("Music", "It went here.");
mp.start();
Button stop = (Button) findViewById(R.id.stopAlarm);
stop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mp.stop();
}
});
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
Calendar t = Calendar.getInstance();
t.add(Calendar.SECOND, 5);
Context context = this;
AlarmManager alarmMgr;
alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmMgr.set(AlarmManager.RTC_WAKEUP, t.getTimeInMillis(), pendingIntent);
}
}
And the declaration in Manifest is:
<receiver android:name="com.example.alarmsound.AlarmReceiver">
<intent-filter>
<action android:name="com.example.alarmsound.MainActivity" />
</intent-filter>
</receiver>
I could also be doing something wrong in the MainActivity, even though I think I'm doing everything right there.

Change the first line of the receiver declaration to:
<receiver android:name="com.example.alarmsound.MainActivity$AlarmReceiver">. That should let Android detect your class through the manifest.
The $ symbol is used to reference inner classes in the Android Manifest.

Okay. So as you mentioned the the AlarmReceiver class cannot be recognized in the AndroidManifest.xml. So I tried it out in Android Studio and it seems the format should be something like this:
<receiver android:name=".MainActivity$AlarmReceiver">
<intent-filter>
<action android:name="com.example.alarmsound.MainActivity" />
</intent-filter>
</receiver>
Tried running the code but it returns an error where the app crashes. Anyways, I think that's a different concern now.

Related

AlarmManager gets canceled after a while

I am writing my first app and I'm trying to fire a notification at a specific time every day that reports some information.
For starter, I created the following class that I use to restart the alarms after a reboot and to start the alarms from the main app (this to have just one piece of code to reuse).
public class SetAlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
startReminderService(context);
}
public void checkServiceRunning(Context context) {
Intent reminderIntent = new Intent(context, AlarmReceiver.class);
reminderIntent.setAction("MyReminder");
// I check if a reminder is already active
boolean reminderActive = (PendingIntent.getBroadcast(context, REMINDER_SERVICE,
reminderIntent,
PendingIntent.FLAG_NO_CREATE) != null);
Log.d("test", "The reminder is active?" + reminderActive);
if (!reminderActive) {
startReminderService(context);
}
}
public void startReminderService(Context context) {
Calendar serviceNotificationTime = Calendar.getInstance();
serviceNotificationTime.set(Calendar.HOUR_OF_DAY, 9);
serviceNotificationTime.set(Calendar.MINUTE, 0);
serviceNotificationTime.set(Calendar.SECOND, 0);
Intent reminderIntent = new Intent(context, AlarmReceiver.class);
reminderIntent.setAction("MyReminder");
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context,
REMINDER_SERVICE,
reminderIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager serviceAlarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
serviceAlarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
serviceNotificationTime.getTimeInMillis(),
AlarmManager.INTERVAL_DAY,
pendingIntent);
if (pendingIntent != null) {
Log.d("test", "Background service set up and running.");
} else {
Log.d("test", "Failed to set up background service!");
}
}
}
After that I updated the manifest with the following lines:
<receiver
android:name="com.mycompany.myapp.services.SetAlarmReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver
android:name="com.mycompany.myapp.services.AlarmReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="MyReminder" />
</intent-filter>
</receiver>
So far, everything goes right. When the phone reboots, the reminder is correctly restarted and (if the reminder time is in the past) it fires immediately.
The AlarmReceiver class is the following:
public class AlarmReceiver extends BroadcastReceiver {
private Context ctx;
#Override
public void onReceive(Context context, Intent intent) {
this.ctx = context;
remindStuff();
}
private void remindStuff() {
....
some code
....
// I check if the alarm is still on (probably awful, since it just fired)
SetAlarmReceiver setAlarmReceiver = new SetAlarmReceiver();
setAlarmReceiver.checkServiceRunning(ctx);
}
}
I use the same approach to check if the alarm is on from the main activity:
private void checkServicesRunning() {
SetAlarmReceiver setAlarmReceiver = new SetAlarmReceiver();
setAlarmReceiver.checkServiceRunning(getApplicationContext());
}
Everything looks correct to me, I've tried any solution I found, reading tons of questions like mine on StackOverflow but I still can't understand what I'm doing wrong.
The alarm fires correctly right after BOOT_COMPLETED is triggered by the system and it fires correctly when I just enabled the alarm (only if the notification time is in the past - f.e. when it's 10pm and the alarm must fire at 9am).
When the checkServiceRunning method runs, it tells me that the alarm is already enabled (returning true in the Logcat) but when I close the app and I re-run it after a while, the alarm looks like it's been canceled and it's being recreated by the app.
Any hint?
Thanks.
EDIT: I tried the command 'adb shell dumpsys alarm' and it actually shows my alarm running correctly so, at this point, I think the issue is something else but I cannot understand what...

onReceive from BroadcastReceiver is not called

I have a music application in which I am trying to add some action button on the notification bar.
I tried something like this:
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
Intent onPreparedIntent=new Intent("MEDIA_PLAYER_PREPARED").putExtra("CURR_SONG",songposn);
LocalBroadcastManager.getInstance(this).sendBroadcast(onPreparedIntent);
Intent notintent = new Intent(this, MainActivity.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Notification.Builder builder=new Notification.Builder(this);
PendingIntent pendingIntent=PendingIntent.getActivity(this,0,notintent,PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent prevPendingIntent=PendingIntent.getActivity
(this,1,new Intent().setAction("PREVIOUS"),PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent pausePendingIntent=PendingIntent.getActivity
(this,2,new Intent().setAction("PAUSE"),PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent nextPendingIntent=PendingIntent.getActivity
(this,3,new Intent().setAction("NEXT"),PendingIntent.FLAG_UPDATE_CURRENT);;
builder.setContentIntent(pendingIntent).setSmallIcon(R.drawable.playicon)
.addAction(R.drawable.back, "Previous", prevPendingIntent)
.addAction(R.drawable.playsmall, "Pause", pausePendingIntent)
.addAction(R.drawable.forw, "Next", nextPendingIntent)
.setTicker(songArtist)
.setOngoing(true).setContentTitle(songTitle).setContentText(songArtist);
Notification not=builder.build();
startForeground(MusicService.NOTIFY_ID,not);
}
I declared a NotificationReciever class inside this service
public class NotificationReciever extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Log.e("here","here");
String action=intent.getAction();
if(action!=null){
switch (action){
case "PREVIOUS":{
playPrev();
break;
}
case "PAUSE":{
pausePlayer();
LocalBroadcastManager.getInstance(MusicService.this).sendBroadcast(new Intent("STOP_THREAD"));
break;
}
case "NEXT":{
playNext();
break;
}
}
}
}
}
Structure looks something like this:
-MusicService extends Service
--NotificationReciever extends BroadcastReceiver
My manifest file contains reciever like this:
<receiver android:name=".MusicService$NotificationReciever">
<intent-filter>
<action android:name="PREVIOUS"/>
<action android:name="PAUSE"/>
<action android:name="NEXT"/>
</intent-filter>
</receiver>
When I run my music play, notification does come up with buttons but they don't seem to fire the onReceive function?
What am I missing here?
Update:
Followed hasif sayed answer and I seem to found an error
java.lang.RuntimeException: Unable to instantiate receiver com.example.tilak.imusicplay.MusicService$NotificationReciev‌​er: java.lang.InstantiationException:java.lang.Class has no zero argument constructor
Googling about it, I found that I have to use a static class or I have to register/unregister in the parent class.
So this is what I did:
public void onCreate() {
super.onCreate();
//
LocalBroadcastManager.getInstance(this).registerReceiver(
new NotificationReciever(),new IntentFilter("PREVIOUS"));
LocalBroadcastManager.getInstance(this).registerReceiver(
new NotificationReciever(),new IntentFilter("PAUSE"));
LocalBroadcastManager.getInstance(this).registerReceiver(
new NotificationReciever(),new IntentFilter("NEXT"));
}
PendingIntent prevPendingIntent=PendingIntent.getBroadcast
(this,1,new Intent().setAction("PREVIOUS"),PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent pausePendingIntent=PendingIntent.getBroadcast
(this,2,new Intent().setAction("PAUSE"),PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent nextPendingIntent=PendingIntent.getBroadcast
(this,3,new Intent().setAction("NEXT"),PendingIntent.FLAG_UPDATE_CURRENT);
Now I don't get this above error but onReceive is not working again.
Actually the reason why your broadcast reciever is not called when you click on pause,previous and next button is because ,you have set the pending intent to fire an acitivity,instead you have to set the pending intent to fire a boradcast
instead of this code snippet
PendingIntent nextPendingIntent=PendingIntent.getActivity
(this,3,new Intent().setAction("NEXT"),PendingIntent.FLAG_UPDATE_CURRENT);;
you have to correct it like this
PendingIntent nextPendingIntent=PendingIntent.getBroadcast
(this,3,new Intent().setAction("NEXT"),PendingIntent.FLAG_UPDATE_CURRENT);;
make corrections in all the three pending intent code which you have written
UPDATE
The reason why you still not receiving the broadcast in your Broadcast Receiver is because you are programitically registering your Receiver as LocalBroadCast
When using with PendingIntent, LocalBroadcast will not receive the Broadcast
so please remove this Line
LocalBroadcastManager.getInstance(this).registerReceiver(
new NotificationReciever(),new IntentFilter("PREVIOUS"));
LocalBroadcastManager.getInstance(this).registerReceiver(
new NotificationReciever(),new IntentFilter("PAUSE"));
LocalBroadcastManager.getInstance(this).registerReceiver(
new NotificationReciever(),new IntentFilter("NEXT"));
Instead, you only have to register the receiver in the Manifest.xml file
or
programitically you can register in code as
NotificationReciever mReciever = new NotificationReciever();
this.registerReceiver(
mReciever,new IntentFilter("PREVIOUS"));
this.registerReceiver(
mReciever,new IntentFilter("PAUSE"));
this.registerReceiver(
mReciever,new IntentFilter("NEXT"));
but if you register this programitically, make sure you unregister it while service is getting destroyed. Otherwise you may LEAK the BroadcastReceiver Object

Running background service through shortcut

So I want to launch a service from a shortcut. I know that this is not possible to do directly, so I've set up a activity with the sole purpose of starting the service.
The aim of my service is to send an intent to another app and then 5 seconds later send another so I've used a CountDownTimer to do this.
However, when I launch the Activity that starts the service from the shortcut (this is getting confusing) it launches the apps UI. I don't want this, as I want it to be a background service.
What am I doing wrong. I've only just got into development, so it could be something obvious, but I've been battling with this for a few days now.
For some reason when I run it from the service it just launches the app straight away...
When I run it straight from the invisible activity it runs properly for the 1st 5 seconds fine and then loads the app...
I can't figure out why it's loading the app at all.
I've included as much info as I can that would be relevant.
Any help is appreciated!
My service:
public class Pop1_5Service extends IntentService {
public Pop1_5Service() {
super("Pop1_5Service");
}
#Override
protected void onHandleIntent(Intent intent) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
new CountDownTimer(5000, 2500) {
public void onTick(long millisUntilFinished) {
Intent i = new Intent(INTENT_ACTION);
Bundle b = new Bundle();
b.putInt(BUNDLE_VERSION_CODE, 1);
b.putString(BUNDLE_STRING_NAME, "POP1");
b.putString(BUNDLE_STRING_VALUE, "1");
i.putExtra(BUNDLE_NAME, b);
sendBroadcast(i); }
public void onFinish() {
Intent i = new Intent(INTENT_ACTION);
Bundle b = new Bundle();
b.putInt(BUNDLE_VERSION_CODE, 1);
b.putString(BUNDLE_STRING_NAME, "POP1");
b.putString(BUNDLE_STRING_VALUE, "1");
i.putExtra(BUNDLE_NAME, b);
sendBroadcast(i); }
}
}.start();
}
}
Activity that launches service:
public class Pop1_5Activity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Intent intent = new Intent(this, Pop1_5Service.class);
startService(intent);
finish();
}
}
Subsection of Manifest:
<activity
android:name=".Pop1_5Activity"
android:theme="#android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".Pop1_5Service" />
And the 'Create a Shortcut' Activity:
public class CreateShortcutActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent shortcutintent = new Intent(this, Pop1_5Activity.class);
ShortcutIconResource iconResource = Intent.ShortcutIconResource.fromContext(this, R.drawable.ic_launcher);
Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutintent);
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "Pop1_5");
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource);
setResult(RESULT_OK, intent);
finish();
}
}
From the look of things, it looks like CreateShortcutActivity does nothing.
Your LAUNCHER is Pop1_5Activity, so when the user presses the app icon, this Activity will run, and it launches the Service.
All the code you have showed us are "invisible", the two Activities finish() themselves, and the Service is a Service.
You might want to look at how your BroadcastReceiver handles your broadcast. For instance, does it create another Activity through PendingIntent? Is the Activity created invisible?
Maybe you should try creating a pending Service instead of pending Activity in the BroadcastReceiver.

Alarm Manager wont trigger

I asked a question similar to this yesterday but have changed my code a fair bit and have a different issue now.
I have a toggle button that sets an alarm manager with a pending intent that should trigger after 5 seconds. I have it on a one shot setting, so i want the message to appear once (as later I will be implementing this for a date value).
I get no errors with this code, but I cant seem to trigger my intent that then shows my toast message.
Here's how I have defined the activity of the 'DateAlarm' class in the xml:
<activity
android:name=".DateAlarm"
android:label="#string/app_name" >
<intent-filter>
<action android:name="com.example.flybase2.DateAlarm" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Heres my my toggle button onClick method for my toggle button with the alarm manager:
case (R.id.toggleButton1):
Integer dobMonth = setDate.getMonth();
Integer dobYear = setDate.getYear();
Integer dobDate = setDate.getDayOfMonth();
Date set;
set = new Date(dobYear - 1900, dobMonth, dobDate);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, DateAlarm.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
am.set(AlarmManager.RTC_WAKEUP,System.currentTimeMillis() + (5 * 1000), pendingIntent);
break;
And my final 'DateAlarm' class that holds the action of the intent.
package com.example.flybase2;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.widget.Toast;
public class DateAlarm extends Activity {
Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Toast.makeText(context, "Appointment is today", Toast.LENGTH_LONG).show();
}
}
You have two problems:
You are using PendingIntent.getService() instead of PendingIntent.getActivity() Since DateAlarm extends Activity, you want PendingIntent.getActivity().
In DateAlarm your context variable is null. In onCreate() you should initialize it. Also note that since Activity extends Context, this variable isn't needed. However if you do want to use that variable do:
super.onCreate(savedInstanceState);
context = this;
or
Context context = this; //right from the global declaration

Get from Android BroadcastReceiver to a UI

I have a receiver that works well, but I can't seem to show a proper UI, although the toast appears correctly. As far as I can tell, this is caused by Android requiring the class to extend Activity, however, the class already extends BroadcastReceiver, so I can't do this.
So, I tried to do an Intent, but this failed too. There are no errors, but the screen doesn't show. Source code is below.
Broadcast (Method in AndyRoidAlarm)
public void setAlarm(){
Intent intent = new Intent(AndyRoidAlarm.this, Reciever.class);
PendingIntent sender = PendingIntent.getBroadcast(AndyRoidAlarm.this,
0, intent, 0);
// We want the alarm to go off 30 seconds from now.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 10);
// Schedule the alarm!
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), sender);
// Tell the user about what we did.
if (mToast != null) {
mToast.cancel();
}
mToast = Toast.makeText(AndyRoidAlarm.this, "Alarm Scheduled for 30secs", Toast.LENGTH_LONG);
mToast.show();
}
Reciever
public class Reciever extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "Alarm Received", Toast.LENGTH_LONG).show();
Intent i = new Intent();
i.setClass(context, AlarmRing.class);
}
}
Reciever V2
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "Alarm Received", Toast.LENGTH_LONG).show();
Intent foo = new Intent(context, AlarmRing.class);
//foo.putExtra("id", "id");//example, if you wish to pass custom variables
context.startActivity(foo);
}
AlarmRing
public class AlarmRing extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.alarm);
MediaPlayer mp = MediaPlayer.create(getBaseContext(), R.raw.sweetchild);
mp.start();
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.comaad.andyroidalarm"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".AndyRoidAlarm"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="com.comaad.andyroidalarm.Reciever" android:enabled="true">
<intent-filter>
<action android:name="com.comaad.andyroidalarm.Reciever"></action>
</intent-filter>
</receiver>
<activity android:name=".AlarmRing"></activity>
</application>
</manifest>
}
In a BroadcastReceiver onReceive() method, if you need a Context (e.g., to create an Intent), use the Context that is passed to you as a parameter of onReceive(). You even have this code in your onReceive() -- you're just not doing anything with the resulting Intent (e.g., calling startActivity()).
Intent foo = new Intent(this, AlarmRing.class);
foo.putExtra("id", id);//example, if you wish to pass custom variables
this.startActivity(foo);
Edit
Check out this example to use BroadcastReciever within an Activity. http://almondmendoza.com/2009/01/04/getting-battery-information-on-android/

Categories

Resources