1

my mean goal is to run a task periodically at midnight (00:00:00)

but the user can set the period based on the interval (daily, weekly , monthly) let's assume that this job is a backup Scheduling. this task will triggred at midnight but based on the user preference (midnight everyday, every week , or monthly ), and if the phone was in the doze mode or even off , wait untill the next start and start backup.

when i start implementing the code , i started with JobService and JobScheduler , but unfortunately i learned that i can set the repetitive but i can't set the exact time, so the last solution was to work with alarmmanager.

i use this code for triggering the alarm :

 public static void setTheTimeToStartBackup(Context context,String periode) {

    int DATA_FETCHER_RC = 123;
    AlarmManager mAlarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
    
    Calendar calendar = Calendar.getInstance();


    Intent intent = new Intent(context, BackUpAlarmRecevier.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, DATA_FETCHER_RC,intent, PendingIntent.FLAG_UPDATE_CURRENT);


    long interval = 0;
    switch (periode){
        case "never":
            return;
        case "daily":
            alarmStartTime.set(Calendar.HOUR_OF_DAY, 0);
            interval = AlarmManager.INTERVAL_DAY;
            break;
        case "weekly":
            alarmStartTime.set(Calendar.DAY_OF_WEEK, 1);
            interval = AlarmManager.INTERVAL_DAY*7;
            break;

        case "monthly":
            alarmStartTime.set(Calendar.WEEK_OF_MONTH, 1);
            interval = AlarmManager.INTERVAL_DAY*30;
            break;
    }

    alarmStartTime.set(Calendar.HOUR_OF_DAY, 0);
    alarmStartTime.set(Calendar.MINUTE, 0);
    alarmStartTime.set(Calendar.SECOND, 0);

    mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),interval, pendingIntent);

    Log.e("Alarm","Set for midnight");

}

this is my receiver :

public class BackUpAlarmRecevier extends BroadcastReceiver {

SharedPreferences preferences;
@Override
public void onReceive(Context context, Intent intent) {
    Log.e("BackUpAlarmReciver","Triggred");

    PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "TAG:APP");
    wl.acquire();

    sendNotification(context);// simple notification...
    Toast.makeText(context, "Alarm !!", Toast.LENGTH_LONG).show(); 
    startBackupProcess();

    wl.release();

}}

the problem is task never start.

so i went to test it with less time interval (15min as the minimum possible as i read ), so i change my first function setTheTimeToStartBackup to this :

public static void setTheTimeToStartBackup(Context context,String periode) {

    int DATA_FETCHER_RC = 123;
    AlarmManager mAlarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);

    Calendar calendar = Calendar.getInstance();

    calendar.set(Calendar.SECOND, 55);

    Intent intent = new Intent(context, BackUpAlarmRecevier.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, DATA_FETCHER_RC,intent, PendingIntent.FLAG_UPDATE_CURRENT);

    mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),AlarmManager.INTERVAL_FIFTEEN_MINUTES, pendingIntent);

    Log.e("Alarm","Set for midnight");

}

and exactly the same problem , nothing started, no log , no notification , nothing.

and i already set the Receiver in my manifest with all permission like that :

        <receiver android:name=".job.BackUpAlarmRecevier"
        android:enabled="true"
        android:process=":remote"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>

what im doing wrong in both cases ? and if it work , this code will persist for ever or i need to set it again each time ?

thanks :)

EDIT: i call my function setTheTimeToStartBackup in the MainActivity.

MoxGeek
  • 458
  • 6
  • 17
  • 1
    JobScheduler is dead. Long live WorkManager. https://developer.android.com/topic/libraries/architecture/workmanager. Also see https://stackoverflow.com/questions/50357066/periodic-daily-work-requests-using-workmanager. Welcome to android, where every time you sneeze something you just learned got obsoleted. – Fabio Jul 17 '20 at 07:38

2 Answers2

0

You could set it to occur at midnight if you did the appropriate time calculations. Dynamically get the current time and date, calculate when to register the broadcast for the alarm manager. Customize the onReceive method to set another alarm at 12pm again.

Either way you can trigger a broadcast receiver by registering your receiver manually.

Broadcast receiver class:

public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
    System.out.println("Alarm received!! ");
    // Register alarm again here.
    }
}

Code to register a receiver with a custom intent filter.

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

    AlarmManager mAlarmManager = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);


    getApplicationContext().registerReceiver(new AlarmReceiver(), new IntentFilter("AlarmAction"));
    PendingIntent broadcast = PendingIntent.getBroadcast(this, 0, new Intent("AlarmAction"), 0);

   // Add dynamic time calculations. For testing just +100 milli.
   mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 100, broadcast);
    ;

}

You could achieve what you wanted through a background service.

MitchHS
  • 323
  • 1
  • 8
  • i did the same thing for this weekend , and the result remine the same. i think i have some issues with dynamic set, for several period ( week, daily, monthly ) – MoxGeek Jul 20 '20 at 10:50
  • Probably. Try calculating it to happen in the next 10 minutes and go from there. I would think that if you get the current date / time you could calculate it to occur at 12am the next day. – MitchHS Jul 21 '20 at 02:55
0

My suggestion would be to turn the problem around a bit. Create three topics on Firebase (daily, weekly, monthly). Subscribe users to appropriate topics. Have a Firebase function that is triggered by CRON job which sends the data notification down to the device, this data notification should schedule one-time WorkManager job for the update. This way you can control everything from server-side, if the phone is off, it will still execute as soon as it turns on and you don't need to manually take care of catching the Boot completed with alarm manager etc.

Simon
  • 1,657
  • 11
  • 16
  • thank you for this idea, the problem is this app can also be used in some country who prohibit google services (china, and china ROM). – MoxGeek Jul 20 '20 at 10:49