Before closing this issue or marking as duplicate based on the title, it is different from the regular "cancel alarm using AlarmManager and PendingIntent" questions.
I am capable of creating and cancelling pending intents, as long as they are set for a time in the future and haven't gone off yet. I'm testing this using the following terminal command to view the PendingIntents before creating an alarm as well as after:
adb shell dumpsys alarm
Here is my code for scheduling alarms in my custom Alarm class:
/**
* Schedules a PendingIntent for the alarm.
* #param context Activity context
*/
public void scheduleAlarm(Context context) {
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, MyBroadcastReceiver.class);
Gson g = new Gson();
String s = g.toJson(this);
intent.putExtra("alarm", s);
String id = this.getId().replaceAll("[^0-9]+", "");
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, Integer.parseInt(id), intent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, this.getHour());
calendar.set(Calendar.MINUTE, this.getMinute());
long calendarTime = calendar.getTimeInMillis();
am.setExact(AlarmManager.RTC_WAKEUP, calendarTime, alarmIntent);
}
Not surprisingly, before creating an alarm, there was no pending intent regarding my app's alarms in the terminal output. After creating the alarm, there was 1 pending intent related to my app in the terminal output, as seen below:
+Batch{b28a2db num=1 start=619295497 end=619385497}: + RTC #0: Alarm{24e4178 tag
alarm:com.google.android.location.internal.action.ULR_BAROMETER_READ_ALARM type 1 when 1501206840000 com.google.android.gms} +
tag=alarm:com.google.android.location.internal.action.ULR_BAROMETER_READ_ALARM + type=1 whenElapsed=+1m59s428ms when=2017-07-27 21:54:00 + window=+1m30s0ms repeatInterval=120000 count=0 flags=0x0 +
operation=PendingIntent{cb99ddd: PendingIntentRecord{f0fbd52
com.google.android.gms startService}}
Note I don't have access to my home computer right now so I can't post exactly what it will be for my app, so I just grabbed the PendingIntent for a different app but it is the same structure.
I cancelled the alarm before it went off using the code found below, reran the adb command from before and the pending intent was no longer in the terminal output so everything worked great.
Here is my code for cancelling alarms:
/**
* Cancels the PendingIntent for the alarm.
* #param context
*/
public void cancelAlarm(Context context) {
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, MyBroadcastReceiver.class);
intent.putExtra("alarm", this);
String id = this.getId().replaceAll("[^0-9]+", "");
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, Integer.parseInt(id), intent, 0);
alarmIntent.cancel();
am.cancel(alarmIntent);
}
Now, if the PendingIntent was reached (BroadcastReceiver runs its onReceive() code and opens a custom activity), I get the following entry in the terminal output when I rerun that adb command:
u0a149:com.my.app +172ms running, 0 wakeups:
+172ms 0 wakes 3 alarms, last -5d8h25m0s423ms:
alarm:com.google.firebase.INSTANCE_ID_EVENT
but I can no longer see the PendingIntent, as expected. Whether I run the cancelAlarm() code or not, this entry will always stay here.
The result of this is that whenever I open the app after the PendingIntent has "gone off" and my BroadcastReceiver class runs it's code, the app acts as if the alarm is continually going off so it does this repeatedly, but like I said there's no PendingIntent entry in the adb output. I want to know how to shut this alarm off or "dismiss" it if you will.
Here is my BroadcastReceiver class:
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String alarm = intent.getStringExtra("alarm");
Intent myIntent = new Intent();
Toast.makeText(context, "Alarm is 1: " + alarm, Toast.LENGTH_SHORT).show();
myIntent.setClassName("com.my.package.name", "com.my.package.name.AlarmReceivedActivity");
myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
myIntent.putExtra("alarm", alarm);
context.startActivity(myIntent);
}
}
and here's my AlarmReceivedActivity:
public class AlarmReceivedActivity extends AppCompatActivity {
private Alarm alarmReceived;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_alarm_received);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
TextView tvTime = (TextView) findViewById(R.id.tv_time);
String lTime = "11:05";
tvTime.setText(lTime);
Intent intent = getIntent();
String s = intent.getStringExtra("alarm");
Toast.makeText(getApplicationContext(), "Alarm is: " + s, Toast.LENGTH_SHORT).show();
Gson g = new Gson();
alarmReceived = g.fromJson(s, Alarm.class);
Uri ringtoneUri = Uri.parse(alarmReceived.getRingtone());
Toast.makeText(getApplicationContext(), "Ringtone is: " + alarmReceived.getRingtone(), Toast.LENGTH_SHORT).show();
try {
MediaPlayer mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDataSource(this, ringtoneUri);
final AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
mMediaPlayer.setLooping(false);
mMediaPlayer.prepare();
mMediaPlayer.start();
}
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Failed to play ringtone", Toast.LENGTH_SHORT).show();
}
}
public void dismissButtonClick(View view) {
Context context = getApplicationContext();
alarmReceived.cancelAlarm(context);
alarmReceived.setIsSet(false);
writeAlarmToSharedPrefs(alarmReceived, context);
alarmReceived.cancelAlarm(context);
System.exit(0);
}
private void writeAlarmToSharedPrefs(Alarm alarmReceived, Context context) {
String alarm = getAlarmObjectAsJson(alarmReceived);
SharedPreferences sPrefs = getApplicationContext().getSharedPreferences("Sleepin", MODE_PRIVATE);
SharedPreferences.Editor pe = sPrefs.edit();
pe.putString(alarmReceived.getId(), alarm);
pe.apply();
}
private String getAlarmObjectAsJson(Alarm a) {
Gson g = new Gson();
return g.toJson(a);
}
public void snoozeButtonClick(View view) {
}
}
So I have a couple questions:
1) Since the PendingIntent has been reached, what is this entry in the adb command output referred to as? A "ReachedPendingIntent" (obviously not called this but I hope you get where I'm going with this).
2) How do I stop my app from running the BroadcastReceiver code? My workaround right now is to clear the app's data and cache. After I do this, the second entry from the adb command doesn't appear and the BroadcastReceiver stops running it's code.
Related
I have following code to fire an alarm at exact time. When my app goes to sleep/background, Alarm does not FIRE, however as soon as I unlock my phone, then it fires right away.
Intent i = new Intent(this, typeof(MyReceiver));
i.PutExtra("Speaker", txtSpeaker.Text);
PendingIntent pi = PendingIntent.GetBroadcast(this, 0, i, 0);
string _date = DateTime.Today.ToString("MM-dd-yyyy") ;
string _time = tpick.Hour + ":" + tpick.Minute;
DateTime scheduleAt = Convert.ToDateTime(_date).Add(TimeSpan.Parse(_time));
DateTimeOffset dateOffsetValue = DateTimeOffset.Parse(scheduleAt.ToString());
var millisec = dateOffsetValue.ToUnixTimeMilliseconds();
AlarmManager alarmManager = (AlarmManager)GetSystemService(AlarmService);
alarmManager.SetExact(AlarmType.RtcWakeup, millisec, pi);
and here is my Receiver Class...
[BroadcastReceiver]
public class MyReceiver : BroadcastReceiver
{
public async override void OnReceive(Context context, Intent intent)
{
Console.WriteLine("FIRED");
String result = intent.Extras.GetString("Speaker");
Toast.MakeText(context, "Alarm Ringing!", ToastLength.Short).Show();
}
}
If the App is running on API 23 or newer, you might want to look into using the SetExactAndAllowWhileIdle method. According to the documentation it appears to me that this method will ignore whether the Device is in some low-power state or doze is enabled.
In the application which i'm developing, i'm having an alarm manager which will launch the application in particular time. During this process, i'm passing a string as the part of intents as shown below.
Intent LaunchIntent = context.getPackageManager().getLaunchIntentForPackage("Application Package Name");
String strName = "Preferences";
LaunchIntent.putExtra("STRING_NAME", strName);
context.startActivity(LaunchIntent);
It is opening the application. But in the when i do intent.getStringExtra("STRING_NAME"), in the onCreate() method of the Homescreen, the passed string value is not coming.
In this class i'm initializing the alarm manager for every 40 seconds as shown below in the onCreate method:
private static void SetScheduleSync(Context context) {
Intent downloader = new Intent(context, ScheduleSyncManager.class);
PendingIntent recurringDownload = PendingIntent.getBroadcast(context, 1000, downloader, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
int interval = 10000*4;
manager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, recurringDownload);
}
Inside the ScheduleSyncManager.class, i have written code to open up the application by passing the extras as the pert of intent. When the application opens up, i checking whether is there any extra data in the particular intent.
Here is the ScheduleManagerDeclaration:
public class ScheduleSyncManager extends WakefulBroadcastReceiver {
public Boolean IsCustomizingPresent = false;
String strName = "Preferences";
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Sync in the background has Started", Toast.LENGTH_SHORT).show();
performScheduleSync(context, intent);
}
public void performScheduleSync(Context context, Intent intent) {
Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage("com.sap.rex.ui");
launchIntent.putExtra("STRING_NAME", strName);
launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(launchIntent);
}
And i'm calling the ScheduleManager from function SetScheduleSync() in Oncreate() method as i posted the code below.
Please help me with this. Is it possible to do like this?
Thanks.
Try the following:
LaunchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
P.S. It's a common practice to make the first letters of the instances lower case., i.e., not LaunchIntent but launchIntent.
I am experiencing some lag/black screen in my application since I start using AlarmManager + BroadcastReceiver. I have 2 BroadcastReceivers, one to when the phone gets restarted and another that AlarmManager call in the given period of time to send data to the server.
This is the code for BootReceiver to start the alarmManager once the cellphone is rebooted (it is working so far):
private final String BOOT_COMPLETED_ACTION = "android.intent.action.BOOT_COMPLETED";
#Override
public void onReceive(Context context, Intent intent) {
// when the boot is completed, restart the alarm manager
if(intent.getAction().equals(BOOT_COMPLETED_ACTION)){
SharedPreferences mPrefs = context.getSharedPreferences("GPS_TRACKING", Context.MODE_PRIVATE);
if (mPrefs.getBoolean("hasGeolocation", false) &&
!mPrefs.getBoolean("isThreadOn", false)){
EngineerTracker tracker = new EngineerTracker(context);
try {
tracker.startEngineerTrackingLocation();
} catch (ApplicationException e) {
e.printStackTrace();
}
}
}
}
The method to start and stop the alarm manager is this:
public void startEngineerTrackingLocation() throws ApplicationException{
PendingIntent pendingIntent = null;
AlarmManager manager = null;
ProjectGeospatialConfig geospatialConfig;
// check if the intent is running, if it is not, start it
if (PendingIntent.getBroadcast(context, 0,
new Intent(context, EngineerGeospatialTrackingReceiver.class),
PendingIntent.FLAG_NO_CREATE) == null){
// fetch the geospatial configuration, it may come null, so verify before using
geospatialConfig = getFirstFoundGeospatialConfiguration();
// if not null and use gps
if (geospatialConfig != null && geospatialConfig.isUseGps()){
// session information
SessionInformationDTO sessionInformation = dao.getObjectForKey(SqlLiteStorageKey.USER_INFORMATION);
Integer currentResourceId = sessionInformation.getSecurityHandler().getCurrentUser().getId();
// Retrieve a PendingIntent that will perform a broadcast and add resource id as extra
Intent alarmIntent = new Intent(context, EngineerGeospatialTrackingReceiver.class);
alarmIntent.putExtra("resourceId", currentResourceId.toString());
// set pending intent
if (pendingIntent == null){
pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
}
// set manager
if (manager == null){
manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
}
// set interval between alarms
int interval = (geospatialConfig.getGpsTrackingInterval() *1000) * 60;
// set alarm repetition
manager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
interval, pendingIntent);
// set variables for gps tracking
SharedPreferences mPrefs = getApplicationContext().getSharedPreferences("GPS_TRACKING", Context.MODE_PRIVATE);
Editor editor = mPrefs.edit();
// these variables will be measured once db is set
editor.putBoolean("hasExecuted", false);
editor.commit();
}
}
}
both are also working so far, the flag is meant to know when the service has been executed once and will not attempt again at the basic activity (template for all activitied)
The broadcast that is invoked in the alarm manager to send the information in the defined interval is this:
public class EngineerGeospatialTrackingReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String resourceId = intent.getStringExtra("id");
sendLocation(context, resourceId);
}
private void sendLocation(final Context context, final String resourceId){
new RemoteRequestTask<Void>(null, false, null) {
#Override
public Void executeTask() throws ApplicationException {
// working code
}
#Override
public void completed(Void refreshed) {
}
#Override
public void onException(final ApplicationException ex) {
}
}.start();
}}
Both receivers were added to the AndroidManifest. Beside the slowness, i also get a black screen when transitioning from an activity to another.
Use Traceview to determine where you are spending your time, and consider enabling StrictMode to point out where you are doing unfortunate things on the main application thread.
You want onReceive() to be very quick, ideally under 1ms, as. However, it looks like you might be doing database I/O in there (e.g., references to dao), which means that work should be handled off the main application thread, perhaps by an IntentService that you start from onReceive().
i'm using below code to launch the alert dialog. This works well sometimes & some times it does not.
` Intent alarmIntent = new Intent("android.intent.action.MAIN");
alarmIntent.setClass(ct, AlertsDlgactivity.class);
alarmIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Pass on the alarm ID as extra data
// Start the popup activity
ct.startActivity(alarmIntent);`
Also, few times multiple instances of dialog appears, any help on how to work on this
Without seeing all of your code, I'm not sure how your trying to accomplish this, so I am providing a simple Function to use the Alarm Manager:
public void scheduleAlarm(int year,int month,int day,int hr,int min,int sec, String message, int _id)
{
long future = new GregorianCalendar(year,month,day,hr,min,sec).getTimeInMillis();
Intent intentAlarm = new Intent(this, AlarmReciever.class);
intentAlarm.putExtra("_MESSAGE",message);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, future,
PendingIntent.getBroadcast(this, _id, intentAlarm, PendingIntent.FLAG_ONE_SHOT));
Toast.makeText(this, "Alarm Scheduled", Toast.LENGTH_LONG).show();
}
And this would be AlarmReciever.class
public class AlarmReciever extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
//Use this to get variables passed from Main Activity
String message = intent.getStringExtra("_MESSAGE");
//Do some stuff here
}
}
Also don't forget to add these to your Manifest:
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
<application
<receiver android:name=".AlarmReciever"/>
</application>
What I want
I want a notification every day at the same time.
I already read some posts and tutorials/examples but it won't work correctly.
Version 1
The Error: Android process / service dies every ~3 minutes after re/starting
11-07 07:33:05.725 4611 6121 I ActivityManager: Process at.htl3r.appmosphere (pid 5238) has died.
11-07 07:33:05.725 4611 6121 W ActivityManager: Scheduling restart of crashed service at.htl3r.appmosphere/.notify.NotifyService in 14648ms
11-07 07:33:20.400 4611 4632 I ActivityManager: Start proc at.htl3r.appmosphere for service at.htl3r.appmosphere/.notify.NotifyService: pid=5463 uid=10096 gids={50096}
---
11-07 07:33:41.580 4611 4623 I ActivityManager: Process at.htl3r.appmosphere (pid 5463) has died.
11-07 07:33:41.580 4611 4623 W ActivityManager: Scheduling restart of crashed service at.htl3r.appmosphere/.notify.NotifyService in 73293ms
11-07 07:33:44.310 4611 5385 F ProcessStats: Starting service ServiceState{43760cf0 at.htl3r.appmosphere.notify.NotifyService pkg=at.htl3r.appmosphere proc=43760cf0} without owner
these are the two ways (with and without owner in last line)
This bug is only on my S3 so extrem, on my N7 (2013) is it a bit better
After every restart I get a notification. (just a thought: And if I delete it, the possibility is higher to make a crash.)
A bit annoying to receive a notification every 3 minutes ^-^
The Code
version 1 - with service
UPDATE 1
updated code like Larry Schiefer told
new full log
UPDATE 2
NotifyManager
see below for newest version
version from this update
NotifyReceiver
public class NotifyReceiver extends BroadcastReceiver {
private static final String TAG = "NotifyReceiver";
public static final int ID_NEWHINTAVAILABLE = 1;
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive");
SharedPreferences spref = PreferenceManager.getDefaultSharedPreferences(context);
NotificationManager mNM = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent i = new Intent(context.getApplicationContext(), MainActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(context, 0, i, 0);
Notification.Builder mNotifyBuilder = new Notification.Builder(context);
mNotifyBuilder.setSmallIcon(R.drawable.ic_stat_name);
mNotifyBuilder.setContentTitle(context.getString(R.string.app_name));
mNotifyBuilder.setContentText(context.getString(R.string.notification_contenttext));
mNotifyBuilder.setContentIntent(pIntent);
mNotifyBuilder.setAutoCancel(true);
// has to have an icon - now the app icon
// auto cancel after click: in main use cancel(int id);
// mNotifyBuilder.addAction(R.drawable.ic_stat_name, getString(R.string.notification_action), pIntent);
// mNotifyBuilder.setTicker(getString(R.string.app_name));
// mNotifyBuilder.setTicker(getString(R.string.app_name)+" "+getString(R.string.notification_contenttext));
// mNotifyBuilder.setWhen(System.currentTimeMillis());
// mNotifyBuilder.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS);
// http://stackoverflow.com/questions/2724871/how-to-bring-up-list-of-available-notification-sounds-on-android
String sound = spref.getString(SettingsFragment.pref_notify_sound, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION).toString());
mNotifyBuilder.setSound(Uri.parse(sound));
if (spref.getBoolean(SettingsFragment.pref_notify_vibrate, true)) {
// mNotifyBuilder.setVibrate(new long[] { 0, 1000 });
mNotifyBuilder.setDefaults(Notification.DEFAULT_VIBRATE);
}
if (spref.getBoolean(SettingsFragment.pref_notify_light, true)) {
mNotifyBuilder.setLights(Color.GREEN, 3000, 3000);
}
Notification mNotify = mNotifyBuilder.build();
mNM.notify(ID_NEWHINTAVAILABLE, mNotify);
NotifyManager.startAlarm(context, true);
// wenn aktiviert: ausgeführt & neu gestartet
// bei Deaktiviertung: abgebrochen - demnach kein Neustart
}
}
Update 3
Autostart worked..
but now, it dies too
nothing changed in this code; only the code above
<receiver android:name="at.htl3r.appmosphere.notify.Autostart" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Autostart.java
public class Autostart extends BroadcastReceiver {
private static final String TAG = "autostart";
#Override
public void onReceive(Context context, Intent intent) {
if (NotifyManager.isNotificationEnabled(context)) {
NotifyManager.startAlarm(context);
Log.i(TAG, "started");
}
}
}
CatLog
s3 - full
n7
12-14 23:15:19.227 1452 1679 I ActivityManager: Start proc at.htl3r.appmosphere for broadcast at.htl3r.appmosphere/.notify.Autostart: pid=5837 uid=10391 gids={50391, 3003}
12-14 23:15:42.300 1452 4109 I ActivityManager: Killing 5837:at.htl3r.appmosphere/u0a391 (adj 15): empty #17
12-15 06:43:47.501 18799 18819 D JsonParser: at.htl3r.appmosphere: publishState=6
12-15 06:43:47.501 18799 18819 D JsonParser: Skipping app 0 with state != 1: package name=at.htl3r.appmosphere: state=6
Update 4
NotifyManager
public class NotifyManager {
private static final String TAG = "NotifyManager";
/**
* {#link #startAlarm(Context, boolean)}<br>
* default: restart: true
*
* #param context Context of activity
* #return alarm started: true<br>
* is running: false
*/
public static boolean startAlarm(Context context) {
return startAlarm(context, false);
}
/**
* #param context Context of activity
* #param restart start the alarm even when already running
* #return true if started | false if running and not started
*/
public static boolean startAlarm(Context context, boolean restart) {// todo restart alarm on settings change
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
SharedPreferences spref = PreferenceManager.getDefaultSharedPreferences(context);
String time = spref.getString(SettingsFragment.pref_notify_time, TimePreference.notify_default);
int hour = Integer.parseInt(time.split("\\:")[0]);
int minute = Integer.parseInt(time.split("\\:")[1]);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.HOUR_OF_DAY, hour);
// alternative: HOUR and AM_PM
if (calendar.getTimeInMillis() < Calendar.getInstance().getTimeInMillis()) {
calendar.add(Calendar.DAY_OF_MONTH, 1);
}
// String time = new SimpleDateFormat("hh:mm", Locale.getDefault()).format(calendar.getTime());
if (!isAlarmRunning(context) || restart) {
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), getPendingIntent(context));
Log.d(TAG, "Start Alarm at " + time);
// Toast.makeText(context, "Start Alarm at " + time, Toast.LENGTH_LONG).show();
return true;
}
Log.d(TAG, "Service already running");
return false;
}
/**
* #param context Context of activity
* #return true if running and canceled
*/
public static boolean cancelAlarm(Context context) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if (isAlarmRunning(context)) {
alarmManager.cancel(getPendingIntent(context));
Log.d(TAG, "Cancel Alarm");
NotifyManager.isAlarmRunning(context);
// Toast.makeText(context, "Cancel Alarm from " + time, Toast.LENGTH_LONG).show();
return true;
}
Log.d(TAG, "Service already canceled");
return false;
}
/**
* #param context Context of activity
* #return if alarm is running
*/
public static boolean isAlarmRunning(Context context) {
Intent intent_service = new Intent(context, NotifyReceiver.class);
Log.d(TAG, "isAlarmRunning:" + (PendingIntent.getBroadcast(context, 0, intent_service, PendingIntent.FLAG_NO_CREATE) != null));
return (PendingIntent.getBroadcast(context, 0, intent_service, PendingIntent.FLAG_NO_CREATE) != null);
}
/**
* #param context Context of activity
* #return PendingIntent
*/
public static PendingIntent getPendingIntent(Context context) {
Intent intent = new Intent(context, NotifyReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_NO_CREATE);
// If it exists return it
if (pi != null)
return pi;
// It doesn't exist, make it (last parameter to 0 for reusable):
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT);
}
/**
* #return yyMMdd
*/
public static String getCurrentTimeStamp() {
SimpleDateFormat sdfDate = new SimpleDateFormat("yyMMdd", Locale.getDefault());
Date now = new Date();
String strDate = sdfDate.format(now);
return strDate;
}
/**
* #param context Context of the activity
* #return if notification is enabled or not
*/
public static boolean isNotificationEnabled(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SettingsFragment.pref_notify, true);
}
}
Point A: The service code is missing a key component
In the code above, the service has an onCreate and onDestroy, which will be triggered when the service is created and destroyed. However, if a service is triggered and it is already running, then it will not go through onCreate. It will, however, go through onstartCommand (onStart pre android 2.0). The actual structure of your code should be:
onCreate() {
// Stuff you only do when this class is instantiated the first time
// and don't need to do if it is called (started in android terminology)
// thereafter
}
// The next two are >=2.0 and then <2.0
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startHandleIntent(intent);
return START_STICKY; // If you want the service to hang around
}
#Override
public void onStart(Intent intent, int startId) {
startHandleIntent(intent);
}
void startHandleIntent(Intent intent) {
// Do things that shiould happen every time here
// eg. in your case, the notification
}
Point B: This isn't really what a service was designed for
You cannot rely on a service hanging around for that long. Inactive services will often be removed to make space for other things. Given that the the service does very little, it would probably be better to use a BroadcastReceiver, which was designed specifically for things that need triggering occasionally but don't really need to be there otherwise. So:
Use a BroadcastRecevier to catch the triggers and issue a notification. Something like this:
class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Issue the notidfication
<...>
// Reissue a request for a future alarm call here if needed
<...>
}
}
Remember to set it up to receive broadcasts in the manifest:
<application>
... other stuff ...
<receiver android:name=".MyBroadcastReceiver" android:enabled="true">
<intent-filter>
<action android:name="com.mystuff.coolapp.ACTION_TIME_FOR_NOTIFICATION"/>
</intent-filter>
</receiver>
</application>
To trigger that, you need an intent that will trigger a broadcast:
Intent intent = new Intent("com.mystuff.coolapp.ACTION_TIME_FOR_NOTIFICATION");
context.sendBroadcast(intent);
If you are setting it up to call later via a PendingIntent (change the final flag to zero if you want a reusable PendingIntent for a recurring event):
Intent intent = new Intent("com.mystuff.coolapp.ACTION_TIME_FOR_NOTIFICATION");
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT)
If later on you wish to change, or cancel somehting, or if you simply need to know if the Pending Intent exists from the system's point of view:
Intent intent = new Intent("com.mystuff.coolapp.ACTION_TIME_FOR_NOTIFICATION");
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_NO_CREATE);
if (pi != null) {
// It exists. If you want then to cancel the alarm that triggers it:
alarmManager.cancel(pi);
}
else {
// It doesn't exist. If you need to create a reusable PendingIntent:
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
}
Personally, I would use this approach instead of initializePendingIntent, ie:
public static PendingIntent getPendingIntent() {
Intent intent = new Intent("com.mystuff.coolapp.ACTION_TIME_FOR_NOTIFICATION");
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_NO_CREATE);
// If it exists return it
if (pi != null) return pi;
// It doesn't exist, make it (last parameter to 0 for reusable):
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT);
}
Use SharedPreferences (as you already do) to keep track of what is going on (time of alarm)
My preference would be to only create a one shot alarm with a one shot intent for when the next alarm should sound. If it changes, remove this alarm and create a new one. When it triggers, crate a new one. This way you minimise the number of things that have to stay alive for lengths of time.
Check your logcat for a stack trace. It will be before the activity manager service entries you have provided. This line looks suspect to me, specifically the setAction as it is not providing a proper resource value for the icon:
mNotifyBuilder.setContentTitle(getString(R.string.app_name)).setContentText(getString(R.string.notification_contenttext)).setContentIntent(pIntent).addAction(0, getString(R.string.notification_action), pIntent).setAutoCancel(true)