Overview
AnkiDroid Companion is built with a modular architecture that integrates with the AnkiDroid API to provide flashcard study sessions through persistent notifications. The app uses Android’s WorkManager for background task scheduling and SharedPreferences for state management.Core Components
The application consists of five main components working together to deliver flashcard notifications:MainActivity
Location:MainActivity.kt:22
The main entry point of the application, responsible for:
- Initialization: Sets up notification channels and checks API availability
- Permission Management: Requests AnkiDroid API read/write permissions
- Deck Selection: Provides a UI for users to select their study deck
- Worker Scheduling: Initiates the periodic background worker
- Creates notification channel on app startup (
MainActivity.kt:32-43) - Validates AnkiDroid API availability (
MainActivity.kt:60-63) - Handles permission requests (
MainActivity.kt:97-115) - Populates deck spinner with available decks (
MainActivity.kt:117-145) - Triggers initial card notification on refresh (
MainActivity.kt:147-168)
AnkiDroidHelper
Location:AnkiDroidHelper.java:31
The core integration layer that communicates with AnkiDroid’s Content Provider API.
- API Access Management: Checks API availability and permissions
- Card Queries: Retrieves scheduled cards from AnkiDroid (
AnkiDroidHelper.java:190-271) - Review Submission: Submits user responses back to AnkiDroid (
AnkiDroidHelper.java:273-284) - State Persistence: Stores and retrieves current card state (
AnkiDroidHelper.java:151-187) - Deck Management: Maps deck names to IDs and handles deck lookups
Notifications
Location:Notifications.kt:15
Handles notification creation and display with custom views.
-
Dual Notification States:
- Active Card (
Notifications.kt:26-62): Shows question/answer with 4 response buttons - Deck Complete (
Notifications.kt:63-80): Congratulations message when no cards remain
- Active Card (
-
Custom Views:
- Collapsed view with question header
- Expanded view with question and answer
- Four action buttons (Again, Hard, Good, Easy)
-
HTML Stripping: Converts HTML card content to plain text (
Notifications.kt:28-40)
NotificationReceiver
Location:NotificationReceiver.kt:8
A BroadcastReceiver that handles user interactions with notification buttons.
NotificationReceiver.kt:22-47):
- Retrieves stored card state
- Submits review to AnkiDroid with selected ease
- Queries for next scheduled card
- Updates notification with next card or completion message
PeriodicWorker
Location:PeriodicWorker.kt:10
A background worker that checks for new cards every 8 hours.
MainActivity.kt:45-56):
PeriodicWorker.kt:23-54):
- Only runs if current stored state shows no active card (cardOrd = -1)
- Queries AnkiDroid for next scheduled card
- Shows notification if a new card is available
- Stays silent if no cards are due
Data Flow
Initial Card Load
Card Response Flow
Background Worker Flow
State Management
The app uses Android’s SharedPreferences for persistent storage across two databases:Deck Reference Database
Key:com.ichi2.anki.api.decks (AnkiDroidHelper.java:40)
Purpose: Maps deck names to deck IDs to handle deck renaming
State Database
Key:com.ichi2.anki.api.state (AnkiDroidHelper.java:41)
Purpose: Stores current card state as JSON
Stored Fields (AnkiDroidHelper.java:154-161):
deck_id: Currently selected decknote_id: Current card’s note IDcard_ord: Card ordinal numberstart_time: When the card was first displayed
Data Models
CardInfo
Location:CardInfo.java:7
Represents a flashcard with all necessary data for display and review.
StoredState
Location:StoredState.java:3
Minimal state representation for persistence.
Dependencies
Frombuild.gradle.kts:52-70:
The app uses WorkManager for reliable background execution and Compose for UI, targeting Android SDK 26+ (Android 8.0 Oreo).
Thread Safety
The app handles threading carefully:- Main Thread: UI updates, notification display
- Worker Thread: AnkiDroid API queries run in WorkManager’s background thread
- Handler: PeriodicWorker uses
Handler(Looper.getMainLooper())to post results back to main thread (PeriodicWorker.kt:11,15)
Notification Channel
Setup (MainActivity.kt:32-43):
- Channel ID:
channel_id - Importance: Default (makes sound, appears in notification tray)
- Persistence: Active card notifications are ongoing (
setOngoing(true)), completion notifications can be dismissed
Summary
The architecture follows a clear separation of concerns:- MainActivity: User interface and initialization
- AnkiDroidHelper: Business logic and API integration
- Notifications: Presentation layer for card display
- NotificationReceiver: User input handling
- PeriodicWorker: Automated card scheduling