-1

I have an application that at 7AM need to check if there are some task during the day to display their notification, example of workflow: 7AM: check if there is any task for today -> found one at 5PM -> set a notification at 5PM

I have tried to implement Worker, JobScheduler, AlarmReceiver, Broadcast Receiver, JobService, but nothing will trigger if the app is not at least in background.

Any suggestion on what to implement to perform what i need? Thankyou!

EDIT: adding output for: adb shell dumpsys jobscheduler

    Implicit constraints:

BackgroundJobsController:
  Forced App Standby Feature enabled: true
  Force all apps standby: false
  Small Battery Device: false
  Force all apps standby for small battery device: false
  Plugged In: true
  Active uids: [u0a112 u0a113 u0a118 u0a119 u0a123 u0a124 u0a131 u0a140 u0a176 u0a190 u0a191 u0a192 u0a196 u0a201 u0a205 u0a212 u0a219 u0a228 u0a244 u0a253 u0a256 u0a287 u0a294 u0a433]
  Foreground uids: [u0a112 u0a119 u0a123 u0a131 u0a176 u0a190 u0a191 u0a196 u0a201 u0a205 u0a212 u0a244 u0a253 u0a256 u0a287 u0a294 u0a433]
  Except-idle + user whitelist appids: [1001, 2000, 10113, 10117, 10118, 10121, 10122, 10126, 10133, 10134, 10152, 10156, 10159, 10161, 10191, 10192, 10193, 10201, 10205, 10215, 10219, 10230, 10433, 10447]
  User whitelist appids: [10159, 10219, 10230, 10433, 10447]
  Temp whitelist appids: [10253]
  Exempted packages:
    User 0

      com.francesco.pickem
     

  Foreground UIDs: {1000=true, 1001=true, 1027=true, 1037=true, 1068=true, 10112=true, 10119=true, 10131=true, 10191=true, 10196=true, 10201=true, 10205=true, 10212=true, 10253=true, 10256=true, 10287=true, 10294=true, 99960=true}

  Cached UID->package map:
    10447: {com.francesco.pickem}

    <0>com.francesco.pickem
      ACTIVE: expirationTime=2051448531, windowSizeMs=600000, jobCountLimit=75, sessionCountLimit=75, executionTimeInWindow=0, bgJobCountInWindow=0, executionTimeInMaxPeriod=0, bgJobCountInMaxPeriod=0, sessionCountInWindow=0, inQuotaTime=0, jobCountExpirationTime=0, jobCountInRateLimitingWindow=0, sessionCountExpirationTime=0, sessionCountInRateLimitingWi
ndow=0
    

Historical stats at 2021-03-26-10-27-54 (-1h24m10s391ms) over +30m1s114ms:
  u0a447 / com.francesco.pickem:
    9x pending 61% 3x active-top
    11x canceled
  Max concurrency: 8 total, 2 foreground


Historical stats at 2021-03-26-09-56-28 (-1h55m36s45ms) over +31m25s654ms:

  u0a447 / com.francesco.pickem:
    24x pending 99% 8x active-top
    23x canceled
  Max concurrency: 8 total, 2 foreground



Historical stats at 2021-03-26-08-41-09 (-3h10m55s336ms) over +33m6s679ms:
  u0a446 / com.francesco.pickem:
    3x pending 2% 1x active-top
    3x canceled
  u0a447 / com.francesco.pickem:
    6x pending 14% 2x active-top
    5x canceled
  Max concurrency: 6 total, 2 foreground


