RepoPilotOpen in app →

Evernote/android-job

Android library to handle jobs in the background.

Mixed

Stale — last commit 4y ago

weakest axis
Use as dependencyMixed

last commit was 4y ago; top contributor handles 90% of recent commits…

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isMixed

last commit was 4y ago; no CI workflows detected

  • 10 active contributors
  • Apache-2.0 licensed
  • Tests present
Show all 6 evidence items →
  • Stale — last commit 4y ago
  • Single-maintainer risk — top contributor 90% of recent commits
  • No CI workflows detected
What would change the summary?
  • Use as dependency MixedHealthy if: 1 commit in the last 365 days; diversify commit ownership (top <90%)
  • Deploy as-is MixedHealthy if: 1 commit in the last 180 days

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Forkable" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/evernote/android-job?axis=fork)](https://repopilot.app/r/evernote/android-job)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/evernote/android-job on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: Evernote/android-job

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/Evernote/android-job shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

WAIT — Stale — last commit 4y ago

  • 10 active contributors
  • Apache-2.0 licensed
  • Tests present
  • ⚠ Stale — last commit 4y ago
  • ⚠ Single-maintainer risk — top contributor 90% of recent commits
  • ⚠ No CI workflows detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live Evernote/android-job repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/Evernote/android-job.

What it runs against: a local clone of Evernote/android-job — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in Evernote/android-job | Confirms the artifact applies here, not a fork | | 2 | License is still Apache-2.0 | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 1425 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>Evernote/android-job</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of Evernote/android-job. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/Evernote/android-job.git
#   cd android-job
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of Evernote/android-job and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "Evernote/android-job(\\.git)?\\b" \\
  && ok "origin remote is Evernote/android-job" \\
  || miss "origin remote is not Evernote/android-job (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
  && ok "license is Apache-2.0" \\
  || miss "license drift — was Apache-2.0 at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "library/src/main/java/com/evernote/android/job/JobManager.java" \\
  && ok "library/src/main/java/com/evernote/android/job/JobManager.java" \\
  || miss "missing critical file: library/src/main/java/com/evernote/android/job/JobManager.java"
test -f "library/src/main/java/com/evernote/android/job/Job.java" \\
  && ok "library/src/main/java/com/evernote/android/job/Job.java" \\
  || miss "missing critical file: library/src/main/java/com/evernote/android/job/Job.java"
test -f "library/src/main/java/com/evernote/android/job/JobApi.java" \\
  && ok "library/src/main/java/com/evernote/android/job/JobApi.java" \\
  || miss "missing critical file: library/src/main/java/com/evernote/android/job/JobApi.java"
test -f "library/src/main/java/com/evernote/android/job/JobCreator.java" \\
  && ok "library/src/main/java/com/evernote/android/job/JobCreator.java" \\
  || miss "missing critical file: library/src/main/java/com/evernote/android/job/JobCreator.java"
test -f "library/src/main/java/com/evernote/android/job/JobConfig.java" \\
  && ok "library/src/main/java/com/evernote/android/job/JobConfig.java" \\
  || miss "missing critical file: library/src/main/java/com/evernote/android/job/JobConfig.java"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 1425 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~1395d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/Evernote/android-job"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

android-job is a deprecated Android background job scheduling library that abstracts over JobScheduler (API 21+), GcmNetworkManager, and AlarmManager to provide a unified API for running tasks in the background across Android Ice Cream Sandwich (API 14) to Oreo and beyond. It handles the complexity of choosing the right scheduler based on device API level and provides backward-compatible task persistence and retry logic. The library has been superseded by Google's WorkManager but remains in the codebase for legacy applications. Dual-module structure: the main library/ module contains the core job scheduling abstraction (Job, JobRequest, JobManager classes) with pluggable implementations for JobScheduler/GcmNetworkManager/AlarmManager; the demo/ application at demo/src/main/java/com/evernote/android/job/demo/ provides reference implementations (DemoJobCreator, DemoSyncJob) showing how to extend Job and initialize JobManager in Application.onCreate().

