Does anyone have faced somthing like this?
Here is the scenario: I want to build a separate class, from where I can stop and start an alarm, via static methods. From the Activity classes, I want to call the methods from this class that I'm planning to build, but the point is that, even tough I'm planning to pass the Activity context to the static methods, when I pass "context" to my AlarmManager object, Android Studio is passing me the following information which is printed on the screen above and I have to admit, that I just can't the point of the message.
What am I missing? I have been looking on Google, but It seems that this situation here is not something so common.
IMPORTAT: Regarding the image above, I tried to use just the context (code below), without using getApplicationContext(), but it didn't worked as well...
Here is the code:
package com.mydomain.myapp;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
public class AlarmManager {
private static AlarmManager alarm;
private static PendingIntent pIntent;
//start alarm
public static void setAlarm(Context context, int alarmId, long alarmTime) {
Intent startAlarmIntent;
long beginAt = SystemClock.elapsedRealtime() + 60 * 1000;
long interval = 300000; // 5 minutes
alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
startAlarmIntent = new Intent(context, AlarmBroadcastReceiver.class);
pIntent = PendingIntent.getBroadcast(context, alarmId, startAlarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarm.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, beginAt, interval, pIntent);
}
//stop alarm
public static void stopAlarm(Context context, int id) {
Intent stopAlarmIntent;
alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
stopAlarmIntent = new Intent(context, AlarmBroadcastReceiver.class);
pIntent = PendingIntent.getBroadcast(context, id, stopAlarmIntent, 0);
alarm.cancel(pIntent);
pIntent.cancel();
}
}
Can anyone give a hand with this, please? Tks!
You created a class named AlarmManager. This is not the same as Android's AlarmManager, and you are trying to cast the value returned by getSystemService() to your AlarmManager, not android.app.AlarmManager.
The simplest solution is to change the name of your class to be something else.
Related
I'm doing a bluetooth scan event every 2 minutes to check if a specific device is nearby and can be detected through bluetooth. It's a service as I want it to run in the background.
I would like to know why setRepeat fluctuates after some time, the longest interval was 10 minutes. I'm setting it to fire every 2 minutes.
var intent = Intent(context, Alarm::class.java);
var am = context.getSystemService(AppCompatActivity.ALARM_SERVICE) as AlarmManager
intent.action = "from.alarm.clock";
var pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() , 1000 * 60 * 2, getBroadcast(this, 0, intent, 0))
UPDATE
Still haven't found the best answer for this problem.
You have to create an Alarm receiver that triggers exactly 2 minutes by recursive call. Android does not allow frequent precise wakeup calls as it might drain battery faster. This is a workaround to get your calls triggered in exact intervals.
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import java.util.concurrent.TimeUnit;
public class NotificationAlarmReceiver extends BroadcastReceiver {
public static final int REQUEST_CODE = 1234;
public static final long PING_FREQ = TimeUnit.MINUTES.toMillis(2);
#Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, NotificationService.class));
initNotification(context);
}
private void initNotification(Context context) {
Intent intent = new Intent(context, NotificationAlarmReceiver.class);
final PendingIntent pIndent = PendingIntent.getBroadcast(context, NotificationAlarmReceiver.REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + PING_FREQ, pIndent);
}
}
Refer this site and you will get a good idea on how to use Boradcast to get periodic calls to a service. Reference codepath.com
I'm developing an app that should perform a certain task every 60 seconds. Since there's some accuracy problems with alarms in Android 4.4+, where all alarms are inexact, I've opted for the chained model: A BroadcastReceiver fires the first alarm, and each alarm in turn sets the next alarm.
The problem is that, even though I'm setting the alarms at intervals of 60 seconds (60000 ms), the alarms trigger at 5 second intervals, and sometimes even less. I've tested the code on my Nexus 5 (Android 5.1.1) and on an Android 5.0.1 emulator, both giving the same result.
I should point out that both receivers are registered on the AndroidManifest and my application has the RECEIVE_BOOT_COMPLETED permission.
EDIT: setExact() causes exactly the same problem
StartupReceiver.java (BroadcastReceiver for BOOT_COMPLETED):
public class StartupReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Got the BOOT_COMPLETED signal");
// Get the first alarm to be invoked immediately
AlarmReceiver.setNextScanAlarm(context, 0);
}
}
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Start the service
Intent startServiceIntent = new Intent(context, BackgroundService.class);
startServiceIntent.putExtra("interval", 60000);
startServiceIntent.putExtra("action", "scan");
context.startService(startServiceIntent);
// Schedule the next alarm
setNextScanAlarm(context, 60000);
}
public static void setNextScanAlarm(Context context, int interval) {
Intent scanIntent = new Intent(context, AlarmReceiver.class);
scanIntent.putExtra("interval", interval);
scanIntent.putExtra("action", "scan");
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context,
0,
scanIntent,
PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
interval,
pendingIntent);
}
}
What could be the problem?
I believe because this is an alarm clock when calling
alarmManager.set(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
interval,
pendingIntent);
The variable you are calling interval is the amount of time you want to elapse UNTIL the next alarm , but when you think about this when does it know to start? More so, when does time actually equal zero? When you create it? No. When you call .set()? No. It is actually zero upon BOOT. So you are asking it to launch 60 seconds after boot, and your asking for this everytime, this time will have already elapsed.
This is where the confusion is, and where you should probably just use a call like new
Handler.postDelayed(Runnnable r, 60000) instead of an alarm Manager. It will be much more accurate and will not be subject to some problems with understanding the Android Operating System and its alarms/clocks/etc/etc.
But for your specific case I believe you could solve it by accessing System function calls/variables. So inside of your function setNextScanAlarm() I believe it would look like this:
public static void setNextScanAlarm(Context context, int interval) {
//create the intent the same way as before
Intent scanIntent = new Intent(context, AlarmReceiver.class);
scanIntent.putExtra("interval", interval);
scanIntent.putExtra("action", "scan");
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context,
0,
scanIntent,
PendingIntent.FLAG_ONE_SHOT);
//create new variables to calculate the correct time for this to go off
long timeRightNow = System.elapsedRealTime() //use something else if you change AlarmManager type
long timeWhenIShouldGoOff = timeRightNow + interval;
//use the new timeWhenIShouldGoOff variable instead of interval
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
timeWhenIShouldGoOff,
pendingIntent);
}
See my answer to a similar question.
I use postDelayed() instead of AlarmManager for the short time intervals (less than 1 minute), and AlarmManager for long.
I have written a class to manage setting and cancelling alarms (via AlarmManager). To allow for easy cancelling of alarms I have linked the intents that set the alarm to a "name" and I have stored these in a HashMap as follows:
private HashMap<String, PendingIntent> alarmIntentsMap = new HashMap<String, PendingIntent>();
An example of a method that sets an alarm is:
public void AddServiceAlarm(Context context, Intent intent, int type, long triggerAtMillies, long intervalMillies, String name) throws Exception
{
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = null;
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
alarmManager.setRepeating(type, triggerAtMillies, intervalMillies, pendingIntent);
alarmIntentsMap.put(name, pendingIntent);
}
And the method that cancels an alarm is:
public void CancelAlarm(Context context, String name)
{
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(alarmIntentsMap.get(name));
}
These methods use the global:
private AlarmManager alarmManager;
This seemed like, to me at least, an elegant way to start and cancel alarms in a system. Is storing references to PendingIntents in the map bad? Would this be considered bad practice in android? I am not very experienced with Android and would love to know.
I took some code from some questions here in SO as well as some other website and I came up with a reasonable solution.
What I am trying to do: I need to shutdown the app after 2 minutes of inactivity. So The idea is to start up the alarm service when our app goes in into 'onPause' and cancel the service when our app goes into 'onResume'.
What I currently Have: Here is the relevant code that is currently running. My issue is that the TimeoutService java file is never being 'onCreated'. Does simply calling AlarmManager.set NOT start up the pending intent?
The Timeout.java File
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class Timeout
{
private static final int REQUEST_ID = 0;
private static final long DEFAULT_TIMEOUT = 2 * 60 * 1000; // 2 minutes
public static final String INTENT_TIMEOUT = "timeoutintent";
public static void start(Context ctx)
{
//long triggerTime = System.currentTimeMillis() + DEFAULT_TIMEOUT;
long triggerTime = System.currentTimeMillis() + (5000);
AlarmManager am = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(ctx, TimeoutService.class);
PendingIntent pi = PendingIntent.getBroadcast(ctx, REQUEST_ID, intent, 0);
am.set(AlarmManager.RTC, triggerTime, pi);
}
public static void cancel(Context ctx)
{
AlarmManager am = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(ctx, TimeoutService.class);
PendingIntent pi = PendingIntent.getBroadcast(ctx, REQUEST_ID, intent, 0);
am.cancel(pi);
}
}
LockingActivity File. This is used as a superclass to all of my Activities.
import android.app.Activity;
import android.widget.Toast;
public class LockingActivity extends Activity
{
#Override
protected void onPause()
{
super.onPause();
Timeout.start(this);
}
#Override
protected void onResume()
{
super.onResume();
Timeout.cancel(this);
checkShutdown();
}
private void checkShutdown()
{
if ( AppVM.isShutDown() )
{
Toast.makeText(this, "Shuting Down", 1).show();
finish();
}
}
}
I could send over the TimeoutService file as well, but it's just a typical service file. The problem is the TimeoutService class is never being instanced, so I can't imagine the problem would lie in that class.
I think you are complicating things with an alarm. Use a Handler and postdelayed() to set a Runnable in two minutes, all in your main activity. Any user interaction cancels the post and sets a new one for the next two minutes. The runnable needs only yourActivity.finish();
Follow this answer here: Count for 45 seconds, pause for 20 then repeat with different title for an example of a timer and how to remove the callbacks.
Hi Try using PendingIntent.FLAG_CANCEL_CURRENT flag for your Pending Intent.
PendingIntent pi = PendingIntent.getBroadcast(ctx, REQUEST_ID, intent,PendingIntent.FLAG_CANCEL_CURRENT);
Make Alarm manager as RTC_WAKEUP to wake up device if it is going off some where and check.
With this you need to register a broadcast receiver and fire intent with some action when alarm goes off. Set action to same intent you are using for pending intent.
Start your service in your receiver.
Your this broadcast receiver should be able to listen to action fired by this Intent when Alarm goes OFF.
Intent intent = new Intent(SCH_ALARM_ACTION);
intent.setClass(getBaseContext(), SchAlarmReciever.class);
registerReceiver(new SchAlarmReciever(), new IntentFilter(SCH_ALARM_ACTION));
PendingIntent pi = PendingIntent.getBroadcast(getBaseContext(),
0,
intent,
PendingIntent.FLAG_CANCEL_CURRENT);
I need to trigger a block of code after 20 minutes from the AlarmManager being set.
Can someone show me sample code on how to use an AlarmManager in ِAndroid?
I have been playing around with some code for a few days and it just won't work.
"Some sample code" is not that easy when it comes to AlarmManager.
Here is a snippet showing the setup of AlarmManager:
AlarmManager mgr=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i=new Intent(context, OnAlarmReceiver.class);
PendingIntent pi=PendingIntent.getBroadcast(context, 0, i, 0);
mgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), PERIOD, pi);
In this example, I am using setRepeating(). If you want a one-shot alarm, you would just use set(). Be sure to give the time for the alarm to start in the same time base as you use in the initial parameter to set(). In my example above, I am using AlarmManager.ELAPSED_REALTIME_WAKEUP, so my time base is SystemClock.elapsedRealtime().
Here is a larger sample project showing this technique.
There are some good examples in the android sample code
.\android-sdk\samples\android-10\ApiDemos\src\com\example\android\apis\app
The ones to check out are:
AlarmController.java
OneShotAlarm.java
First of, you need a receiver, something that can listen to your alarm when it is triggered. Add the following to your AndroidManifest.xml file
<receiver android:name=".MyAlarmReceiver" />
Then, create the following class
public class MyAlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Alarm went off", Toast.LENGTH_SHORT).show();
}
}
Then, to trigger an alarm, use the following (for instance in your main activity):
AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, MyAlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
Calendar time = Calendar.getInstance();
time.setTimeInMillis(System.currentTimeMillis());
time.add(Calendar.SECOND, 30);
alarmMgr.set(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(), pendingIntent);
.
Or, better yet, make a class that handles it all and use it like this
Bundle bundle = new Bundle();
// add extras here..
MyAlarm alarm = new MyAlarm(this, bundle, 30);
this way, you have it all in one place (don't forget to edit the AndroidManifest.xml)
public class MyAlarm extends BroadcastReceiver {
private final String REMINDER_BUNDLE = "MyReminderBundle";
// this constructor is called by the alarm manager.
public MyAlarm(){ }
// you can use this constructor to create the alarm.
// Just pass in the main activity as the context,
// any extras you'd like to get later when triggered
// and the timeout
public MyAlarm(Context context, Bundle extras, int timeoutInSeconds){
AlarmManager alarmMgr =
(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, MyAlarm.class);
intent.putExtra(REMINDER_BUNDLE, extras);
PendingIntent pendingIntent =
PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
Calendar time = Calendar.getInstance();
time.setTimeInMillis(System.currentTimeMillis());
time.add(Calendar.SECOND, timeoutInSeconds);
alarmMgr.set(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(),
pendingIntent);
}
#Override
public void onReceive(Context context, Intent intent) {
// here you can get the extras you passed in when creating the alarm
//intent.getBundleExtra(REMINDER_BUNDLE));
Toast.makeText(context, "Alarm went off", Toast.LENGTH_SHORT).show();
}
}
What you need to do is first create the intent you need to schedule. Then obtain the pendingIntent of that intent. You can schedule activities, services and broadcasts. To schedule an activity e.g MyActivity:
Intent i = new Intent(getApplicationContext(), MyActivity.class);
PendingIntent pi = PendingIntent.getActivity(getApplicationContext(),3333,i,
PendingIntent.FLAG_CANCEL_CURRENT);
Give this pendingIntent to alarmManager:
//getting current time and add 5 seconds in it
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 5);
//registering our pending intent with alarmmanager
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis(), pi);
Now MyActivity will be launched after 5 seconds of the application launch, no matter you stop your application or device went in sleep state (due to RTC_WAKEUP option).
You can read complete example code Scheduling activities, services and broadcasts #Android
I wanted to comment but <50 rep, so here goes. Friendly reminder that if you're running on 5.1 or above and you use an interval of less than a minute, this happens:
Suspiciously short interval 5000 millis; expanding to 60 seconds
See here.
Some sample code when you want to call a service from the Alarmmanager:
PendingIntent pi;
AlarmManager mgr;
mgr = (AlarmManager)ctx.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(DataCollectionActivity.this, HUJIDataCollectionService.class);
pi = PendingIntent.getService(DataCollectionActivity.this, 0, i, 0);
mgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() , 1000, pi);
You dont have to ask userpermissions.
An AlarmManager is used to trigger some code at a specific time.
To start an Alarm Manager you need to first get the instance from the System. Then pass the PendingIntent which would get executed at a future time that you specify
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(context, MyAlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
int interval = 8000; //repeat interval
manager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
You need to be careful while using the Alarm Manager.
Normally, an alarm manager cannot repeat before a minute. Also in low power mode, the duration can increase to up to 15 minutes.