Current stats at 2021-03-26-10-57-55 (-54m9s277ms) over +54m9s278ms:
  u0a447 / com.francesco.pickem:
    27x pending 22% 7x active-top
    27x canceled
  Max concurrency: 6 total, 3 foreground

  Job history:

       -11m26s720ms   START: #u0a447/2 com.francesco.pickem/.NotificationsService.BackgroundTasks
       -11m26s715ms   START: #u0a447/3 com.francesco.pickem/.NotificationsService.BackgroundTasks
       -11m21s695ms START-P: #u0a447/4 com.francesco.pickem/.NotificationsService.BackgroundTasks

        -5m42s273ms  STOP-P: #u0a447/3 com.francesco.pickem/.NotificationsService.BackgroundTasks unexpectedly disconnected
        -5m42s260ms  STOP-P: #u0a447/2 com.francesco.pickem/.NotificationsService.BackgroundTasks unexpectedly disconnected
        -5m42s208ms    STOP: #u0a447/4 com.francesco.pickem/.NotificationsService.BackgroundTasks unexpectedly disconnected

        -5m41s321ms   START: #u0a447/2 com.francesco.pickem/.NotificationsService.BackgroundTasks
        -5m41s319ms   START: #u0a447/3 com.francesco.pickem/.NotificationsService.BackgroundTasks
        -5m36s313ms START-P: #u0a447/4 com.francesco.pickem/.NotificationsService.BackgroundTasks

        -5m04s703ms  STOP-P: #u0a447/2 com.francesco.pickem/.NotificationsService.BackgroundTasks canceled
        -5m04s683ms   START: #u0a447/2 com.francesco.pickem/.NotificationsService.BackgroundTasks
        -5m04s683ms  STOP-P: #u0a447/3 com.francesco.pickem/.NotificationsService.BackgroundTasks canceled
        -5m04s671ms   START: #u0a447/3 com.francesco.pickem/.NotificationsService.BackgroundTasks
        -4m59s730ms    STOP: #u0a447/4 com.francesco.pickem/.NotificationsService.BackgroundTasks canceled
        -4m59s709ms START-P: #u0a447/4 com.francesco.pickem/.NotificationsService.BackgroundTasks
        -4m13s802ms  STOP-P: #u0a447/2 com.francesco.pickem/.NotificationsService.BackgroundTasks canceled
        -4m13s777ms   START: #u0a447/2 com.francesco.pickem/.NotificationsService.BackgroundTasks
        -4m13s776ms  STOP-P: #u0a447/3 com.francesco.pickem/.NotificationsService.BackgroundTasks canceled
        -4m13s766ms   START: #u0a447/3 com.francesco.pickem/.NotificationsService.BackgroundTasks
        -4m08s818ms    STOP: #u0a447/4 com.francesco.pickem/.NotificationsService.BackgroundTasks canceled
        -4m08s800ms START-P: #u0a447/4 com.francesco.pickem/.NotificationsService.BackgroundTasks
        -1m43s958ms    STOP: #u0a447/4 com.francesco.pickem/.NotificationsService.BackgroundTasks unexpectedly disconnected
        -1m43s842ms  STOP-P: #u0a447/2 com.francesco.pickem/.NotificationsService.BackgroundTasks unexpectedly disconnected
        -1m43s839ms  STOP-P: #u0a447/3 com.francesco.pickem/.NotificationsService.BackgroundTasks unexpectedly disconnected

        -1m41s389ms   START: #u0a447/2 com.francesco.pickem/.NotificationsService.BackgroundTasks
        -1m41s387ms   START: #u0a447/3 com.francesco.pickem/.NotificationsService.BackgroundTasks
        -1m36s367ms START-P: #u0a447/4 com.francesco.pickem/.NotificationsService.BackgroundTasks

          -32s680ms  STOP-P: #u0a447/3 com.francesco.pickem/.NotificationsService.BackgroundTasks unexpectedly disconnected
          -32s668ms  STOP-P: #u0a447/2 com.francesco.pickem/.NotificationsService.BackgroundTasks unexpectedly disconnected
          -32s628ms    STOP: #u0a447/4 com.francesco.pickem/.NotificationsService.BackgroundTasks unexpectedly disconnected

          -29s854ms   START: #u0a447/2 com.francesco.pickem/.NotificationsService.BackgroundTasks
          -29s851ms   START: #u0a447/3 com.francesco.pickem/.NotificationsService.BackgroundTasks
          -24s834ms START-P: #u0a447/4 com.francesco.pickem/.NotificationsService.BackgroundTasks

          -19s005ms  STOP-P: #u0a447/3 com.francesco.pickem/.NotificationsService.BackgroundTasks unexpectedly disconnected
          -18s975ms  STOP-P: #u0a447/2 com.francesco.pickem/.NotificationsService.BackgroundTasks unexpectedly disconnected
          -18s967ms    STOP: #u0a447/4 com.francesco.pickem/.NotificationsService.BackgroundTasks unexpectedly disconnected


Pending queue:

Active jobs:
  Slot #0: inactive since -6s437ms, stopped because: app called jobFinished
  Slot #1: inactive since -5s631ms, stopped because: app called jobFinished
  Slot #2: inactive since -8s14ms, stopped because: last work dequeued
  Slot #3: inactive since -19s778ms, stopped because: cancel() called by app, callingUid=10196 uid=10196 jobId=-439
  Slot #4: inactive since -19s751ms, stopped because: cancel() called by app, callingUid=10196 uid=10196 jobId=-459
  Slot #5: inactive since -5m41s932ms, stopped because: cancel() called by app, callingUid=10196 uid=10196 jobId=-439
  Slot #6: inactive since -1h22m42s81ms, stopped because: app called jobFinished
  Slot #7: inactive since -1h22m42s441ms, stopped because: app called jobFinished
  Slot #8: inactive
  Slot #9: inactive
  Slot #10: inactive
  Slot #11: inactive
  Slot #12: inactive
  Slot #13: inactive
  Slot #14: inactive
  Slot #15: inactive

