/** * Only valid if the job isn't periodic. * * @return The start of the time frame when the job will run after it's been scheduled. * @see JobRequest#getStartMs() */ public long getStartMs() { return mRequest.getStartMs(); }
public static long getStartMs(JobRequest request) { if (request.getFailureCount() > 0) { return request.getBackoffOffset(); } else { return request.getStartMs(); } }
Set<JobRequest> requests = new HashSet<>(manager.getAllJobRequestsForTag(builder.mTag)); for (JobRequest request : requests) { if (!request.isExact() || request.getStartMs() != JobRequest.START_NOW) { manager.cancel(request.getJobId());
@SuppressWarnings("ConstantConditions") @Test public void verifyEarlyExecution() { TestClock clock = new TestClock(); clock.setTime(13, 0); JobRequest request = verifyExecutionAndSuccessfulReschedule(clock, TimeUnit.HOURS.toMillis(14), TimeUnit.HOURS.toMillis(15)); assertThat(request.getStartMs()).isEqualTo(TimeUnit.HOURS.toMillis(25)); assertThat(request.getEndMs()).isEqualTo(TimeUnit.HOURS.toMillis(26)); int id = DailyJob.schedule(DummyJobs.createBuilder(DummyJobs.SuccessDailyJob.class), TimeUnit.HOURS.toMillis(14), TimeUnit.HOURS.toMillis(15)); request = manager().getJobRequest(id); assertThat(request.getStartMs()).isEqualTo(TimeUnit.HOURS.toMillis(1)); assertThat(request.getEndMs()).isEqualTo(TimeUnit.HOURS.toMillis(2)); }
private void verifyScheduleInNextHour(Clock clock) { JobConfig.setClock(clock); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(clock.currentTimeMillis()); int hour = calendar.get(Calendar.HOUR_OF_DAY); int minute = calendar.get(Calendar.MINUTE); long start = TimeUnit.HOURS.toMillis(hour + 1) + TimeUnit.MINUTES.toMillis(minute); long end = start + TimeUnit.HOURS.toMillis(1); DailyJob.schedule(DummyJobs.createBuilder(DummyJobs.SuccessJob.class), start, end); assertThat(manager().getAllJobRequests()).hasSize(1); JobRequest request = manager().getAllJobRequests().iterator().next(); assertThat(request.getStartMs()).isEqualTo(TimeUnit.HOURS.toMillis(1)); assertThat(request.getEndMs()).isEqualTo(TimeUnit.HOURS.toMillis(2)); }
/** * Cancel this request if it has been scheduled. Note that if the job isn't periodic, then the * time passed since the job has been scheduled is subtracted from the time frame. For example * a job should run between 4 and 6 seconds from now. You cancel the scheduled job after 2 * seconds, then the job will run between 2 and 4 seconds after it's been scheduled again. * * @return A builder to modify the parameters. */ public Builder cancelAndEdit() { // create a temporary variable, because .cancel() will reset mScheduledAt long scheduledAt = mScheduledAt; JobManager.instance().cancel(getJobId()); Builder builder = new Builder(this.mBuilder); mStarted = false; if (!isPeriodic()) { long offset = JobConfig.getClock().currentTimeMillis() - scheduledAt; long minValue = 1L; // 1ms builder.setExecutionWindow(Math.max(minValue, getStartMs() - offset), Math.max(minValue, getEndMs() - offset)); } return builder; }
private void verifyScheduleOverMidnight(Clock clock) { JobConfig.setClock(clock); long start = TimeUnit.HOURS.toMillis(24) - 1L; long end = 1L; DailyJob.schedule(DummyJobs.createBuilder(DummyJobs.SuccessJob.class), start, end); assertThat(manager().getAllJobRequests()).hasSize(1); JobRequest request = manager().getAllJobRequests().iterator().next(); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(clock.currentTimeMillis()); int hour = calendar.get(Calendar.HOUR_OF_DAY); long maxStart = TimeUnit.HOURS.toMillis(24 - hour); assertThat(request.getStartMs()).isLessThan(maxStart); assertThat(request.getEndMs()).isLessThan(maxStart + 3); }
@Override public void plantOneOff(JobRequest request) { PendingIntent pendingIntent = getPendingIntent(request, false); AlarmManager alarmManager = getAlarmManager(); if (alarmManager == null) { return; } try { if (request.isExact()) { if (request.getStartMs() == 1 && request.getFailureCount() <= 0) { // this job should start immediately PlatformAlarmService.start(mContext, request.getJobId(), request.getTransientExtras()); } else { plantOneOffExact(request, alarmManager, pendingIntent); } } else { plantOneOffInexact(request, alarmManager, pendingIntent); } } catch (Exception e) { // https://gist.github.com/vRallev/621b0b76a14ddde8691c mCat.e(e); } }
@Override public void plantOneOff(JobRequest request) { if (request.isTransient()) { TransientBundleHolder.putBundle(request.getJobId(), request.getTransientExtras()); } OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(PlatformWorker.class) .setInitialDelay(request.getStartMs(), TimeUnit.MILLISECONDS) // don't use the average here, WorkManager will do the right thing .setConstraints(buildConstraints(request)) .addTag(createTag(request.getJobId())) .build(); // don't set the back-off criteria, android-job is handling this WorkManager workManager = getWorkManager(); if (workManager == null) { throw new JobProxyIllegalStateException("WorkManager is null"); } workManager.enqueue(workRequest); }
@Test public void testPeriodic() { long interval = JobRequest.MIN_INTERVAL * 5; JobRequest request = getBuilder() .setPeriodic(interval) .setExtras(new PersistableBundleCompat()) .build(); assertThat(request.getJobId()).isGreaterThan(0); assertThat(request.getTag()).isEqualTo(DummyJobs.SuccessJob.TAG); assertThat(request.getIntervalMs()).isEqualTo(interval); assertThat(request.getFlexMs()).isEqualTo(interval); assertThat(request.isPeriodic()).isTrue(); assertThat(request.isFlexSupport()).isFalse(); assertThat(request.getStartMs()).isNegative(); assertThat(request.getEndMs()).isNegative(); assertThat(request.getBackoffMs()).isEqualTo(JobRequest.DEFAULT_BACKOFF_MS); assertThat(request.getBackoffPolicy()).isEqualTo(JobRequest.DEFAULT_BACKOFF_POLICY); assertThat(request.getExtras()).isNotNull(); assertThat(request.isExact()).isFalse(); assertThat(request.requiredNetworkType()).isEqualTo(JobRequest.DEFAULT_NETWORK_TYPE); assertThat(request.requirementsEnforced()).isFalse(); assertThat(request.requiresCharging()).isFalse(); assertThat(request.requiresDeviceIdle()).isFalse(); }
/** * Only valid if the job isn't periodic. * * @return The start of the time frame when the job will run after it's been scheduled. * @see JobRequest#getStartMs() */ public long getStartMs() { return mRequest.getStartMs(); }
private boolean isImmediate(JobRequest jobRequest) { return jobRequest.getStartMs() < IMMEDIATE_THRESHOLD; }
private boolean isSoonButNotImmediate(JobRequest jobRequest) { return IMMEDIATE_THRESHOLD < jobRequest.getStartMs() && jobRequest.getStartMs() < SOON_THRESHOLD; }
public static long getStartMs(JobRequest request) { if (request.getFailureCount() > 0) { return request.getBackoffOffset(); } else { return request.getStartMs(); } }
Set<JobRequest> requests = new HashSet<>(manager.getAllJobRequestsForTag(builder.mTag)); for (JobRequest request : requests) { if (!request.isExact() || request.getStartMs() != JobRequest.START_NOW) { manager.cancel(request.getJobId());
/** * Cancel this request if it has been scheduled. Note that if the job isn't periodic, then the * time passed since the job has been scheduled is subtracted from the time frame. For example * a job should run between 4 and 6 seconds from now. You cancel the scheduled job after 2 * seconds, then the job will run between 2 and 4 seconds after it's been scheduled again. * * @return A builder to modify the parameters. */ public Builder cancelAndEdit() { // create a temporary variable, because .cancel() will reset mScheduledAt long scheduledAt = mScheduledAt; JobManager.instance().cancel(getJobId()); Builder builder = new Builder(this.mBuilder); mStarted = false; if (!isPeriodic()) { long offset = JobConfig.getClock().currentTimeMillis() - scheduledAt; long minValue = 1L; // 1ms builder.setExecutionWindow(Math.max(minValue, getStartMs() - offset), Math.max(minValue, getEndMs() - offset)); } return builder; }
@Test public void testAdapter() throws InterruptedException, IOException { FilePayload payload = buildPayload(); int tenMinutes = 10 * 60 * 1000; UploadRequest<FilePayload> request = buildUploadRequest(payload, tenMinutes); JobRequest adapted = AndroidJobStrategy.adapt(request); assertEquals(20, adapted.getStartMs()); assertEquals(tenMinutes, adapted.getEndMs()); assertEquals(true, adapted.requiresCharging()); assertEquals(false, adapted.requiresDeviceIdle()); assertEquals(100, adapted.getBackoffMs()); assertEquals(JobRequest.BackoffPolicy.LINEAR, adapted.getBackoffPolicy()); assertEquals(9, adapted.getExtras().get("maxErrorRetries")); } }
@Override public void plantOneOff(JobRequest request) { PendingIntent pendingIntent = getPendingIntent(request, false); AlarmManager alarmManager = getAlarmManager(); if (alarmManager == null) { return; } try { if (request.isExact()) { if (request.getStartMs() == 1 && request.getFailureCount() <= 0) { // this job should start immediately PlatformAlarmService.start(mContext, request.getJobId(), request.getTransientExtras()); } else { plantOneOffExact(request, alarmManager, pendingIntent); } } else { plantOneOffInexact(request, alarmManager, pendingIntent); } } catch (Exception e) { // https://gist.github.com/vRallev/621b0b76a14ddde8691c mCat.e(e); } }