14

I have critical reminders that are set via the Alarm Manager (It should function the same way as an alarm clock application).

Previously I had the following in my Android Manifest:

    <receiver android:name="com.example.app.AlarmReceiver" >
        <intent-filter>
            <action android:name="${packageName}.alarm.action.trigger"/>
        </intent-filter>
    </receiver>

The broadcast receiver:

public class AlarmReceiver extends BroadcastReceiver {

  @Override public void onReceive(
      final Context context,
      final Intent intent) {
// WAKE LOCK
// BUILD NOTIFICATION etc...
  }

}

How the alarm is set:

final PendingIntent operation = PendingIntent.getBroadcast(
          mContext,
          requestCode,
          intent,
          PendingIntent.FLAG_CANCEL_CURRENT);

      if (PlatformUtils.hasMarshmallow()) {
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, operation);

      } else {
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerAtMillis, operation);
      }
}

With Android 8.0 I can no longer use an implicit broadcast as defined in the Manifest. That's fine, the alternative given is to register it manually like so:

final BroadcastReceiver receiver = new AlarmReceiver();
final IntentFilter intentFilter = new IntentFilter(ALARM_RECEIVER_INTENT_TRIGGER);
context.registerReceiver(receiver, intentFilter);

This does not seem logical to me.

  1. The alarm receiver will be tied to the lifetime of the context. This causes an issue when say the application is killed due to memory pressure or when the device is restarted. I need my alarms to fire every time as they are critical for the health of the user.

  2. Even if I listen to "android.intent.action.BOOT_COMPLETED" and register my alarm receiver the app is killed shortly after and no alarm is fired. I also don't see my alarm via

    adb shell dumpsys alarm

How do I create a custom broadcast receiver that receives an implicit broadcast to fire an alarm while targeting Android O (8.0)? Can someone enlighten me with a code example or link to documentation. How does Timely or any other alarm clock app function while targeting O?

ViciDroid
  • 3,555
  • 4
  • 14
  • 16

2 Answers2

29

Revise your code slightly to make the broadcast explicit rather than implicit and you'll be fine (assuming this is an Activity reference or some other Context):

Intent intent = new Intent(ALARM_RECEIVER_INTENT_TRIGGER);
intent.setClass(this, AlarmReceiver.class);

The restriction in Oreo is on implicit broadcast Intent registration, which is to say it you are sending it broadcasts will only action, category, or data specified. You make it an explicit broadcast by specifying the class which is to receive the broadcast.

Larry Schiefer
  • 15,687
  • 2
  • 27
  • 33
  • 1
    How do I register a broadcast receiver with this intent argument? This looks like it is for sending a broadcast. – ViciDroid Sep 19 '17 at 16:43
  • 2
    Your registration in the manifest is fine (I'm assuming that your constant `ALARM_RECEIVER_INTENT_TRIGGER` is the string `com.example.app.alarm.action.trigger` from your manifest), though you probably should add an `android:export="false"` in the entry to prevent other apps from trying to send your receiver a broadcast which could mess you up. – Larry Schiefer Sep 19 '17 at 16:47
  • This worked, forgot to set the class when creating the intent for the pending intent. Thank you! – ViciDroid Sep 21 '17 at 01:15
  • You are very welcome, glad I could help. Please be sure to mark the answer as correct. – Larry Schiefer Sep 21 '17 at 10:38
  • Please can someone share how to send/receive explicit intents to other app ? Best would be running example – hannes ach Oct 12 '17 at 06:45
  • @hannesach it's not clear what you are asking. An explicit `Intent` specifies exactly which application package and component (class instance) will receive it. One app cannot receive explicit `Intent` object which are being sent to another app. – Larry Schiefer Oct 31 '17 at 16:37
  • @LarrySchiefer let me try to clarify: with api25 it was possible to make a specific app-to-app communication with *explicit* Intent. With api26 Google writes: no more *implicit* `Intent`, I agree. But no word about *explicit* `Intent` by Google, for me it sounds there is no new restriction. But I'm not able to make it work with api26. When you wrote: it's not possible, you can only mean api 26 (because api25 works) but Google writes only about new *implicit* broadcast restriction – hannes ach Nov 01 '17 at 08:48
  • @hannesach you should still be able to send explicit broadcasts to other apps, as long as you know the package/class target for the `Intent`. Explicit `Intent`s have been in Android since 1.0, there is nothing new there. The only thing which is new is the restriction on implicit intents. – Larry Schiefer Nov 01 '17 at 10:55
  • 1
    @LarrySchiefer my implementation doesn't work in Android that'w why I asked "Please can someone share how to send/receive explicit intents to other app ? Best would be running example" – hannes ach Nov 05 '17 at 07:12
  • Hannes Ach, would need to see your code in order to help. – Larry Schiefer Nov 05 '17 at 14:53
  • waow. I'm working on this for 2+ days now. I was googling with the wrong keywords! Many many thanks! If you have some time, may I ask you to throw an eye on https://stackoverflow.com/questions/50894567/widget-case-that-doesnt-work-with-oreo-8-1-message-received-w-broadcastqueue – narb Jun 20 '18 at 17:30
  • @hannesach have you got the solution ? – mob_web_dev Jul 25 '18 at 11:19
  • currently not, but I need the solution till end of October. please ping me later again – hannes ach Jul 26 '18 at 08:02
  • Thanks this helped me a lot. I was stuck for a while because my intent was being made in a superclass but receivers are registered to subclasses. To get the right class name use: intent.setClass(context, this.getClass()) – Georgie Oct 17 '18 at 04:43
  • Thank you, instead of setClass, setPackage also works. – Knowledge Drilling Mar 01 '19 at 04:57
  • 2022 I don't think this is working anymore. Nothing happens in my case – user1034912 Feb 12 '22 at 13:22
1

If you guys are used to check if the alarm has already been registered don't forget to do the same on this verification:

public boolean isAlarmBroadcastRegistered(Context context, String action, Class clazz) {
    Intent intent = new Intent(action);
    intent.setClass(context, clazz);
    return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_NO_CREATE) != null;
}
Cícero Moura
  • 2,027
  • 1
  • 24
  • 36