Search code examples
javaandroidkotlinalarmmanager

Android: Alarm not being triggered through AlarmManager


I am writing a simple Android program that triggers an alarm 15 seconds after the application initialization (plays the default ringtone and pushes a notification) through AlarmManager. Below is my code:

MainActivity.java:

package com.example.basicalarmsetter;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;

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

public class MainActivity extends AppCompatActivity {
    private int uniqueId = 0;

    // Schedules a notification in the future given the delay
    @RequiresApi(api = Build.VERSION_CODES.O)
    private void scheduleNotification(int matchId, long delay) {
        // Construct the PendingIntent which will trigger our alarm to go off
        Intent notificationIntent = new Intent();
        notificationIntent.setAction("com.example.basicalarmsetter.MatchNotification");

        PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), matchId, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT) ;
        long futureInMillis = SystemClock.elapsedRealtime() + delay;

        // Set off our PendingIntent
        AlarmManager alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, futureInMillis, pendingIntent);
        assert alarmManager != null;
        alarmManager.setExact(AlarmManager. ELAPSED_REALTIME_WAKEUP, futureInMillis, pendingIntent);
    }

    // Sets an Alarm at a future specified date
    @RequiresApi(api = Build.VERSION_CODES.O)
    private void setAlarm(long notificationDelay) {
        try {
            System.out.println("Setting alarm at " + notificationDelay + " seconds");

            // Sets off a notification after 5 seconds
            scheduleNotification(uniqueId, notificationDelay);

            uniqueId++;

        } catch (Exception ex) {
            System.out.println("Cannot print alarm!");
            System.out.println("Exception: " + ex.toString());
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        setAlarm(15000);
    }
}

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.basicalarmsetter">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <receiver
            android:name="com.example.basicalarmsetter.MatchNotification"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                ...
                <action android:name="com.example.notificationtest.MatchNotification" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

MatchNotification.kt:

package com.example.basicalarmsetter

import android.app.Notification
import android.app.NotificationManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.media.MediaPlayer
import android.media.RingtoneManager
import android.net.Uri
import androidx.core.app.NotificationCompat

class MatchNotification : BroadcastReceiver() {
    var NOTIFICATION_ID = "notification-id"
    var NOTIFICATION_CHANNEL_ID = "10001";

    private lateinit var player: MediaPlayer;
    private lateinit var context: Context;

    // Construct the notification to push to the user given the teams in the match
    private fun getNotification(
        content: String
    ): Notification? {
        val builder = NotificationCompat.Builder(
            context,
            "default"
        )

        builder.setContentTitle("NBA Alarm")
        builder.setStyle(NotificationCompat.BigTextStyle().bigText(content))
        builder.setContentText(content)
        builder.setSmallIcon(R.drawable.ic_launcher_foreground)
        builder.setAutoCancel(true)
        builder.setChannelId(NOTIFICATION_CHANNEL_ID)

        return builder.build()
    }

    override fun onReceive(context: Context, intent: Intent) {
        System.out.println("Match Notification Activated.");

        this.context = context

        val notificationManager =
            context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        val id = intent.getIntExtra(NOTIFICATION_ID, 0)
        notificationManager.notify(id, getNotification("Trigger Notification!"))

        // Retrieve the URI of the alarm the user has set
        var ringtoneUri:Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
        player = MediaPlayer.create(context, ringtoneUri)

        player.start()
    }

}

This seems strange, consdering that I have specified my MatchNotification class as a receiver in my AndroidManifest.xml file.

Devices Tested On:

  1. Motorola Moto E6 (Android 9)
  2. Emulator for Pixel 2 (API 26)

Note: The solution should have the MainActivity code in Java


Solution

  • This part of your code seems wrong:

    notificationIntent.setAction("com.example.basicalarmsetter.MatchNotification");

    You're using the class name here. You need to use the action of the broadcast receiver, the one you put in your intent filter, a.k.a:

    notificationIntent.setAction("com.example.notificationtest.MatchNotification");

    Another issue: You're creating two alarms, which is unnecessary, at here:

    AlarmManager alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
    alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, futureInMillis, pendingIntent);
    assert alarmManager != null;
    alarmManager.setExact(AlarmManager. ELAPSED_REALTIME_WAKEUP, futureInMillis, pendingIntent);
    

    At this section, following lines are unnecessary:

    alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, futureInMillis, pendingIntent);
    assert alarmManager != null;
    

    The value RTC_WAKEUP is supposed to be used with System.currentTimeMillis(), not SystemClock.elapsedRealtime().

    The final of your MainActivity.java would look like this:

    package com.example.basicalarmsetter;
    
    import androidx.annotation.RequiresApi;
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.app.AlarmManager;
    import android.app.PendingIntent;
    import android.content.Context;
    import android.content.Intent;
    import android.os.Build;
    import android.os.Bundle;
    import android.os.SystemClock;
    
    public class MainActivity extends AppCompatActivity {
        private int uniqueId = 0;
    
        // Schedules a notification in the future given the delay
        @RequiresApi(api = Build.VERSION_CODES.O)
        private void scheduleNotification(int matchId, long delay) {
            // Construct the PendingIntent which will trigger our alarm to go off
            Intent notificationIntent = new Intent();
            notificationIntent.setAction("com.example.notificationtest.MatchNotification");
    
            PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), matchId, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT) ;
            long futureInMillis = SystemClock.elapsedRealtime() + delay;
    
            // Set off our PendingIntent
            AlarmManager alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
            alarmManager.setExact(AlarmManager. ELAPSED_REALTIME_WAKEUP, futureInMillis, pendingIntent);
        }
    
        // Sets an Alarm at a future specified date
        @RequiresApi(api = Build.VERSION_CODES.O)
        private void setAlarm(long notificationDelay) {
            try {
                System.out.println("Setting alarm at " + notificationDelay + " seconds");
    
                // Sets off a notification after 5 seconds
                scheduleNotification(uniqueId, notificationDelay);
    
                uniqueId++;
    
            } catch (Exception ex) {
                System.out.println("Cannot print alarm!");
                System.out.println("Exception: " + ex.toString());
            }
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            setAlarm(15000);
        }
    }