👥Who it's for

Android app developers maintaining legacy applications that were built before WorkManager became the standard; specifically those supporting devices running Android 4.0+ who need reliable background job scheduling without rewriting their entire background task infrastructure.

🌱Maturity & risk

This project is actively abandoned — the README explicitly states 'This library is not maintained anymore and there will be no further releases except for very critical bug fixes.' Last release was 1.4.3 (version visible in README). The codebase is stable (586KB of Java) and was production-ready during its maintenance period, but no new features or non-critical bug fixes will be accepted. Suitable only for maintaining existing apps, not for new projects.

High risk for new projects. The library is unmaintained with no active development; depends on deprecated Google Play Services APIs (playServicesVersion = '17.0.0' from 2019); targets compileSdkVersion 31 which may cause friction with modern app stores requiring higher targets; single-maintainer risk (Evernote organization appears inactive on this repo). Migration path to WorkManager exists but requires code refactoring.

Active areas of work

Nothing — this is a maintained-but-not-developed repository. The project is in archive/legacy status with a deprecation notice. The codebase will receive critical security fixes only if necessary, but no active work is occurring. Evernote has directed users to migrate to WorkManager instead.

🚀Get running

Clone: git clone https://github.com/evernote/android-job.git && cd android-job. Build: ./gradlew build (Gradle wrapper included, targets Gradle 7.4.2 per build.gradle). To run the demo app on an emulator or device: ./gradlew demo:installDebug demo:run. Requires JDK 8+, Android SDK with API 31 (compileSdkVersion = 31 in build.gradle ext block).

Daily commands: Development: ./gradlew build compiles all modules. Demo app: ./gradlew demo:installDebug installs to emulator, then open the app to manually test job scheduling. Unit tests: ./gradlew test (Robolectric configured in build.gradle). Integration tests require Android emulator or device.

🗺️Map of the codebase

  • library/src/main/java/com/evernote/android/job/JobManager.java — Central public API for scheduling and managing background jobs; primary entry point for all library users
  • library/src/main/java/com/evernote/android/job/Job.java — Abstract base class all background jobs must extend; defines job execution contract and result handling
  • library/src/main/java/com/evernote/android/job/JobApi.java — Abstract interface defining core job scheduling operations across different Android API levels
  • library/src/main/java/com/evernote/android/job/JobCreator.java — Factory interface required by all apps to instantiate Job subclasses at runtime
  • library/src/main/java/com/evernote/android/job/JobConfig.java — Global configuration class controlling logging, API selection, and job behavior across the library
  • library/src/main/AndroidManifest.xml — Declares required permissions, broadcast receivers, and services needed for all job scheduling strategies
  • library/build.gradle — Build configuration defining dependencies on Google Play Services and AndroidX WorkManager support

🛠️How to make changes

Add a New Background Job Type

  1. Create a new class extending com.evernote.android.job.Job with onRunJob() implementation (library/src/main/java/com/evernote/android/job/Job.java)
  2. In your JobCreator implementation, add a case in create() method to instantiate your new job (demo/src/main/java/com/evernote/android/job/demo/DemoJobCreator.java)
  3. Call JobManager.create().setTag("my-job-tag").setExecutionWindow(minMs, maxMs).build().schedule() to schedule it (library/src/main/java/com/evernote/android/job/JobManager.java)
  4. Add unit tests extending PlatformTest to verify job execution behavior (library/src/androidTest/java/com/evernote/android/job/PlatformTest.java)

Configure Job Scheduling Strategy for Different API Levels

  1. In your Application class onCreate(), call JobConfig.setApiSelection() to choose JobScheduler, GCM, or AlarmManager (library/src/main/java/com/evernote/android/job/JobConfig.java)
  2. Ensure AndroidManifest.xml includes required permissions for your chosen strategy (RECEIVE_BOOT_COMPLETED, SCHEDULE_EXACT_ALARM) (library/src/main/AndroidManifest.xml)
  3. For GCM support, check GcmAvailableHelper.isGcmNetworkManagerAvailable() and add Google Play Services dependency (library/src/main/java/com/evernote/android/job/GcmAvailableHelper.java)

