Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AlarmManager and BroadcastReceiver in Android Oreo+

I am making an application that notifies the user at certain times of the day. Like an alarm clock. The code works normally in versions prior to Android Oreo.

From what I read, Android Oreo and later versions kill actions in the background and that's why I'm having the error below.

2020-07-13 20:31:06.766 1609-1737/? W/BroadcastQueue: Background execution not allowed: receiving Intent { act=android.intent.action.PACKAGE_REPLACED dat=package:studio.com.archeagemanager flg=0x4000010 (has extras) } to air.br.com.alelo.mobile.android/co.acoustic.mobile.push.sdk.wi.AlarmReceiver

It is as if the BroadcastService is simply not triggered when it should be. But when I open the app, it starts up instantly.

AndroidManifest.xml

<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="owner.custom.permission" />
<permission
    android:name="owner.custom.permission"
    android:protectionLevel="signatureOrSystem">
</permission>

<meta-data
    android:name="com.google.android.gms.version"
    android:value="@integer/google_play_services_version" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/app_icon_new"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity
        android:name=".SplashScreenActivity"
        android:theme="@style/AppCompat.TelaCheia">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:screenOrientation="portrait"
        android:theme="@style/AppTheme.NoActionBar">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity>

    <receiver
        android:name=".AlarmReceiver"
        android:enabled="true"
        android:exported="false">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>

</application>

TabFragEventA.java (Here I put only the function that initiates the alarm)

public void startAlarm(int eventID) {
    String[] NOTIFICATION_TITLES = {"Ocleera Rift", "Ocleera Rift", "Mistmerrow Conflict", "Mistmerrow Conflict",
            "Mistmerrow Conflict", "Nation Construction Quests", "Diamond Shores", "Diamond Shores", "Battle of the Golden Plains",
            "Battle of the Golden Plains", "Karkasse Ridgelands", "Kraken", "The Mirage Isle Fish Fest", "Red Dragon",
            "Abyssal Attack", "Lusca Awakening", "Delphinad Ghostship", "Cattler Wrangler", "Legendary Chef", "+1"};

    String notificationTitle = getString(R.string.contentTitle);
    String notificationText = NOTIFICATION_TITLES[eventID] + getString(R.string.contentNotificationText);

    int alarmHour = localHour.get(eventID);
    int alarmMinute = localMinute.get(eventID);
    // Decrease 5 minutes
    if(alarmMinute == 0) {
        alarmHour = alarmHour - 1;
        alarmMinute = 55;
    } else {
        alarmMinute = alarmMinute - 5;
    }
    // Setting the alarm moment
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    calendar.set(Calendar.HOUR_OF_DAY, alarmHour);
    calendar.set(Calendar.MINUTE, alarmMinute);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    // Analyze if the alarm moment has passed
    Calendar actualTime = Calendar.getInstance();
    if(actualTime.getTimeInMillis() >= calendar.getTimeInMillis()) {
        calendar.add(Calendar.DAY_OF_MONTH, 1);
    }

    Intent intent = new Intent(getActivity().getApplicationContext(), AlarmReceiver.class);
    intent.putExtra("contentTitle", notificationTitle);
    intent.putExtra("contentText", notificationText);
    /*if(eventID == 11 || eventID == 13) {
        intent.putExtra("specificDayWeek", true);
    } else {
        intent.putExtra("specificDayWeek", false);
    }*/
    if(eventID == 12) {
        intent.putExtra("castleSupply", true);
        intent.putIntegerArrayListExtra("castleSupplyDayWeek", (ArrayList<Integer>) CastleSupply);
    }
    else if(eventID == 13) {
        intent.putExtra("castleClaim", true);
        intent.putIntegerArrayListExtra("castleClaimDayWeek", (ArrayList<Integer>) CastleClaim);
    }
    else if(eventID == 14) {
        intent.putExtra("abyssalAttack", true);
        intent.putIntegerArrayListExtra("abyssalDaysWeek", (ArrayList<Integer>) AbyssalDayWeek);
    }
    else if(eventID == 15) {
        intent.putExtra("luscaAwakening", true);
        intent.putIntegerArrayListExtra("luscaAwakeningDayWeek", (ArrayList<Integer>) LuscaAwakening);
    } else {
        intent.putExtra("abyssalAttack", false);
    }

    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
    // PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity().getApplicationContext(), eventID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity().getApplicationContext(), eventID, intent, 0);
    AlarmManager alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
}

AlarmReceiver.java

public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        String contentTitle = intent.getStringExtra("contentTitle");
        String contentText = intent.getStringExtra("contentText");

        String CHANNEL_ID = "my_channel_01";
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence name = "Channel Name";
            int importance = NotificationManager.IMPORTANCE_HIGH;
            NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, importance);
            notificationManager.createNotificationChannel(mChannel);
        }

        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, CHANNEL_ID)
                .setSmallIcon(R.drawable.icon_notification)
                .setContentTitle(contentTitle)
                .setContentText(contentText)
                .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.icon_notification))
                .setContentIntent(pendingIntent)
                .setAutoCancel(true)
                .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
                .setVibrate(new long[]{800, 500, 600, 300});

        notificationManager.notify(0, notificationBuilder.build());

        Log.d("ALARMRECEIVER", "INSIDE");

    }
}

I would like to know what to do to make the Broadcast Receiver work in the background. Or an alternative to set this alarm clock on Android Oreo + so that it notifies the user even with the application closed or in the background.

like image 713
Kelton Holanda Fontenele Avatar asked Jan 29 '26 10:01

Kelton Holanda Fontenele


1 Answers

Android has a doze mode in which it goes to sleep after some inactivity, Even if you manage to do this on some phones chinese ROMs will trouble you for sure ( in which removing from recent apps works as force stopping application)

For your problem there are solutions Like Work manager , Foregroundservices ,jobscheduler it should work but again can't say for all the ROMs. I think right now there isn't a proper solution to this background processing.

But One thing you can do is sending a FCM notification from server with high priority.

You can see that Facebook and whatsapp can work in background because they are whitelisted by the companies. You can whitelist your application by enabling auto start from settings.But you need to do it manually which isnt a case when we talk about fb and whatsapp

Check this website for more details : https://dontkillmyapp.com/

With this issue Most affected are alarm clocks, health trackers, automation apps, calendars or simply anything which needs to do some job for you at a particular moment when you don’t use your phone.

With Android 6 (Marshmallow), Google has introduced Doze mode to the base Android, in an attempt to unify battery saving across the various Android phones.

Unfortunately, some manufacturers (e.g. Xiaomi, Huawei, OnePlus or even Samsung..) did not seem to catch that ball and they all have their own battery savers, usually very poorly written, saving battery only superficially with side effects.

like image 90
kelvin Avatar answered Feb 01 '26 00:02

kelvin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!