mReadyToRock=true
mReportedActive=false

Concurrency:
  Screen state: current ON  effective ON
  Last screen ON : 2021-03-26 08:46:09.717 (-2h5m54s784ms)
  Last screen OFF: 2021-03-26 08:42:01.879 (-2h10m2s622ms)

  Current max jobs:

  Config={tot=8 bg min/max=2/6} Running[FG/BG (total)]: 0 / 0 (0) Pending: 0 / 0 (0) Actual max: 0 / 0 (0) Res BG: 0 Starting: 0 / 0 (0) Total: 0 / 0 (0)

  mLastMemoryTrimLevel: 0
  Stats:
    assignJobsToContexts: count=413694, total=704690,5ms, avg=1,703ms, max calls/s=3604 max dur/s=71812,1ms max time=71812,0ms
    refreshSystemState: count=80114, total=157823,1ms, avg=1,970ms, max calls/s=10 max dur/s=26915,4ms max time=26915,4ms

PersistStats: FirstLoad: 124/28/25 LastSave: 119/27/24


C:\Users\Francesco\AndroidStudioProjects\LeagueOfLegendsApp\PickEm2020>

edit 2:

C:\Users\Francesco\AndroidStudioProjects\LeagueOfLegendsApp\PickEm2020>adb shell dumpsys jobscheduler | find  "JOB #u0a447"
  JOB #u0a447/3: d3eed36 com.francesco.pickem/.NotificationsService.BackgroundTasks
  JOB #u0a447/4: aadcfa5 com.francesco.pickem/.NotificationsService.BackgroundTasks

3 Answers3

0

I recommand you too use WorkerManager and set a PeriodicWorkRequest. Of course the app should run at least one time. Then regulary check if the job if well planned when the app is open.

But as the documentation said the PeriodicWorkRequest should be enough:

Robust Scheduling

WorkManager allows you to schedule work to run one- time or repeatedly using flexible scheduling windows. Work can be tagged and named as well, allowing you to schedule unique, replaceable work and monitor or cancel groups of work together. Scheduled work is stored in an internally managed SQLite database and WorkManager takes care of ensuring that this work persists and is rescheduled across device reboots. In addition, WorkManager adheres to power-saving features and best practices like Doze mode, so you don’t have to worry about it.

WorkerManager documentation

Lu No
  • 51
  • 5
  • Thanks for your answer, I did set A workerManager with the periodicWorkRequest following both the documentation and various tutorials about it, however, I'm still not getting lucky because if the application is cleaned from the background, I won't receive any notification at the set hour – Francis Blank Mar 25 '21 at 09:22
  • That is weird, that doesn't match with what the documentation said. Can you save and share the result of this comand after the schedule and after you cleaned the app in background: `adb shell dumpsys jobscheduler` – Lu No Mar 25 '21 at 17:10
  • Thanks for the hint, i tried to clean out the output because it was 5k+ lines, i think the problem may lie in : -19s005ms STOP-P: #u0a447/3 com.francesco.pickem/.NotificationsService.BackgroundTasks unexpectedly disconnected -18s975ms STOP-P: #u0a447/2 com.francesco.pickem/.NotificationsService.BackgroundTasks unexpectedly disconnected -18s967ms STOP: #u0a447/4 com.francesco.pickem/.NotificationsService.BackgroundTasks unexpectedly disconnected – Francis Blank Mar 26 '21 at 11:20
0

Yes it's very verbose maybe you can use https://pastebin.com/.

The stop you see just inform that the job start then stop because it's done.

There is several interesting part in the dump to analyze jobscheduler issue. To know if the job is well planned share at least the part named: "Registered XX jobs". It's look like this:

Registered 65 jobs:
  JOB #1000/800: f44b386 android/com.android.server.pm.BackgroundDexOptService
    1000 tag=*job*/android/com.android.server.pm.BackgroundDexOptService
    Source: uid=1000 user=0 pkg=android
    JobInfo:
      Service: android/com.android.server.pm.BackgroundDexOptService
      PERIODIC: interval=+1d0h0m0s0ms flex=+1d0h0m0s0ms
      Requires: charging=true batteryNotLow=false deviceIdle=true
      Backoff: policy=1 initial=+30s0ms
      Has early constraint
      Has late constraint
    Required constraints: CHARGING TIMING_DELAY DEADLINE IDLE [0xc0000005]
    Satisfied constraints: CHARGING BATTERY_NOT_LOW TIMING_DELAY DEVICE_NOT_DOZING BACKGROUND_NOT_RESTRICTED [0x82400003]
    Unsatisfied constraints: DEADLINE IDLE [0x40000004]
    Uid: active
    Tracking: BATTERY IDLE TIME
    Standby bucket: ACTIVE
    Enqueue time: -20h45m53s452ms
    Run time: earliest=-27m55s737ms, latest=+23h32m4s263ms
    Last successful run: 2021-03-25 16:56:16
    Last run heartbeat: 885
    Ready: false (job=false user=true !pending=true !active=true !backingup=true comp=true)

