protected JobInfo.Builder createBaseBuilder(JobRequest request, boolean allowPersisting) { JobInfo.Builder builder = new JobInfo.Builder(request.getJobId(), new ComponentName(mContext, PlatformJobService.class)) .setRequiresCharging(request.requiresCharging()) .setRequiresDeviceIdle(request.requiresDeviceIdle()) .setRequiredNetworkType(convertNetworkType(request.requiredNetworkType())) .setPersisted(allowPersisting && !request.isTransient() && JobUtil.hasBootPermission(mContext)); return setTransientBundle(request, builder); }
@Override public void plantPeriodicFlexSupport(JobRequest request) { long startMs = Common.getStartMsSupportFlex(request); long endMs = Common.getEndMsSupportFlex(request); JobInfo jobInfo = createBuilderOneOff(createBaseBuilder(request, true), startMs, endMs).build(); int scheduleResult = schedule(jobInfo); if (scheduleResult == ERROR_BOOT_PERMISSION) { jobInfo = createBuilderOneOff(createBaseBuilder(request, false), startMs, endMs).build(); scheduleResult = schedule(jobInfo); } mCat.d("Schedule periodic (flex support) jobInfo %s, %s, start %s, end %s, flex %s", scheduleResultToString(scheduleResult), request, JobUtil.timeToString(startMs), JobUtil.timeToString(endMs), JobUtil.timeToString(request.getFlexMs())); }
@Override public void plantPeriodic(JobRequest request) { long intervalMs = request.getIntervalMs(); long flexMs = request.getFlexMs(); JobInfo jobInfo = createBuilderPeriodic(createBaseBuilder(request, true), intervalMs, flexMs).build(); int scheduleResult = schedule(jobInfo); if (scheduleResult == ERROR_BOOT_PERMISSION) { jobInfo = createBuilderPeriodic(createBaseBuilder(request, false), intervalMs, flexMs).build(); scheduleResult = schedule(jobInfo); } mCat.d("Schedule periodic jobInfo %s, %s, interval %s, flex %s", scheduleResultToString(scheduleResult), request, JobUtil.timeToString(intervalMs), JobUtil.timeToString(flexMs)); }
@Override public boolean isPlatformJobScheduled(JobRequest request) { List<JobInfo> pendingJobs; try { pendingJobs = getJobScheduler().getAllPendingJobs(); } catch (Exception e) { // it's possible that this throws an exception, see https://gist.github.com/vRallev/a59947dd3932d2642641 mCat.e(e); return false; } //noinspection ConstantConditions if (pendingJobs == null || pendingJobs.isEmpty()) { return false; } for (JobInfo info : pendingJobs) { if (isJobInfoScheduled(info, request)) { return true; } } return false; }
@Override public void cancel(int jobId) { try { getJobScheduler().cancel(jobId); } catch (Exception e) { // https://gist.github.com/vRallev/5d48a4a8e8d05067834e mCat.e(e); } TransientBundleCompat.cancel(mContext, jobId, null); }
@Override public void plantPeriodicFlexSupport(JobRequest request) { mCat.w("plantPeriodicFlexSupport called although flex is supported"); super.plantPeriodicFlexSupport(request); }
@Override protected int convertNetworkType(@NonNull JobRequest.NetworkType networkType) { switch (networkType) { case NOT_ROAMING: return JobInfo.NETWORK_TYPE_NOT_ROAMING; default: return super.convertNetworkType(networkType); } } }
@NonNull private JobProxy createProxy(Context context) { switch (this) { case WORK_MANAGER: return new JobProxyWorkManager(context); case V_26: return new JobProxy26(context); case V_24: return new JobProxy24(context); case V_21: return new JobProxy21(context); case V_19: return new JobProxy19(context); case V_14: return new JobProxy14(context); case GCM: return new JobProxyGcm(context); default: throw new IllegalStateException("not implemented"); } }
@Override public boolean isPlatformJobScheduled(JobRequest request) { List<JobInfo> pendingJobs; try { pendingJobs = getJobScheduler().getAllPendingJobs(); } catch (Exception e) { // it's possible that this throws an exception, see https://gist.github.com/vRallev/a59947dd3932d2642641 mCat.e(e); return false; } //noinspection ConstantConditions if (pendingJobs == null || pendingJobs.isEmpty()) { return false; } for (JobInfo info : pendingJobs) { if (isJobInfoScheduled(info, request)) { return true; } } return false; }
protected final int schedule(JobInfo jobInfo) { JobScheduler jobScheduler = getJobScheduler(); if (jobScheduler == null) { throw new JobProxyIllegalStateException("JobScheduler is null"); } try { return jobScheduler.schedule(jobInfo); } catch (IllegalArgumentException e) { mCat.e(e); String message = e.getMessage(); if (message != null && message.contains("RECEIVE_BOOT_COMPLETED")) { return ERROR_BOOT_PERMISSION; } else if (message != null && message.contains("No such service ComponentInfo")) { // this will reset the proxy and in the worst case use the AlarmManager throw new JobProxyIllegalStateException(e); } else { throw e; } } catch (NullPointerException e) { /* Attempt to invoke interface method 'int android.app.job.IJobScheduler.schedule(android.app.job.JobInfo)' on a null object reference at android.app.JobSchedulerImpl.schedule(JobSchedulerImpl.java:42) at com.evernote.android.job.v21.JobProxy21.schedule(JobProxy21.java:198) */ mCat.e(e); throw new JobProxyIllegalStateException(e); } }
@Override public void plantPeriodicFlexSupport(JobRequest request) { mCat.w("plantPeriodicFlexSupport called although flex is supported"); super.plantPeriodicFlexSupport(request); }
@Override protected int convertNetworkType(@NonNull JobRequest.NetworkType networkType) { switch (networkType) { case NOT_ROAMING: return JobInfo.NETWORK_TYPE_NOT_ROAMING; default: return super.convertNetworkType(networkType); } } }
@NonNull private JobProxy createProxy(Context context) { switch (this) { case V_26: return new JobProxy26(context); case V_24: return new JobProxy24(context); case V_21: return new JobProxy21(context); case V_19: return new JobProxy19(context); case V_14: return new JobProxy14(context); case GCM: return new JobProxyGcm(context); default: throw new IllegalStateException("not implemented"); } }
@Override public void plantOneOff(JobRequest request) { long startMs = Common.getStartMs(request); long endMs = Common.getEndMs(request, true); JobInfo jobInfo = createBuilderOneOff(createBaseBuilder(request, true), startMs, endMs).build(); int scheduleResult = schedule(jobInfo); if (scheduleResult == ERROR_BOOT_PERMISSION) { jobInfo = createBuilderOneOff(createBaseBuilder(request, false), startMs, endMs).build(); scheduleResult = schedule(jobInfo); } mCat.d("Schedule one-off jobInfo %s, %s, start %s, end %s (from now), reschedule count %d", scheduleResultToString(scheduleResult), request, JobUtil.timeToString(startMs), JobUtil.timeToString(Common.getEndMs(request, false)), Common.getRescheduleCount(request)); }
@Override public void plantPeriodic(JobRequest request) { long intervalMs = request.getIntervalMs(); long flexMs = request.getFlexMs(); JobInfo jobInfo = createBuilderPeriodic(createBaseBuilder(request, true), intervalMs, flexMs).build(); int scheduleResult = schedule(jobInfo); if (scheduleResult == ERROR_BOOT_PERMISSION) { jobInfo = createBuilderPeriodic(createBaseBuilder(request, false), intervalMs, flexMs).build(); scheduleResult = schedule(jobInfo); } mCat.d("Schedule periodic jobInfo %s, %s, interval %s, flex %s", scheduleResultToString(scheduleResult), request, JobUtil.timeToString(intervalMs), JobUtil.timeToString(flexMs)); }
protected JobInfo.Builder createBaseBuilder(JobRequest request, boolean allowPersisting) { JobInfo.Builder builder = new JobInfo.Builder(request.getJobId(), new ComponentName(mContext, PlatformJobService.class)) .setRequiresCharging(request.requiresCharging()) .setRequiresDeviceIdle(request.requiresDeviceIdle()) .setRequiredNetworkType(convertNetworkType(request.requiredNetworkType())) .setPersisted(allowPersisting && !request.isTransient() && JobUtil.hasBootPermission(mContext)); return setTransientBundle(request, builder); }
@Override public void cancel(int jobId) { try { getJobScheduler().cancel(jobId); } catch (Exception e) { // https://gist.github.com/vRallev/5d48a4a8e8d05067834e mCat.e(e); } TransientBundleCompat.cancel(mContext, jobId, null); }
@Override public void plantOneOff(JobRequest request) { long startMs = Common.getStartMs(request); long endMs = Common.getEndMs(request, true); JobInfo jobInfo = createBuilderOneOff(createBaseBuilder(request, true), startMs, endMs).build(); int scheduleResult = schedule(jobInfo); if (scheduleResult == ERROR_BOOT_PERMISSION) { jobInfo = createBuilderOneOff(createBaseBuilder(request, false), startMs, endMs).build(); scheduleResult = schedule(jobInfo); } mCat.d("Schedule one-off jobInfo %s, %s, start %s, end %s (from now), reschedule count %d", scheduleResultToString(scheduleResult), request, JobUtil.timeToString(startMs), JobUtil.timeToString(Common.getEndMs(request, false)), Common.getRescheduleCount(request)); }
protected final int schedule(JobInfo jobInfo) { JobScheduler jobScheduler = getJobScheduler(); if (jobScheduler == null) { throw new JobProxyIllegalStateException("JobScheduler is null"); } try { return jobScheduler.schedule(jobInfo); } catch (IllegalArgumentException e) { mCat.e(e); String message = e.getMessage(); if (message != null && message.contains("RECEIVE_BOOT_COMPLETED")) { return ERROR_BOOT_PERMISSION; } else if (message != null && message.contains("No such service ComponentInfo")) { // this will reset the proxy and in the worst case use the AlarmManager throw new JobProxyIllegalStateException(e); } else { throw e; } } catch (NullPointerException e) { /* Attempt to invoke interface method 'int android.app.job.IJobScheduler.schedule(android.app.job.JobInfo)' on a null object reference at android.app.JobSchedulerImpl.schedule(JobSchedulerImpl.java:42) at com.evernote.android.job.v21.JobProxy21.schedule(JobProxy21.java:198) */ mCat.e(e); throw new JobProxyIllegalStateException(e); } }
@Override public void plantPeriodicFlexSupport(JobRequest request) { long startMs = Common.getStartMsSupportFlex(request); long endMs = Common.getEndMsSupportFlex(request); JobInfo jobInfo = createBuilderOneOff(createBaseBuilder(request, true), startMs, endMs).build(); int scheduleResult = schedule(jobInfo); if (scheduleResult == ERROR_BOOT_PERMISSION) { jobInfo = createBuilderOneOff(createBaseBuilder(request, false), startMs, endMs).build(); scheduleResult = schedule(jobInfo); } mCat.d("Schedule periodic (flex support) jobInfo %s, %s, start %s, end %s, flex %s", scheduleResultToString(scheduleResult), request, JobUtil.timeToString(startMs), JobUtil.timeToString(endMs), JobUtil.timeToString(request.getFlexMs())); }