How to Set Alarm in Android Programmatically

How to set Alarm in Android programmatically?

I think you want to set the alarm for 26th June and not 26th July. If so then change cal.set(Calendar.MONTH,6); to cal.set(Calendar.MONTH,5); because the months are zero-based. if you intend the alarm to fire on 26th july then it is expected that the alarm will fire when the date-time is 26th July 2011, 17:30

How to set an alarm on Android Q?

What's wrong in the code I've made? How come it works on P but not always on Q?

You are attempting to start an activity from the background. That is banned on Android 10+ for the most part.

According to the docs, alarms shouldn't be harmed.

From the material that you quoted, with emphasis added: "The app receives a notification PendingIntent from the system". You are not using notifications. And, therefore, this exception does not apply.

On Android Q, is there an official way to let alarms work correctly? To open an Activity that will be shown to the user, exactly as an alarm clock app should?

Use a notification with a full-screen Intent, as is covered in the documentation. If the screen is locked, your activity will be displayed when the notification is raised. If the screen is unlocked, a high-priority ("heads up") notification will be displayed instead. In other words:

  • If the device is not being used, you get what you want

  • If the device is probably being used, the user find out about the event without your taking over the screen, so you do not interfere with whatever the user is doing (e.g., relying on a navigation app while driving)

How to set an alarm to be scheduled at an exact time after all the newest restrictions on Android?

Found a weird workaround (sample here) that seems to work for all versions, including even Android R:

  1. Have the permission SAW permission declared in the manifest:
      <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

On Android R you will have to also have it granted. On before, doesn't seem like it's needed to be granted, just declared. Not sure why this changed on R, but I can say that SAW could be required as a possible solution to start things in the background, as written here for Android 10.

EDIT: Here is a guide on how to request it.


  1. Have a service that will detect when the tasks was removed, and when it does, open a fake Activity that all it does is to close itself:
class OnTaskRemovedDetectorService : Service() {
override fun onBind(intent: Intent?) = null

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int) = START_STICKY

override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
Log.e("AppLog", "onTaskRemoved")
applicationContext.startActivity(Intent(this, FakeActivity::class.java).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
stopSelf()
}

}

FakeActivity.kt

class FakeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("AppLog", "FakeActivity")
finish()
}
}

You can also make this Activity almost invisible to the user using this theme:

    <style name="AppTheme.Translucent" parent="@style/Theme.AppCompat.NoActionBar">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">true</item>
</style>

Sadly, this is a weird workaround. I hope to find a nicer workaround to this.

The restriction talks about starting Activity, so my current idea is that maybe if I start a foreground service for a split of a second it will also help, and for this I won't even need SAW permission.

EDIT: OK I tried with a foreground service (sample here), and it didn't work. No idea why an Activity is working but not a service. I even tried to re-schedule the alarm there and tried to let the service stay for a bit, even after re-schedule. Also tried a normal service but of course it closed right away, as the task was removed, and it didn't work at all (even if I created a thread to run in the background).

Another possible solution that I didn't try is to have a foreground service forever, or at least till the task is removed, but this is a bit weird and I don't see the apps I've mentioned using it.

EDIT: tried to have a foreground service running before removal of the app's task, and for a bit afterwards, and the alarm still worked. Also tried to have this service to be the one in charge of task-removed event, and to close itself right away when it occurs, and it still worked (sample here). The advantage of this workaround is that you don't have to have the SAW permission at all. The disadvantage is that you have a service with a notification while the app is already visible to the user. I wonder if it's possible to hide the notification while the app is already in the foreground via the Activity.


EDIT: Seems it's a bug on Android Studio (reported here, including videos comparing versions).
When you launch the app from the problematic version I tried, it could cause the alarms to be cleared.

If you launch the app from the launcher, it works fine.

This is the current code to set the alarm:

        val timeToTrigger = System.currentTimeMillis() + 10 * 1000
val pendingShowList = PendingIntent.getActivity(this, 1, Intent(this, SomeActivity::class.java), PendingIntent.FLAG_UPDATE_CURRENT)
val pendingIntent = PendingIntent.getBroadcast(this, 1, Intent(this, AlarmReceiver::class.java), PendingIntent.FLAG_UPDATE_CURRENT)
manager.setAlarmClock(AlarmManager.AlarmClockInfo(timeToTrigger, pendingShowList), pendingIntent)

I don't even have to use "pendingShowList". Using null is also ok.

Android - how to set an alarm to a specific date

package your.pack.name;

import java.util.Calendar;

import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

public class AlarmActivity extends Activity {
/** Called when the activity is first created. */

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Calendar cal = Calendar.getInstance();

cal.setTimeInMillis(System.currentTimeMillis());
cal.clear();
cal.set(2012,2,8,18,16);

AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
// cal.add(Calendar.SECOND, 5);
alarmMgr.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent);

}
}

Set Repeat days of week alarm in android