Set Up Daily Recurring Jobs

  1. Create a class extending com.evernote.android.job.DailyJob and override onRunDailyJob() (library/src/main/java/com/evernote/android/job/DailyJob.java)
  2. Return your DailyJob instance from your JobCreator's create() method (demo/src/main/java/com/evernote/android/job/demo/DemoJobCreator.java)
  3. Schedule with JobManager.create().setTag("daily-tag").setPeriodic(TimeUnit.DAYS.toMillis(1)).build().schedule() (library/src/main/java/com/evernote/android/job/JobManager.java)

Handle Device Boot and Job Persistence

  1. JobBootReceiver is declared in AndroidManifest.xml and automatically restores jobs after boot (library/src/main/AndroidManifest.xml)
  2. Verify JobBootReceiver receives BOOT_COMPLETED broadcast and calls JobManager.instance().getAllJobRequests() (library/src/main/java/com/evernote/android/job/JobBootReceiver.java)
  3. Jobs are persisted in SharedPreferences or database; no manual persistence code needed (library/src/main/java/com/evernote/android/job/JobConfig.java)

🔧Why these technologies

  • JobScheduler API (Android 5.0+) — Native Android API offering battery-optimized job scheduling with strict execution constraints and doze mode awareness
  • GcmNetworkManager (Google Play Services) — Provides reliable job scheduling with network-aware scheduling for devices without Job

🪤Traps & gotchas

API level selection logic is implicit: JobManager automatically chooses JobScheduler (API 21+), GcmNetworkManager (API 14-20 with Google Play), or AlarmManager fallback. No explicit configuration needed, but behavior differs significantly — JobScheduler is more reliable but GCM requires Google Play Services APK. Manifest merger dependency: README notes that without Gradle manifest merger enabled, you must manually add permissions and services from library/src/main/AndroidManifest.xml. WorkManager opt-in complexity: Version 1.3.0+ internally uses WorkManager if enabled, but migration is incomplete — legacy code paths still exist, creating confusion. Exact alarm permission: Android 12+ (API 31) requires SCHEDULE_EXACT_ALARM permission for exact jobs; this is not auto-declared. GCM deprecation: GcmNetworkManager is deprecated; apps on modern Play Store may fail attestation if still using it.

🏗️Architecture

💡Concepts to learn

  • JobScheduler (Android API 21+) — android-job's primary backend for modern devices; understanding its constraints (batch window, doze mode restrictions) explains why the library exists to handle older APIs
  • GcmNetworkManager (deprecated) — One of three core backends this library abstracts; was necessary for reliable scheduling on Android 4.0-5.0 before JobScheduler existed, now deprecated but still in production apps
  • Alarm-based scheduling (AlarmManager fallback) — Lowest-level fallback implementation when GCM unavailable; requires WAKE_LOCK permission and is less efficient but guarantees execution even without Google Play Services
  • Doze Mode and App Standby — Android 6.0+ feature that aggressively restricts background execution; affects how jobs are scheduled and why JobScheduler's whitelisting mechanisms exist
  • Intent-based Service execution vs. direct Job scheduling — android-job must bridge AlarmManager (Intent-based) to modern Job APIs; understanding this impedance mismatch explains the abstraction layer's complexity
  • Manifest-declared vs. runtime-scheduled services — Library requires both static manifest declarations (services, receivers, permissions) and runtime JobRequest scheduling; mixing these is a common source of bugs in background work
  • Content Provider-based job persistence — android-job stores pending jobs in a private ContentProvider database so they survive process death and device reboot; crucial for reliability but adds complexity vs. in-memory queues
  • androidx/androidx — Contains WorkManager (the official replacement for android-job recommended in the README), part of Jetpack with modern background scheduling APIs
  • google/android-architecture-components — Provides architectural guidance and lifecycle-aware job scheduling primitives that modern Android apps should use instead of this library
  • jbarr21/RxSchedulers — Reactive approach to background task scheduling; shows alternative patterns for coordinating async work without the older JobManager abstraction
  • evernote/evernote-sdk-android — Sibling Evernote Android library that likely used android-job for background sync tasks; demonstrates real-world job scheduling usage
  • google/android-job-scheduler-demo — Official Android JobScheduler example showing the native API that android-job abstracted over; useful for understanding what the library wraps

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive unit tests for DemoJobCreator and DemoSyncJob