You can also filter with grep on your app package name or uid. If I follow your last comment it could be:

adb shell dumpsys jobscheduler | grep "JOB #u0a447" -A 22

Lu No
  • 51
  • 5
  • I was not able to find the "Registered XX jobs" in the response, and "grep" was not recognize as a command, General question: Since I tried various apps and codes that should do the same and they do not, may be that the OS is killing background services of the applications? – Francis Blank Mar 26 '21 at 16:18
  • XX correspond to a number. If you don't have grep I suppose you are using a Windows OS so replace it by `find` for cmd or `select-string` for powershell. Don't forget to remove the option part "-A 22". At last your app is in charge of request for a work but the management of the jobs are handle by the system. It keep a reference to the jobs into a database so it persiste to app kill or device reboot. If your job is not execute at time maybe the condition required are not satified. In order to determine that we will need to analyse the registered jobs. You can use pastebin as I mention ealier. – Lu No Mar 26 '21 at 20:52
  • added the results as EDIT2, it's only 2 lines, i think that they are the job actually scheduled? – Francis Blank Mar 27 '21 at 09:19
  • Exactly ! But your dump is trunked so we can't see it. You can do the following to get information about your job. In a powershell terminal use this: ```adb shell dumpsys jobscheduler | Select-String "JOB #u0a447" -Context 0,22``` – Lu No Mar 29 '21 at 14:09
  • 1
    Mate, i really appreciated the work you have done to help me, i have implemented a different solution (a foreground service with a alarmManager) that works fine for me. Thanks for your work and your time, happy coding (: – Francis Blank Mar 29 '21 at 15:03
0

I found a decent solution to this problem, if you accept to have a foreground service you can implement it:

  1. create a notification channel:
private static final String CHANNEL_ID = "1";

    private void createNotificationChannel() {
        // Create the NotificationChannel, but only on API 26+ because
        // the NotificationChannel class is new and not in the support library
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence name = "channel_name";
            String description = "channel_description";
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
            channel.setDescription(description);
            // Register the channel with the system; you can't change the importance
            // or other notification behaviors after this
            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }
    }

  1. Implement the start of the Foreground Service (i have a switch to turn it on/off):
        switch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {

                if (b){
                    createNotificationChannel();
                    
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                        
                        Intent serviceIntent = new Intent(SettingsActivity.this, ForegroundService.class);
                        ContextCompat.startForegroundService(SettingsActivity.this, serviceIntent);
                    }
                    serviceIntent);
                }else {
                    
                    Intent serviceIntent = new Intent(SettingsActivity.this, ForegroundService.class);
                    stopService(serviceIntent);
                }

            }
        });
  1. If you need to check if your foreground service is up:
    private boolean isMyServiceRunning(Class<?> serviceClass) {
        ActivityManager manager = (ActivityManager) 
        getSystemService(Context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo service : 
        manager.getRunningServices(Integer.MAX_VALUE)) {
            if (serviceClass.getName().equals(service.service.getClassName())) {
                return true;
            }
        }
        return false;
    }
  1. The ForegroundService class:
public class ForegroundService extends Service {

    DatabaseHelper databaseHelper;

    public static final String TAG ="ForegroundService";
    @Override
    public void onCreate() {
        super.onCreate();
        databaseHelper = new DatabaseHelper(getBaseContext());
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String input = intent.getStringExtra("inputExtra");
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,
                0, notificationIntent, 0);
        Notification notification = new NotificationCompat.Builder(this, "1")
                .setContentTitle("Foreground Service")
                .setContentText(input)
                .setSmallIcon(R.drawable.icon)
                .setContentIntent(pendingIntent)
                .build();
        startForeground(1, notification);

        setAlarmManager();

        return START_NOT_STICKY;
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    private void setAlarmManager() {
        Intent intent = new Intent(this, AlarmReceiver.class);
        intent.putExtra("TYPE", "TEST");
        PendingIntent sender = PendingIntent.getBroadcast(this, 2, intent, 0);
        AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
        long l = new Date().getTime();
        if (l < new Date().getTime()) {
            l += 86400000; // start at next 24 hour
        }
        
        am.setRepeating(AlarmManager.RTC_WAKEUP, l, 60000, sender); // 86400000
    }



}


  1. Don't forget to add on the Manifest:
        <service
            android:name=".NotificationsService.ForegroundService">

        </service>

The daily repeating service is taken from NyanLH Solution to this other problem