These questions talk about the same thing as you want. Those answers will be helpful:

You just need to specify the day to start it and then repeat it every 7 days. There are few ways specified in answers on given questions:

How can i get the repeat alarm for week days using alarm manager?

Android Notification on specific weekday goes off directly

how to repeat alarm week day on in android

Update:

In your comment you said

How to set the triggerAtMillis part in setRepeating. say for example today is Tuesday, I choose weekly Monday, Wednesday, Friday. - What do I put for Wednesday ?

What I understood that that if today is Tuesday, how to set alarm for lets say Wednesday repeating, right? First of all yes you can use mulltiple id's to set alarms for each day separately.

Then you can add alarmCalendar.set(Calendar.DAY_OF_WEEK, week); line to your existing code. Based on the week day( from 1-7) it repeats for that day. You can pass it into a function as parameter. Like:

    setAlarm(2); //set the alarm for this day of the week

public void setAlarm(int dayOfWeek) {
// Add this day of the week line to your existing code
alarmCalendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);

alarmCalendar.set(Calendar.HOUR, AlarmHrsInInt);
alarmCalendar.set(Calendar.MINUTE, AlarmMinsInInt);
alarmCalendar.set(Calendar.SECOND, 0);
alarmCalendar.set(Calendar.AM_PM, amorpm);

Long alarmTime = alarmCalendar.getTimeInMillis();
//Also change the time to 24 hours.
am.setRepeating(AlarmManager.RTC_WAKEUP, alarmTime, 24 * 60 * 60 * 1000 , pi);
}

I've taken the example from one of above question. Hope its more clear now.

is it right way to set alarm at every 30 seconds ???

In this page there is a finished example of what you need:

https://www.thepolyglotdeveloper.com/2014/10/use-broadcast-receiver-background-services-android/

Apparently you have to change the line:

PendingIntent pintent = PendingIntent.getService(MainActivity.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

To

PendingIntent pintent = PendingIntent.getBroadcast(MainActivity.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

Change your start method to this:

public void start() {
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
AlarmManager manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
int interval = 30 * 1000; // 30 seconds of interval.
manager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
Toast.makeText(this, "Alarm Set", Toast.LENGTH_SHORT).show();
}

Let me know if works.

How run the Alarm without open the Application

You don't need to create your own service for this use case , you can use Alarmservice from Android framework for this, which can start the app(even if app is not running) and time set provided the phone is ON State. Now to set the alarm, call can be in any view (Activity/Fragment) . You can create a button and set action to set Alarm as you like.
On invocation of alarm you use a pending broadcast receiver for any subsquent action. Call for setting Alarm as below, you can use Pending Broadcast intent to do your stuff. And trust me it will work even if your application is not running. Note - AlarmBroadCastReceiver should be a manifest receiver i.e. declared in manifest file.

private void setAlarm(int type) {

// AlarmManager
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

// Alarm type
int alarmType = AlarmManager.RTC;

Calendar time = Calendar.getInstance();

time.setTimeInMillis(System.currentTimeMillis());

switch (type) {

case 1:
// Set Alarm for next 20 seconds
time.add(Calendar.SECOND, 20);
break;

case 2:
// Set Alarm for next 2 min
time.add(Calendar.MINUTE, 2);
break;

case 3:
// Set Alarm for next 30 mins
time.add(Calendar.MINUTE, 30);
break;

}

Intent broadcastIntent = new Intent(this, AlarmBroadCastReceiver.class);

broadcastIntent.putExtras(sourceIntent);

Random generator = new Random();

PendingIntent pendingAlarmIntent = PendingIntent.getBroadcast(this,
generator.nextInt(), broadcastIntent,
PendingIntent.FLAG_ONE_SHOT);
alarmManager.set(alarmType, time.getTimeInMillis(), pendingAlarmIntent);

}

Set alarm for several days

That is because you are logging the time before setting the hour and minutes from the time picker,

your code si working fine but to display the time that was set to the Alarm in your log you have to move the Log.e to after you set the Calendar to the hour and minute from your picker so your code should look like this :

calendar.set(Calendar.DAY_OF_WEEK, Calendar.TUESDAY, Calendar.FRIDAY);
//calendar.add(Calendar.DAY_OF_WEEK,Calendar.FRIDAY);
calendar.set(Calendar.HOUR_OF_DAY,timePicker.getCurrentHour());
calendar.set(Calendar.MINUTE,timePicker.getCurrentMinute());
Log.e("Point_1","Calendar " + calendar.getTime());
Intent intent1 = new Intent(MyService_alarm.this,MyReceiver_Alarm.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(MyService_alarm.this,intent.getIntExtra("Size", 1),intent1,0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), 7 * 24 * 3600 * 1000, pendingIntent);

Also since you are making an Alarm for several days it would be wise to save all the set alarms and to add a receiver to detect when the device has been booted since your alarms are cancelled on reboot and will need to be added again.



Related Topics



Leave a reply



Submit