The demo app has DemoJobCreator.java and DemoSyncJob.java in demo/src/main/java/com/evernote/android/job/demo/, but there are no corresponding test files visible in the structure. Since this is a deprecated library, adding tests for the demo implementations would help new contributors understand how to properly implement JobCreator and Job subclasses, and serve as reference tests for migration guides to WorkManager.

  • [ ] Create demo/src/androidTest/java/com/evernote/android/job/demo/DemoJobCreatorTest.java with tests for job registration
  • [ ] Create demo/src/androidTest/java/com/evernote/android/job/demo/DemoSyncJobTest.java with tests for onRunJob() behavior and result handling
  • [ ] Add tests that verify DemoSyncEngine integration and database persistence in DemoSyncJob
  • [ ] Verify tests run with Robolectric (4.7.3 is already in dependencies)

Add GitHub Actions workflow for automated testing on PR submissions

The repo has .github/ISSUE_TEMPLATE.md and .github/PULL_REQUEST_TEMPLATE.md but no visible CI workflow files (.github/workflows/). Even for a deprecated library, automated testing on PRs prevents regressions. This would validate the build, run unit tests with Robolectric, and lint checks using the existing checkstyle.xml config in build-config/checkstyle/.

  • [ ] Create .github/workflows/test.yml that runs on push and pull_request events
  • [ ] Configure the workflow to build with ./gradlew build using gradle 7.4.2 (from updateWrapper task)
  • [ ] Add step to run ./gradlew check to execute checkstyle (build-config/checkstyle/checkstyle.xml) and unit tests
  • [ ] Add step to verify compileSdkVersion 31 and targetSdkVersion compatibility
  • [ ] Cache gradle dependencies to speed up builds

Add missing SCHEDULE_EXACT_ALARM permission documentation to README.md

The README.md snippet shows the file is cut off mid-sentence explaining the exact alarm permission for API 31+ ("When targeting API 31 and you still use this library..."). This critical permission requirement is incomplete. Complete the documentation with proper manifest configuration and usage notes.

  • [ ] Complete the truncated section in README.md about SCHEDULE_EXACT_ALARM permission for Android 12+
  • [ ] Add code snippet showing the required AndroidManifest.xml entry: <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
  • [ ] Document which JobScheduler APIs require this permission and provide the ProGuard configuration needed (library/proguard.cfg already exists)
  • [ ] Add migration warning section pointing developers to WorkManager with comparison of APIs and upgrade path

🌿Good first issues

  • Add comprehensive unit test coverage for alarm-based job retry logic in JobAlarmImpl — current test files are sparse and retry behavior during device sleep is under-tested (would require Robolectric time mocking)
  • Document WorkManager migration path with code examples — create MIGRATION.md showing how to convert existing Job subclasses and JobRequest scheduling calls to WorkManager equivalents (Tasks and Workers), since the README only mentions switching but provides no guidance
  • Add missing Javadoc for JobRequest.Builder configuration options — many builder methods (setRequiresCharging, setRequiresDeviceIdle, setRequiresNetworkType) lack documentation on actual behavior differences across JobScheduler/GCM/AlarmManager backends

Top contributors

Click to expand

📝Recent commits

Click to expand
  • adec0ae — Publish version 1.4.3 (vRallev)
  • 69775d8 — Fix incompatibilities for targeting API 31. (vRallev)
  • 25cf43c — Setup a working Maven publishing mechanism. (vRallev)
  • 4aae129 — Upgrade build tools to make the project compile. Publishing is broken for now. (vRallev)
  • d9cfc62 — Publish version 1.4.2 (vRallev)
  • 754db63 — Bump libraries to the latest version, this fixes a binary incompatibility with WorkManager, see #591 (vRallev)
  • 3437936 — Publish version 1.4.1 (vRallev)
  • 376b851 — Remove appcompat as dependency, which was accidentally added in 1.4.0. (vRallev)
  • 5ad493f — Deprecate the library (vRallev)
  • f1010e8 — Publish version 1.4.0 (vRallev)

