During development of a small android app, I am having problem in running an alarm manager, after the app is terminated by the user. While the app is running in the foreground or background, everything works fine.
I did the following steps:
AndroidManifest.xml
<receiver android:name="MyBroadcastReceiver" ></receiver>
MainActivity.java
Within the OnClick method of a button, I call
startAlert( x*60*1000);
x is a class-wide visible variable
public void startAlert(long timeInMillis){
Intent intent = new Intent(this, MyBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), 234324243, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,System.currentTimeMillis()+(timeInMillis),pendingIntent);
}
Toast.makeText(this, "Alarm in " + x + " Minuten",Toast.LENGTH_LONG).show();
}
MyBroacastReciever.java
public void onReceive(Context context, Intent intent) {
MediaPlayer player = MediaPlayer.create(context,MainActivity.link);
player.start();
Toast.makeText(context, "Alarm....", Toast.LENGTH_LONG).show();}
What should I do to get the alarmManager successfully running, after the app is closed?
You could put the alarm manager in the service. The foreground service is used to keep our application alive even though the main application has been quit by the user. And then the alarm manager could trigger the code in the broadcast receiver class
Related
I am working on an alarm application.
In this, I am using a broadcast receiver and alarm manager. When the alarm goes off the onReceive method is called and then from the onReceive method, I am calling startActivity to start an intent
BUT the problem that I am facing is that in some devices activity is not getting started when the app is in the background or killed.
In onReceive method, I have three things:
Toast
RingtoneManager
Intent
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "In broadcast receiver", Toast.LENGTH_LONG).show();
Bundle args = intent.getBundleExtra(Constants.BROADCAST_RECEIVER_BUNDLE);
Alarms alarms = (Alarms) args.getSerializable(Constants.ALARM_OBJECT);
int alarmRequestCode = args.getInt(Constants.ALARM_REQUEST_CODE);
Intent OpenAppIntent = new Intent();
// I also tried with adding classes in intent object directly eg new Intent(context, MyActivity.class) but no luck
OpenAppIntent.setClass(context,com.example.MyActivity.class);
OpenAppIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
OpenAppIntent.putExtra(Constants.BROADCAST_RECEIVER_BUNDLE , args);
context.startActivity(OpenAppIntent);
Uri alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
if (alarmUri == null) {
alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
}
Ringtone ringtone = RingtoneManager.getRingtone(context, alarmUri);
ringtone.play();
}
Now we have two cases
When we have all three items in onReceive method ( toast, ringtone manager and intent ) - Then toast and ringtone is getting played and displayed respectively and activity is not getting started
When we remove the ringtone manager from onReceive method ( toast and intent ) - Then Toast is also not getting displayed ( activity is not started as well )
Devices in which this problem is noticed are Gionee F9, Motorola g5s, and Redmi k20 pro. Also, sometimes the same thing happens with Nokia 7 Plus
Please tell me what's wrong with the code or what is the best way to start an activity when the broadcast is received.
Test 1
Instead of starting activity I tried displaying a fullscreen notification as shown here and as suggested in a comment but unable to do so because of Error Non-static method startForeground(int, notification) cannot be referenced from a static context
#Override
public void onReceive(Context context, Intent intent) {
Intent notificationIntent = new Intent(context, MyActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable(Constants.ALARM_OBJECT , alarms);
notificationIntent.putExtra(Constants.BROADCAST_RECEIVER_BUNDLE , bundle);
PendingIntent pendingIntent = PendingIntent.getActivity(context,
0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(context, CHANNEL_ID)
.setContentTitle(Constants.APP_NAME)
.setContentText("Stop the alarm")
.setSmallIcon(R.drawable.logo_inner)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setFullScreenIntent(pendingIntent, true)
.build();
Service.startForeground(1, notification); // Non-static method startForeground(int, notification) cannot be referenced from a static context
}
Test 2
I Also tried starting foreground service directly from the onReceive method but the same problem is occurring as with the starting activity. I also tried debugging by placing breakpoints on the onCreate method of service but onCreate never get called these devices ( Gionee F9, Motorola g5s, and Redmi k20 pro )
#Override
public void onReceive(Context context, Intent intent) {
Intent alarmServiceIntent = new Intent(context, AlarmSoundService.class);
Bundle alarmServiceBundle = new Bundle();
alarmServiceBundle.putSerializable(Constants.ALARM_OBJECT , alarms );
alarmServiceIntent.putExtra(Constants.ALARM_BUNDLE , alarmServiceBundle);
// startService(alarmServiceIntent);
ContextCompat.startForegroundService(context, alarmServiceIntent);
}
Any suggestions will be appreciated.
Thank you
I am starting to learn about the AlarmManager, and I want to fire a broadcast to fetch some info from a server. The documentation is clear about the intents and the alarms, but I cannot find anything on how the receiving end should look.
This is my alarm code:
AlarmManager aMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
aMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 10000,
AlarmManager.INTERVAL_FIFTEEN_MINUTES, pendingIntent);
and my AlarmReceiver is like this:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(MainActivity.TAG, "Received intent");
}
}
But nothing happens. I added a button to just fire the broadcast like this:
public void btnTrigger_onClick(View view) {
Intent i = new Intent(this, AlarmReceiver.class);
sendBroadcast(i);
}
and also nothing happens here.
I have used broadcasts before, but only with registerReceiver, but I do not want to process the broadcast in my Activity now.
Explicit broadcasts — ones where the Intent has the component name (i.e., class) — require a <receiver> element in the manifest in order to work.
My alarm code is working fine as default ringtone is playing well on time. But not able to stop the alarm tone. In receiver class I inserted the following code.
try {
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
Ringtone r = RingtoneManager.getRingtone(context, notification);
r.play();
} catch (Exception e) {
e.printStackTrace();
}
I also inserted the code for cancel the alarm in main class, which is also working well with the code
alarmMgr.cancel(pendingIntent);
But once the default ringtone start playing and user want to stop this by stop button then it is not working.
In main class with stopbutton.setOnClickListener I inserted the following code
Intent intent = new Intent(getBaseContext(), Reciver.class);
stopService(intent);
I think it can be stop by r.stop();
but how should I use it in stop button.
Make a Global instance of Ringtone and on button click use r.stop() use this link to perform the operation in service. Let me know if I understood the question correctly.
A broadcast intent registered while you schedule the alarm but to ensure a cancel you have to registered another intent that would boradcast cancel event to system.
Look at piece of code working fine during a cancel event.
Intent intent = new Intent(this, YourReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 123, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
I am making a small android APP and I want to have some code that runs once a day at 6AM. When the app is not running to update some parameters and send a notification to the user telling them to enter the app. Can someone help me by telling me the best way to go about doing this?
You can do it like so with alarm manager, pending intent and a broadcast receiver. This code will wake up the device every two hours:
AlarmManager alarmManager = (AlarmManager)this.getSystemService(ALARM_SERVICE);
Calendar cal = Calendar.getInstance();
//set the alarms to start in the time period
cal.add(Calendar.MILLISECOND,60000);
Intent i = new Intent(this, AlarmBroadcastReceiver.class);
PendingIntent getSqlUpdatesTimer = PendingIntent.getBroadcast(this, 0, i, 0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 7200000, getSqlUpdatesTimer);
And your broadcast receiver:
public class AlarmBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
if (intent != null) {
PowerManager pm = (PowerManager)context.getSystemService(context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
wl.acquire();
//Some code to do your task
wl.release();
}
}
}
You also need to have the wakelock permission set in your Manifest.
I have some doubts that I would like to clear regarding the AlarmManager class in Android.
I have an app that needs to:
Allow the user to set a time.
Start an alarm.
Then, even if the app is closed, it should start up on the preset time and do a certain function (like button.performClick()) in the main activity.
So, I have successfully created an activity called alarm.java, created the layout in res\layout and added it to AndroidManifest.xml. Also, I have successfully set the alarm as follows in my alarm.java class:
onCreate(){
alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
intent = new Intent(context, MyActivity.class);
pi = PendingIntent.getBroadcast(this.getApplicationContext(), ALARM_ID, intent, 0);
}
onClick(){
cal.setTimeInMillis(System.currentTimeMillis());
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, minute);
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi);
Toast.makeText(getApplicationContext(), "Alarm Set For " + hour + ":" + minute + " " + ampm, Toast.LENGTH_LONG).show();
}
Now, in my MyActivity.java class, which is the main activity, I have added the BroadcastReceiver
public BroadcastReceiver AlarmReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
/*This is the part I got from SO for starting an activity from `BroadcastReceiver`
Intent i = new Intent();
i.setClassName("com.kanishka.nightstalker.homeautomation", "com.kanishka.nightstalker.homeautomation.MainActivity");
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);*/
Toast.makeText(getApplicationContext(), "APP STARTED", Toast.LENGTH_LONG).show();
button.performClick();
}
};
Obviously, this method isn't working as I see no Toast popping up after elapsed time. I kinda understand what the issue is, and I should be using a Service for this. But from what I know, AlarmManager itself runs in the background and SHOULD trigger the BroadcastReceiver of MyActivity.java on elapsed time. Where am I going wrong?
Where am I going wrong?
You are using setInexactRepeating(). Here, "inexact" means "not exact", and so the alarm will occur sometime within INTERVAL_DAY of your requested time.
You are taking the current time, then setting the hour and minute, which could result in a time in the past.
You are creating an Intent for MyActivity, which is probably not a BroadcastReceiver (or, if it is, MyActivity is a very odd name to choose).
If you want the alarm to go off "even if the app is closed", then you need to use a BroadcastReceiver that is registered in the manifest.
It is not possible to "do a certain function (like button.performClick()) in the main activity", as there will not be an activity "if the app is closed".