5

Good day, I've built a timer into my Android app that sends a message after a certain time. To do this, I added an AlarmManager with a pending intent. Everything works as it should when I have the app open. It also works in the lock screen. But when I close the app, the pending intent is no longer activated and no message appears at the given time. This is my Alarm Manager:

Intent notifyIntent = new Intent(getContext(), MyReceiver.class);
 alarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
        pendingIntent = PendingIntent.getBroadcast
                (getContext(), NOTIFICATION_ID, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);

//when the alarm gets activated:

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                            alarmManager.setExact(AlarmManager.RTC_WAKEUP,System.currentTimeMillis()+delta_time2, pendingIntent);

                        }
 else {
                            alarmManager.set(AlarmManager.RTC_WAKEUP,System.currentTimeMillis()+delta_time2, pendingIntent);

                        }

In the IntentService-Class (where the notification is declared and called):


Intent notifyIntent = new Intent(this, BigTextMainActivity.class);

      
        notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

        PendingIntent notifyPendingIntent =
                PendingIntent.getActivity(
                        this,
                        0,
                        notifyIntent,
                        PendingIntent.FLAG_UPDATE_CURRENT
                );



       
        Intent snoozeIntent = new Intent(this, BigTextIntentService.class);
        snoozeIntent.setAction(BigTextIntentService.ACTION_SNOOZE);

        PendingIntent snoozePendingIntent = PendingIntent.getService(this, 0, snoozeIntent, 0);
        NotificationCompat.Action snoozeAction =
                new NotificationCompat.Action.Builder(
                        R.drawable.ic_alarm_white_48dp,
                        "Snooze",
                        snoozePendingIntent)
                        .build();

        Intent dismissIntent = new Intent(this, BigTextIntentService.class);
        dismissIntent.setAction(BigTextIntentService.ACTION_DISMISS);

        PendingIntent dismissPendingIntent = PendingIntent.getService(this, 0, dismissIntent, 0);
        NotificationCompat.Action dismissAction =
                new NotificationCompat.Action.Builder(
                        R.drawable.ic_cancel_white_48dp,
                        "Dismiss",
                        dismissPendingIntent)
                        .build();

        NotificationCompat.Builder notificationCompatBuilder =
                new NotificationCompat.Builder(
                        getApplicationContext(), notificationChannelId);

        GlobalNotificationBuilder.setNotificationCompatBuilderInstance(notificationCompatBuilder);

        Notification notification = notificationCompatBuilder
                .setStyle(bigTextStyle)
                .setContentTitle(bigTextStyleReminderAppData.getContentTitle())
                .setContentText(bigTextStyleReminderAppData.getContentText())
                .setSmallIcon(R.drawable.ic_launcher)
                .setLargeIcon(BitmapFactory.decodeResource(
                        getResources(),
                        R.drawable.ic_alarm_white_48dp))
                .setContentIntent(notifyPendingIntent)
                .setDefaults(NotificationCompat.DEFAULT_ALL)
    
                .setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary))


                .setCategory(Notification.CATEGORY_REMINDER)

                .setPriority(bigTextStyleReminderAppData.getPriority())

                .setVisibility(bigTextStyleReminderAppData.getChannelLockscreenVisibility())

             
                .addAction(snoozeAction)
                .addAction(dismissAction)

                .build();
//I am not quite shure, if I declared the foregroundservice for the notification at the right place
 
        startForeground(NOTIFICATION_ID, notification);
        mNotificationManagerCompat.notify(NOTIFICATION_ID, notification);
        Vibrator vibrator = (Vibrator) getApplication().getSystemService(Context.VIBRATOR_SERVICE);
        vibrator.vibrate(2 * 1000);

These are my permissions:

<uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.VIBRATE"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

Thank you for your help! (btw if this question is stupid or something it's because I didn't really deal with the topic and just wanted to quickly set off an alarm for my app sorry in advance)

Simba
  • 51
  • 7
  • what device are you testing this on? And what version of Android is it running? – David Wasser Aug 23 '21 at 13:32
  • AlarmManager will trigger `MyReceiver` when it goes off. Have you added logging to see if that is happening? Where is the code for `MyReceiver.onReceive()`? – David Wasser Aug 23 '21 at 13:34
  • I tested it on my device, which is runing Android 10. I checked the logcat and the message "java.lang.RuntimeException: Unable to start receiver com.example.myapplication.ui.dashboard.MyReceiver: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.example.myapplication/.ui.dashboard.MyNewIntentService }: app is in background uid UidRecord{1ea9ce7 u0a353 RCVR idle change:idle|uncached procs:1 seq(0,0,0)}" appeared. On the Emulator-device (which is on Android 11) everything works. – Simba Aug 23 '21 at 21:31
  • The code for MyReceiver.onReceive() is just: "public class MyReceiver extends BroadcastReceiver { public MyReceiver() { } @Override public void onReceive(Context context, Intent intent) { Intent intent1 = new Intent(context, MyNewIntentService.class); context.startService(intent1); } }" – Simba Aug 23 '21 at 21:33
  • What is the manufacturer of "your device"? – David Wasser Aug 24 '21 at 06:50
  • Also, please don't put code in comments. It doesn't format and is hard to read. Just edit your question and add the code to the original question. – David Wasser Aug 24 '21 at 06:53
  • 1
    I have to correct myself: it doesn't work with the Android emulator either. The same message appears stating that my app is in the background. What do I have to change so that my app remains in the foreground? – Simba Aug 24 '21 at 09:55
  • You can start your `Service` as a foreground `Service` in this case. I've added a code snippet to my answer. Read the documentation about the requirements for a foreground `Service`. Please be considerate in your use of foreground services as these chew up resources and may anger your users. – David Wasser Aug 24 '21 at 10:34

1 Answers1

1

Based on your comments it looks like the alarm is triggering as it should, but your BroadcastReceiver is failing when trying to start your Service. The most likely reason is that your device has additional restrictions on background processing. Some devices, mostly low-end and Chinese manufacture, have restrictions on what apps are allowed to run "in the background". If your app isn't on a "white list" of allowed apps, Android won't allow components of the app to be launched in the background.

See https://developer.android.com/about/versions/oreo/background to read about background Service limitations and see https://stackoverflow.com/a/45482394/769265 as an example of an answer where I discuss the problem of certain manufacturers limiting background processing.


Note: Since you cannot start a background Service on Android 8 and above (due to the limitations), you can start your Service as a foreground Service, like this:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    context.startForegroundService(intent)
} else {
    context.startService(intent)
}
David Wasser
  • 93,459
  • 16
  • 209
  • 274
  • Thank you very much, with the ForegroundService it works now! – Simba Aug 24 '21 at 11:44
  • Well, except that my app always closes when you leave it open and the alarm has expired. The notification is still sent, but the app gets closed. If you still have time, could you tell me why? (In the Logcat the message: "android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{7fae484 u0 com.example.myapplication/.ui.dashboard.MyNewIntentService}" is sent) – Simba Aug 24 '21 at 11:53
  • 1
    The error message pretty much tells you the problem. You need to read the documentation about foreground `Service`s. if your `Service` is running as a foreground `Service`, it needs to call `startForeground()`. Obviously you haven't added this to your `Service` code. See https://developer.android.com/guide/components/foreground-services – David Wasser Aug 24 '21 at 20:50
  • Now I have the problem, that the notification just dissappeares from the screen after a short time. I dont't know, what I changed but can you tell me, why that could happen? – Simba Aug 30 '21 at 22:06
  • no, sorry. Look in logcat or try to retrace your changes. – David Wasser Aug 31 '21 at 14:45