I've been stuck on this problem for days. I want to set an alarm and then send a notification when the alarm goes off. works well when the app is open, but it should work when the app is closed too.
here's the code:
Android Manifest:
<receiver android:name=".note.AlertReceiver"
android:enabled="true"
android:exported="true" ></receiver>
<service android:name=".note.AlarmNotificationService"
android:enabled="true"
android:exported="true" ></service>
AlertReceiver:
public class AlertReceiver extends BroadcastReceiver {
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public void onReceive(Context context, Intent intent) {
Log.d("done", "done");
Intent serviceIntent = new Intent(context,AlarmNotificationService.class);
context.startService(serviceIntent);
}
}
AlarmNotificationService:
public class AlarmNotificationService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("done","done1");
return START_NOT_STICKY;
}
MainActivity:
#RequiresApi(api = Build.VERSION_CODES.N)
private void setAlarm(Calendar calendar){
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this , AlertReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this,REQUEST_CODE_alarm,intent,0);
alarmManager.setExact(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),pendingIntent);
}
setAlarm is triggered after TimePicker dialog is closed. I won't add the time picker code because it works with the app open.
when the app is closed. done won't appear in logcat so I'm assuming that there BroadcastReceiver isn't receiving anything
I haven't used AlarmManager with Service therefore it is hard for me to understand why it works only in foreground in your case, but, what I can do is give you a working example that executes in both foreground/background.
From there you should be able to figure out the solution that works for you.
Again, keep in mind that we are not going to use Service class.
AndroidManifest.xml
<receiver
android:name="com.example.name.Receiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
</intent-filter>
</receiver>
Alarm.kt
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, Receiver::class.java)
// Used for filtering inside Broadcast receiver
intent.action = "MyBroadcastReceiverAction"
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0)
// In this particular example we are going to set it to trigger after 30 seconds.
// You can work with time later when you know this works for sure.
val msUntilTriggerHour: Long = 30000
val alarmTimeAtUTC: Long = System.currentTimeMillis() + msUntilTriggerHour
// Depending on the version of Android use different function for setting an
// Alarm.
// setAlarmClock() - used for everything lower than Android M
// setExactAndAllowWhileIdle() - used for everything on Android M and higher
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
alarmManager.setAlarmClock(
AlarmManager.AlarmClockInfo(alarmTimeAtUTC, pendingIntent),
pendingIntent
)
} else {
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
alarmTimeAtUTC,
pendingIntent
)
}
BroadcastReceiver.kt
class Receiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
// We use this to make sure that we execute code, only when this exact
// Alarm triggered our Broadcast receiver
if (intent?.action == "MyBroadcastReceiverAction") {
Log.d("ALARM", "RECEIVED")
}
}
}
The code is in Kotlin, but you should have no trouble using it in your project or just rewrite to Java.
Related
I'm attempting to make it so my app runs some code once per day at 6AM. This works just fine when the app is open and in the foreground, but if the app is closed by swiping it away, the code is never called at the appropriate time.
AlarmReceiver.java (For testing purposes, I have it just trying to display a Toast to verify it runs)
public class AlarmReceiver extends BroadcastReceiver {
public static final String intentAction = "com.mpagliaro98.action.NOTIFICATIONS";
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(intentAction)) {
Toast.makeText(context, "RECEIVER CALLED", Toast.LENGTH_LONG).show();
}
}
}
MainActivity.java (Where the alarm is being set)
public class MainActivity extends AppCompatActivity {
...
private void setRecurringAlarm() {
// Set this to run at 6am
Calendar updateTime = Calendar.getInstance();
updateTime.setTimeZone(TimeZone.getDefault());
updateTime.set(Calendar.HOUR_OF_DAY, 6);
updateTime.set(Calendar.MINUTE, 0);
updateTime.set(Calendar.SECOND, 0);
updateTime.set(Calendar.MILLISECOND, 0);
// Build the pending intent and set the alarm
Intent i = new Intent(AlarmReceiver.intentAction);
PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(),
0, i, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
assert am != null;
am.setRepeating(AlarmManager.RTC, updateTime.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi);
}
}
AndroidManifest.xml (Just the relevant parts)
<uses-permission android:name="android.permission.SET_ALARM" />
<receiver
android:name=".AlarmReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.mpagliaro98.action.NOTIFICATIONS" />
</intent-filter>
</receiver>
I've read through dozens of similar problems to this on this site and elsewhere and I'm seriously at a loss for why this won't work. Any help would be appreciated.
Try changing receiver to
<receiver android:process=":remote" android:name="AlarmReceiver"></receiver>
Should I use android: process =":remote" in my receiver?
DUE TO COMMENTS, CODE IS UPDATED WITH MORE SPECIFIC INFORMATION.
Manifest.xml
<receiver
android:name="com.x.x.x.MyReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="com.x.x.x.NOTIFICATION_INTENT_ACTION.TEST" />
</intent-filter>
</receiver>
MyReceiver.java
internal class MyReceiver: BroadcastReceiver() {
companion object {
const val NOT_ID = ".."
const val NOT = ".."
const val NOTIFICATION_INTENT_ACTION = "com.x.x.x.NOTIFICATION_INTENT_ACTION.TEST"
}
override fun onReceive(context: Context, intent: Intent) {
// does not get called
}
}
CreatingIntent.java
Intent intent = new Intent(this, MyReceiver.class);
mPendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mAlarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
if (mAlarmManager != null) {
mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 60000L, mPendingIntent);
}
Problem: onReceive method inside of NotRec class does not get called. I tried to change Manifest to <receiver android:name="FULL_PATH.receiver.NotRec" /> but it didn't change anything. Any ideas?
Remove
android:exported="false"
from the <receiver> declaration in the manifest.
If you don't "export" your receiver, the AlarmManager cannot trigger it. When you mark a component in the manifest as "not exported", this means that it is "private" and other applications (including system applications like AlarmManager) cannot launch or trigger the component.
I have implemented a service to run with the alarm manager.
I read this link: Should I use android: process =“:remote” in my receiver?
I thought this would be a nice feature for my app, since i want the service to keep running after my app is down.
But when i add this line of configuration to my receiver on the manifest, my service stops being called.
Any clues?
Here is my receiver declaration:
This works:
<receiver
android:name=".service.MyAlarmReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name=".service.MyAlarmReceiver"></action>
</intent-filter>
</receiver>
This wont'n work:
<receiver
android:name=".service.MyAlarmReceiver"
android:enabled="true"
android:process=":remote"
android:exported="false">
<intent-filter>
<action android:name=".service.MyAlarmReceiver"></action>
</intent-filter>
</receiver>
public class MyAlarmReceiver extends BroadcastReceiver {
public static final int REQUEST_CODE = 12345;
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Time to start scan service!");
Intent intent = new Intent(context, BeaconFinderService.class);
context.startService(intent);
}
}
This is how i start my alarm manager:
// Construct an intent that will execute the AlarmReceiver
Intent intent = new Intent(getApplicationContext(), MyAlarmReceiver.class);
final PendingIntent pIntent = PendingIntent.getBroadcast(getApplicationContext(), MyAlarmReceiver.REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), Constants.BLE_SERVICE_LOOP_TIME, pIntent);
When you configure your service to run in remote mode (android:process=":remote"), you will have to debug the process :remote instead as usual .
Personal bug:
So I was having an exception when trying to access FirebaseUser on the service. When in remote mode, you can't access the FirebaseUser, since your process runs on another context.
I had to pass the user through intent extras when initializing the service.
That was all!
here is my manifest
<receiver android:name=".MyCallReceiver" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
and
public class MyCallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING)) {
some code
}
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_IDLE) || intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
some code
}
}
}
it is works but after sometime that press back button and phone be idle it doesn't work any more
(i added "android.os.Process.killProcess(android.os.Process.myPid());" at the end of my code and now it is better and work for maybe 2 3 hour after last execute)
You can use alarm manger to broadcast receiver after certain interval of time like this.
public static void scheduleTestAlarmReceiver(Context context) {
Intent receiverIntent = new Intent(context, TestAlarmReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 123456789, receiverIntent, 0);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()+startDelay, someDelay, sender);
}
I"m sure this is something that is simple, but I'm not figuring it out. I'm trying to make a simple repeating alarm and it never gets triggered. What I have is:
private void setupAlarms()
{
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
Intent intent = new Intent(this, RepeatingAlarm.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(HelloAndroid.this, 0, intent, 0);
GregorianCalendar fifteenSeconds = (GregorianCalendar)Calendar.getInstance();
fifteenSeconds.add(Calendar.MINUTE, 0);
fifteenSeconds.set(Calendar.SECOND, 15);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(), fifteenSeconds.getTimeInMillis(), pendingIntent);
}
This is called from the main onCreate call.
My alarm receiver:
public class RepeatingAlarm extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, R.string.hello, Toast.LENGTH_SHORT).show();
}
}
In my manifest, I have added:
<receiver android:name=".RepeatingAlarm" android:process=":remote" />
Any help, much appreciated
Have you added an intent filter to your BroadcastReceiver?
Code might look something like this in your AndroidManifest.xml file:
<receiver android:name=".RepeatingAlarm" android:exported="true">
<intent-filter>
<action android:name="intent id text" />
</intent-filter>
</receiver>
and when creating your intent do something like this:
Intent intent = new Intent("intent id text")
where the "intent id text" can be any string you use to identify your intent. Also Android alarms get reset if you reboot your device so that may be something you need to look into.
Hope this helps.