/** * <b>WARNING:</b> Please use this method carefully. It's only meant to be used for testing purposes * and could break how the library works. * <br> * <br> * Programmatic switch to enable or disable the given API. This only has an impact for new scheduled jobs. * * @param api The API which should be enabled or disabled. * @param enabled Whether the API should be enabled or disabled. */ public static void setApiEnabled(@NonNull JobApi api, boolean enabled) { ENABLED_APIS.put(api, enabled); CAT.w("setApiEnabled - %s, %b", api, enabled); }
@Override public void plantPeriodicFlexSupport(JobRequest request) { mCat.w("plantPeriodicFlexSupport called although flex is supported"); super.plantPeriodicFlexSupport(request); }
@Override public void plantPeriodicFlexSupport(JobRequest request) { CAT.w("plantPeriodicFlexSupport called although flex is supported"); plantPeriodic(request); }
/** * <b>WARNING:</b> You shouldn't call this method. It only exists for testing and debugging * purposes. The {@link JobManager} automatically decides which API suits best for a {@link Job}. * * @param api The {@link JobApi} which will be used for future scheduled JobRequests. */ public static void forceApi(@NonNull JobApi api) { for (JobApi jobApi : JobApi.values()) { ENABLED_APIS.put(jobApi, jobApi == api); } CAT.w("forceApi - %s", api); }
public Job createJob(String tag) { Job job = null; boolean atLeastOneCreatorSeen = false; for (JobCreator jobCreator : mJobCreators) { atLeastOneCreatorSeen = true; job = jobCreator.create(tag); if (job != null) { break; } } if (!atLeastOneCreatorSeen) { CAT.w("no JobCreator added"); } return job; }
public synchronized Future<Job.Result> execute(@NonNull Context context, @NonNull JobRequest request, @Nullable Job job, @NonNull Bundle transientExtras) { mStartingRequests.remove(request); if (job == null) { CAT.w("JobCreator returned null for tag %s", request.getTag()); return null; } if (job.isFinished()) { throw new IllegalStateException(String.format(Locale.ENGLISH, "Job for tag %s was already run, a creator should always create a new Job instance", request.getTag())); } job.setContext(context).setRequest(request, transientExtras); CAT.i("Executing %s, context %s", request, context.getClass().getSimpleName()); mJobs.put(request.getJobId(), job); return JobConfig.getExecutorService().submit(new JobCallable(job)); }
/*package*/ void deleteDatabaseFile(String fileName) { if (fileName.equalsIgnoreCase(":memory:") || fileName.trim().length() == 0) { return; } CAT.e("deleting the database file: " + fileName); try { File databaseFile = new File(fileName); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { deleteApi16(databaseFile); } else { deleteApi14(JobManager.instance().getContext(), databaseFile); } } catch (Exception e) { /* print warning and ignore exception */ CAT.w(e, "delete failed: " + e.getMessage()); } }
public static boolean isGcmApiSupported(Context context) { try { if (!checkedServiceEnabled) { checkedServiceEnabled = true; setServiceEnabled(context, GCM_IN_CLASSPATH); } return GCM_IN_CLASSPATH && GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS && isGcmServiceRegistered(context) == ConnectionResult.SUCCESS; } catch (Throwable t) { // seeing sometimes a DeadObjectException, return false, we can't do anything in this case // still sometimes seeing a NoClassDefFoundError here if (BuildConfig.DEBUG) { CAT.w(t.getMessage()); } return false; } }
/*package*/ boolean meetsRequirements(boolean checkRequirementsEnforced) { if (checkRequirementsEnforced && !getParams().getRequest().requirementsEnforced()) { return true; } if (!isRequirementChargingMet()) { CAT.w("Job requires charging, reschedule"); return false; } if (!isRequirementDeviceIdleMet()) { CAT.w("Job requires device to be idle, reschedule"); return false; } if (!isRequirementNetworkTypeMet()) { CAT.w("Job requires network to be %s, but was %s", getParams().getRequest().requiredNetworkType(), Device.getNetworkType(getContext())); return false; } if (!isRequirementBatteryNotLowMet()) { CAT.w("Job requires battery not be low, reschedule"); return false; } if (!isRequirementStorageNotLowMet()) { CAT.w("Job requires storage not be low, reschedule"); return false; } return true; }
CAT.w("AllowSmallerIntervals enabled, this will crash on Android N and later, interval %d (minimum is %d), flex %d (minimum is %d)", mIntervalMs, MIN_INTERVAL, mFlexMs, MIN_FLEX); CAT.w("Attention: your execution window is too large. This could result in undesired behavior, see https://github.com/evernote/android-job/wiki/FAQ"); CAT.w("Warning: job with tag %s scheduled over a year in the future", mTag);
private WorkManager getWorkManager() { // don't cache the instance, it could change under the hood, e.g. during tests WorkManager workManager; try { workManager = WorkManager.getInstance(); } catch (Throwable t) { workManager = null; } if (workManager == null) { try { WorkManager.initialize(mContext, new Configuration.Builder().build()); workManager = WorkManager.getInstance(); } catch (Throwable ignored) { } CAT.w("WorkManager getInstance() returned null, now: %s", workManager); } return workManager; }
@Override public Job.Result call() throws Exception { try { // just in case something was blocking and the wake lock is no longer acquired WakeLockUtil.acquireWakeLock(mJob.getContext(), mWakeLock, WAKE_LOCK_TIMEOUT); return runJob(); } finally { markJobAsFinished(mJob); if (mWakeLock == null || !mWakeLock.isHeld()) { CAT.w("Wake lock was not held after job %s was done. The job took too long to complete. This could have unintended side effects on your app.", mJob); } WakeLockUtil.releaseWakeLock(mWakeLock); } }
@Test public void testSingleCustomLoggerAddAfter() { JobCat cat = new JobCat("Tag"); TestLogger printer = new TestLogger(); assertThat(JobConfig.addLogger(printer)).isTrue(); cat.d("hello"); cat.w("world"); assertThat(printer.mMessages).containsExactly("hello", "world"); }
@Test public void test100Loggers() { JobCat cat1 = new JobCat("Tag1"); List<TestLogger> printers = new ArrayList<>(); for (int i = 0; i < 100; i++) { TestLogger printer = new TestLogger(); assertThat(JobConfig.addLogger(printer)).isTrue(); printers.add(printer); } JobCat cat2 = new JobCat("Tag2"); cat1.d("hello"); cat2.w("world"); for (TestLogger printer : printers) { assertThat(printer.mTags).containsExactly("Tag1", "Tag2"); assertThat(printer.mMessages).containsExactly("hello", "world"); } TestLogger removedPrinter = printers.remove(50); JobConfig.removeLogger(removedPrinter); cat1.d("third"); for (TestLogger printer : printers) { assertThat(printer.mTags).containsExactly("Tag1", "Tag2", "Tag1"); assertThat(printer.mMessages).containsExactly("hello", "world", "third"); } assertThat(removedPrinter.mTags).containsExactly("Tag1", "Tag2"); assertThat(removedPrinter.mMessages).containsExactly("hello", "world"); }
@Test public void testSingleCustomLoggerAddBefore() { TestLogger printer = new TestLogger(); assertThat(JobConfig.addLogger(printer)).isTrue(); JobCat cat = new JobCat("Tag"); cat.d("hello"); cat.w("world"); assertThat(printer.mMessages).contains("hello", "world"); }
mCat.w("Running JobRequest on a main thread, this could cause stutter or ANR in your app.");
CAT.w("you haven't registered a JobCreator with addJobCreator(), it's likely that your job never will be executed");
@Override public void plantPeriodicFlexSupport(JobRequest request) { mCat.w("plantPeriodicFlexSupport called although flex is supported"); super.plantPeriodicFlexSupport(request); }
/** * <b>WARNING:</b> You shouldn't call this method. It only exists for testing and debugging * purposes. The {@link JobManager} automatically decides which API suits best for a {@link Job}. * * @param api The {@link JobApi} which will be used for future scheduled JobRequests. */ public static void forceApi(@NonNull JobApi api) { for (JobApi jobApi : JobApi.values()) { ENABLED_APIS.put(jobApi, jobApi == api); } CAT.w("forceApi - %s", api); }