🔒Security observations

  • High · Deprecated Library with No Maintenance — README.md, Multiple source files. The android-job library is explicitly marked as deprecated and no longer maintained. The README states 'This library is not maintained anymore and there will be no further releases except for very critical bug fixes.' This means security vulnerabilities discovered in the future will not be patched, and the library will not receive updates for new Android API changes or security requirements. Fix: Migrate to WorkManager, the official Google-recommended job scheduling library for Android, which is actively maintained and receives regular security updates.
  • High · Outdated Gradle Build Tool — build.gradle (classpath 'com.android.tools.build:gradle:7.1.3'). The project uses Android Gradle Plugin version 7.1.3, which is outdated. Current versions provide important security fixes and improvements. Using outdated build tools may expose the build process to known vulnerabilities. Fix: Update to the latest stable Android Gradle Plugin version (currently 8.x series). Review and apply latest security patches in the build toolchain.
  • High · Multiple Outdated Dependencies with Known Vulnerabilities — build.gradle (dependencies section). Several dependencies appear to be significantly outdated and likely contain known CVEs: mockito 3.12.4, robolectric 4.7.3, and gradle-maven-publish-plugin 0.18.0. These versions are from 2021-2022 and have not received updates for several years. Fix: Update all dependencies to their latest stable versions: mockito to 5.x+, robolectric to 4.10+, and gradle-maven-publish-plugin to 0.25.3 or later. Review dependency changelogs for security fixes.
  • Medium · Low Target SDK Version — build.gradle (minSdkVersion = 14). While compileSdkVersion is 31, the targetSdkVersion is also 31. However, minSdkVersion is set to 14 (released in 2013). Supporting such an old minimum SDK significantly expands the attack surface and limits the use of modern security APIs and best practices available in newer Android versions. Fix: Consider raising minSdkVersion to at least 21 (Android 5.0) to eliminate support for extremely outdated platforms. This allows use of modern security APIs like StrictMode and better memory protections.
  • Medium · Play Services Dependency Potentially Outdated — build.gradle (playServicesVersion = '17.0.0'). The Play Services version '17.0.0' is from early 2020 and may contain unpatched security vulnerabilities. GCM dependencies are particularly sensitive given their role in app communication. Fix: Update to the latest Play Services version (currently 23.x series). Review the changelog for security patches and ensure GCM/FCM migration if still using legacy services.
  • Medium · Missing Package Name Prefix in ProGuard Configuration — demo/proguard.cfg, library/proguard.cfg. The ProGuard configuration files (demo/proguard.cfg and library/proguard.cfg) are present but cannot be analyzed from the file listing. Misconfigured ProGuard rules could expose sensitive code from being properly obfuscated in release builds. Fix: Verify that ProGuard/R8 rules are properly configured to obfuscate all sensitive code. Ensure no sensitive strings or method names are exposed. Use R8 (modern replacement) if possible.
  • Low · Compiler Warnings Not Enforced as Errors — build.gradle (JavaCompile options). The build configuration enables lint warnings for unchecked and deprecation warnings but does not fail the build on warnings. This allows deprecated or potentially unsafe code to be compiled without breaking the build. Fix: Consider adding 'failOnWarning = true' or converting warnings to errors for unchecked and deprecation issues in critical components. At minimum, enforce warnings in CI/CD pipelines.
  • Low · No Static Security Analysis Tools Configured — build.gradle, build-. While the build-config includes checkstyle configuration, there is no evidence of OWASP Dependency-Check, FindBugs, SpotBugs, or other static security analysis tools in the build configuration. Fix: undefined

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · Evernote/android-job — RepoPilot