Block Person
Block Person

Reputation: 13

Want to set Alarm even when App is closed and when mobile device is in sleep mood

I want to notify the user at a specific time using Alarm Manager. I have go through many answers and implemented but not working. The following code is working fine when App is running. It is not working when APP IN BACKGROUND & APP IS KILLED. Manifest file code

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

<receiver
        android:name=".newAlarmBroadcast.AlarmReceiver"
        android:enabled="true"
        android:exported="false" />

AlarmReceiver class

public class AlarmReceiver extends BroadcastReceiver {

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

    Notification.createNotificationChannel(context);
    Notification.displayNotification(
            context, context.getString(R.string.alarm), "Its time to do your work",
            Constants.NOTIFICATION_ID
    );

Notification Class

public class Notification {

public static void createNotificationChannel(Context context) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        int importance = NotificationManager.IMPORTANCE_HIGH;

        NotificationChannel channel = new NotificationChannel(
                Constants.NOTIFICATION_CHANNEL_ID,
                context.getString(R.string.alarm_channel),
                importance
        );

        channel.setDescription(context.getString(R.string.channel_message));
        NotificationManager manager = context.getSystemService(NotificationManager.class);
        manager.createNotificationChannel(channel);
    }
}

public static void displayNotification(
        Context context,
        String title,
        String body,
        int id
) {
    Intent intent = new Intent(context, NotesMainActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(context, id, intent, 0);
    NotificationCompat.Builder notificationBuilder =
            new NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_ID)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentIntent(pendingIntent)
                    .setContentTitle(title)
                    .setContentText(body)
                    .setAutoCancel(true)
                    .setPriority(NotificationCompat.PRIORITY_HIGH);

    NotificationManagerCompat manager = NotificationManagerCompat.from(context);
    manager.notify(id, notificationBuilder.build());

}

Here I am setting alarm time

@SuppressLint("SimpleDateFormat")
private void setTheAlarm(long dateTime) {

    alarmManager = (AlarmManager) requireActivity().getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(requireActivity(), AlarmReceiver.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(requireActivity(), Constants.ALARM_ID, intent, 0);

    if (SDK_INT >= Build.VERSION_CODES.M) {
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, dateTime, pendingIntent);
    } else {
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, dateTime, pendingIntent);
    }

Note Constants.NOTIFICATION_ID & Constants.ALARM_ID both are same as required.

Upvotes: 1

Views: 515

Answers (1)

Abdullahi Usman
Abdullahi Usman

Reputation: 58

Use WorkManager as it is easier, light-weight on the OS and backward compatible.

add to your dependencies

implementation "androidx.work:work-runtime-ktx:2.7.1"
implementation "androidx.work:work-runtime:2.7.1"

Create worker class:

class MyWorker(val appContext: Context, workerParams: WorkerParameters): Worker(appContext, workerParams) {
    override fun doWork(): Result {

       
 val notCompat =  NotificationManagerCompat.from(appContext.applicationContext)
 val channel = NotificationChannelCompat.Builder("com.yourcompany.noti_id", NotificationManagerCompat.IMPORTANCE_DEFAULT).setName("Importance").setName("Importance").setVibrationEnabled(true).build()

notCompat.createNotificationChannel(channel)

val noti = NotificationCompat.Builder(appContext.applicationContext, channel.id).setSmallIcon(R.drawable.ic_launcher_foreground).setContentTitle("Internal Test").setContentText("Hope" + Calendar.getInstance().timeInMillis).build()
          

/**
// If your are going to be doing long running operations. To avoid being killed by the //OS
setForegroundAsync(ForegroundInfo(channel.id.hashCode(), noti))
// .... Do long running operations here ....

**/

// Or If you are not doing long running operations....
NotificationManagerCompat.from(appContext.applicationContext).notify("organ".hashCode(), noti)
 
return Result.success()
}

add this to your manifest if you post as long running operations

 <service
    
    android:name="androidx.work.impl.foreground.SystemForegroundService"
            android:foregroundServiceType="location|microphone"
            tools:node="merge" />

Possibly in a fore-ground service

 WorkManager.getInstance(this )
            .enqueueUniquePeriodicWork("com.yourcompany.mywork", ExistingPeriodicWorkPolicy.REPLACE,
                PeriodicWorkRequestBuilder<MyWorker>(30, TimeUnit.MINUTES).setInitialDelay(1, TimeUnit.MINUTES).setConstraints(Constraints.NONE).build())

or If it is a one time work

WorkManager.getInstance(this).enqueueUniqueWork("com.yourcompany.mywork", ExistingWorkPolicy.REPLACE, OneTimeWorkRequestBuilder<MyWorker>().setScheduleRequestedAt(10, TimeUnit.MINUTES).build())
        

See also: https://developer.android.com/topic/libraries/architecture/workmanager https://developer.android.com/topic/libraries/architecture/workmanager/advanced/long-running

Upvotes: 1

Related Questions