@Test @Config(sdk = Build.VERSION_CODES.LOLLIPOP) public void verifyReset() { assertThat(JobConfig.isApiEnabled(JobApi.V_19)).isTrue(); // default JobConfig.setApiEnabled(JobApi.V_19, false); assertThat(JobConfig.isApiEnabled(JobApi.V_19)).isFalse(); // did change assertThat(JobConfig.isAllowSmallerIntervalsForMarshmallow()).isFalse(); // default JobConfig.setAllowSmallerIntervalsForMarshmallow(true); assertThat(JobConfig.isAllowSmallerIntervalsForMarshmallow()).isTrue(); // did change JobConfig.reset(); assertThat(JobConfig.isApiEnabled(JobApi.V_19)).isTrue(); // default assertThat(JobConfig.isAllowSmallerIntervalsForMarshmallow()).isFalse(); // default }
@Override public boolean onStartJob(final JobParameters params) { JobConfig.getExecutorService().execute(new Runnable() { @Override public void run() {
private static void closeDatabase(@Nullable SQLiteDatabase database) { // SQLiteDatabase doesn't implement Closable on some 4.0.3 devices, see #182 if (database != null && JobConfig.isCloseDatabase()) { try { database.close(); } catch (Exception ignored) { } } } }
protected long getTriggerAtMillis(JobRequest request) { if (JobConfig.isForceRtc()) { return JobConfig.getClock().currentTimeMillis() + Common.getAverageDelayMs(request); } else { return JobConfig.getClock().elapsedRealtime() + Common.getAverageDelayMs(request); } }
@Test public void verifyForceApiDisabledOtherApis() { JobApi forcedApi = JobApi.GCM; for (JobApi api : JobApi.values()) { assertThat(JobConfig.isApiEnabled(api)).isTrue(); } JobConfig.forceApi(forcedApi); for (JobApi api : JobApi.values()) { assertThat(JobConfig.isApiEnabled(api)).isEqualTo(api == forcedApi); } }
@NonNull public static JobApi getDefault(Context context) { if (WORK_MANAGER.isSupported(context) && JobConfig.isApiEnabled(WORK_MANAGER)) { return WORK_MANAGER; } else if (V_26.isSupported(context) && JobConfig.isApiEnabled(V_26)) { return V_26; } else if (V_24.isSupported(context) && JobConfig.isApiEnabled(V_24)) { return V_24; } else if (V_21.isSupported(context) && JobConfig.isApiEnabled(V_21)) { return V_21; } else if (GCM.isSupported(context) && JobConfig.isApiEnabled(GCM)) { return GCM; } else if (V_19.isSupported(context) && JobConfig.isApiEnabled(V_19)) { return V_19; } else if (JobConfig.isApiEnabled(V_14)) { return V_14; } else { throw new IllegalStateException("All supported APIs are disabled"); } } }
/*package*/ void updateStats(boolean incFailureCount, boolean updateLastRun) { ContentValues contentValues = new ContentValues(); if (incFailureCount) { mFailureCount++; contentValues.put(JobStorage.COLUMN_NUM_FAILURES, mFailureCount); } if (updateLastRun) { mLastRun = JobConfig.getClock().currentTimeMillis(); contentValues.put(JobStorage.COLUMN_LAST_RUN, mLastRun); } JobManager.instance().getJobStorage().update(this, contentValues); }
/*package*/ static long getMinInterval() { return JobConfig.isAllowSmallerIntervalsForMarshmallow() ? TimeUnit.MINUTES.toMillis(1) : MIN_INTERVAL; }
@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_force_26: JobConfig.forceApi(JobApi.V_26); return true; case R.id.action_force_24: JobConfig.forceApi(JobApi.V_24); return true; case R.id.action_force_21: JobConfig.forceApi(JobApi.V_21); return true; case R.id.action_force_19: JobConfig.forceApi(JobApi.V_19); return true; case R.id.action_force_14: JobConfig.forceApi(JobApi.V_14); return true; case R.id.action_force_gcm: JobConfig.forceApi(JobApi.GCM); return true; default: return super.onOptionsItemSelected(item); } }
@Override protected void before() { Context context = InstrumentationRegistry.getTargetContext(); Executor executor = new Executor() { @Override public void execute(@NonNull Runnable command) { command.run(); } }; WorkManagerTestInitHelper.initializeTestWorkManager(context, new Configuration.Builder().setExecutor(executor).build()); JobConfig.setJobReschedulePause(0, TimeUnit.MILLISECONDS); JobConfig.setSkipJobReschedule(true); JobConfig.forceApi(JobApi.WORK_MANAGER); mManager = JobManager.create(context); mManager.cancelAll(); }
@Test public void verifyCloseDatabase() { assertThat(JobConfig.isCloseDatabase()).isFalse(); // default SQLiteDatabase database = mock(SQLiteDatabase.class); JobStorage storage = manager().getJobStorage(); storage.injectDatabase(database); storage.get(1); verify(database, times(1)).query(anyString(), nullable(String[].class), anyString(), any(String[].class), nullable(String.class), nullable(String.class), nullable(String.class)); verify(database, times(0)).close(); JobConfig.setCloseDatabase(true); storage.get(1); verify(database, times(2)).query(anyString(), nullable(String[].class), anyString(), any(String[].class), nullable(String.class), nullable(String.class), nullable(String.class)); verify(database, times(1)).close(); } }
public synchronized int nextJobId() { if (mJobCounter == null) { mJobCounter = new AtomicInteger(getMaxJobId()); } int id = mJobCounter.incrementAndGet(); int offset = JobConfig.getJobIdOffset(); if (id < offset || id >= JobIdsInternal.RESERVED_JOB_ID_RANGE_START) { /* * An overflow occurred. It'll happen rarely, but just in case reset the ID and start from scratch. * Existing jobs will be treated as orphaned and will be overwritten. */ mJobCounter.set(offset); id = mJobCounter.incrementAndGet(); } mPreferences.edit().putInt(JOB_ID_COUNTER, id).apply(); return id; }
protected int getType(boolean wakeup) { if (wakeup) { return JobConfig.isForceRtc() ? AlarmManager.RTC_WAKEUP : AlarmManager.ELAPSED_REALTIME_WAKEUP; } else { return JobConfig.isForceRtc() ? AlarmManager.RTC : AlarmManager.ELAPSED_REALTIME; } }
@Override protected void onHandleWork(@NonNull Intent intent) { /* * Delay this slightly. This avoids a race condition if the app was launched by the * AlarmManager. Then the alarm was already removed, but the JobRequest might still * be available in the storage. We still catch this case, because we never execute * a job with the same ID twice. Nonetheless, add the delay to save resources. */ try { CAT.d("Reschedule service started"); SystemClock.sleep(JobConfig.getJobReschedulePause()); JobManager manager; try { manager = JobManager.create(this); } catch (Exception e) { return; } Set<JobRequest> requests = manager.getAllJobRequests(null, true, true); int rescheduledCount = rescheduleJobs(manager, requests); CAT.d("Reschedule %d jobs of %d jobs", rescheduledCount, requests.size()); } finally { if (latch != null) { // latch can be null, if the service was restarted after a process death latch.countDown(); } } }
public boolean isSupported(Context context) { switch (this) { case WORK_MANAGER: return WorkManagerAvailableHelper.isWorkManagerApiSupported(); case V_26: return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && isServiceEnabled(context, PlatformJobService.class); case V_24: return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && isServiceEnabledAndHasPermission(context, PlatformJobService.class, JOB_SCHEDULER_PERMISSION); case V_21: return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && isServiceEnabledAndHasPermission(context, PlatformJobService.class, JOB_SCHEDULER_PERMISSION); case V_19: return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && isServiceEnabled(context, PlatformAlarmService.class) && isBroadcastEnabled(context, PlatformAlarmReceiver.class); case V_14: return JobConfig.isForceAllowApi14() || (isServiceEnabled(context, PlatformAlarmService.class) && isServiceEnabled(context, PlatformAlarmServiceExact.class) && isBroadcastEnabled(context, PlatformAlarmReceiver.class)); case GCM: try { // see https://github.com/evernote/android-job/issues/487 return GcmAvailableHelper.isGcmApiSupported(context); } catch (Exception e) { return false; } default: throw new IllegalStateException("not implemented"); } }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mJobManager = JobManager.instance(); if (savedInstanceState != null) { mLastJobId = savedInstanceState.getInt(LAST_JOB_ID, 0); } CompoundButton enableGcm = findViewById(R.id.enable_gcm); mRequiresCharging = findViewById(R.id.check_requires_charging); mRequiresDeviceIdle = findViewById(R.id.check_requires_device_idle); mNetworkTypeSpinner = findViewById(R.id.spinner_network_type); ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, getNetworkTypesAsString()); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); mNetworkTypeSpinner.setAdapter(adapter); enableGcm.setChecked(JobConfig.isApiEnabled(JobApi.GCM)); enableGcm.setEnabled(JobApi.GCM.isSupported(this)); enableGcm.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { JobConfig.setApiEnabled(JobApi.GCM, isChecked); } }); }
calendar.setTimeInMillis(JobConfig.getClock().currentTimeMillis());
/*package*/ static long getMinFlex() { return JobConfig.isAllowSmallerIntervalsForMarshmallow() ? TimeUnit.SECONDS.toMillis(30) : MIN_FLEX; }
protected long getTriggerAtMillis(JobRequest request) { if (JobConfig.isForceRtc()) { return JobConfig.getClock().currentTimeMillis() + Common.getAverageDelayMs(request); } else { return JobConfig.getClock().elapsedRealtime() + Common.getAverageDelayMs(request); } }