Click here to jump to the project!
- About Me 🙂
- My Mentors 🙏
- About GSoC ☀️ and AnkiDroid ⭐
- Project Goals 🎯
- Project Results ✨
- Architecture ⚒️
- Pull Requests 🧑💻
- Highlights 💭
- Plan Changes 🔁
- Next Steps ➡️
Hi, I'm Eric! As of writing, I'm a Computer Science student at the University of Waterloo in Canada. Feel free to reach out!
Thanks to my mentors for guiding me, reviewing my code, and being super supportive for the entire summer!
Extra shoutout to the other maintainers of AnkiDroid, too. Even though they weren't formally my mentors, they also helped guide and support me, and for that I am eternally grateful.
- David Allison
- Brayan Oliveira / BrayanDSO
- Shridhar Goel
- Sanjay Sargam
- Mike Hardy
- lukstbit
- Anyone else I'm forgetting!
Learn more about GSoC here.
See AnkiDroid on GitHub!
You may have heard of Anki, one of the most popular spaced-repetition flashcards apps in the world. AnkiDroid is the official open-source Android mobile port of Anki, with over ten million downloads on Google Play. I personally have been using Anki and AnkiDroid for years to study for school, learn Chinese characters, etc.
See my original project proposal document.
For my GSoC project, I proposed adding review reminders to AnkiDroid, as the current notifications system is completely broken and has been for multiple years.
"Notifications have been broken for 5/6 years and are one of the most common complaints about our app on Google Play [...] They're one of our few issues which have a dedicated label"
~ David Allison, one of AnkiDroid's principal maintainers
Quoting from my proposal (with emojis added to indicate which features I completed):
In summary, my key goals are as follows:
- Be able to create deck-specific reminders which fire once per day ✅
- Be able to view reminders in a specific deck ✅
- Be able to view reminders app-wide on a single screen ✅
- Be able to receive notifications in a timely manner ✅
- Be able to edit the time a reminder is sent at ✅
- Be able to delete reminders ✅
- Be able to ask the user for notification permissions ✅
- Be able to create global, app-wide notifications ✅
If possible, I also plan to implement the following:
- Be able to view previews of cards in notifications ❎ (not met because, after a maintainer debate, we decided it was better off as an add-on feature rather than one that should be included in the vanilla app)
- Be able to create persistent notifications that have a defined start and end ✅ (met in a different way than originally planned: we decided creating two types of review reminders (single and persistent) was too confusing. Instead, I added two simple snooze buttons to the review reminder notifications)
- Be able to modify special options for notifications, such as including subdecks when counting cards for the card trigger threshold ✅ (this specific advanced option was removed for adding unnecessary complexity, but other advanced options were implemented)
For more details about how my project changed from the initial proposal, see Plan Changes.
Here's a demonstration of how the new review reminders feature allows you to schedule, view, edit, and delete review reminders:
Deleting a deck also deletes the corresponding review reminders:
When you receive reminder notifications, they look like this:
Clicking snooze dismisses the notification and causes it to come back after the selected time interval. Clicking on the notification opens the corresponding deck and allows you to begin reviewing.
Here are some images of the main UI screens:
I also created dialogs and screens for explaining to the user why AnkiDroid needs the notification permission:
There are multiple ways to access the review reminders screen to ensure new users don't get stuck looking for it:
I also added a few advanced review reminder configuration settings:
-
Count new cards / cards in learning / cards in review: For example, if a user only wants to get notifications when they have a lot of cards to review, but otherwise does not care if they have only new cards to learn, then they can un-check the "count new cards when checking card threshold" advanced option.
-
Only notify me if no reviews have been done today: If a user dislikes receiving notifications and only wants to receive them if they are about to forget a review, they can toggle this advanced setting on.
One thing I struggled with during this project was deprecating the old notifications system. Previous attempts at creating review reminders were still sitting around in the codebase in a broken state. I had to sieve through the code to figure out what parts were safe to keep and which parts had to be removed. Here's a mind map I created while mapping out which parts of the codebase were broken:
While I filed other PRs during the summer, the following are the ones which are directly related to the review reminders feature. As of writing, a few stragglers are still awaiting review: see Next Steps for more information. Key PRs that added new features are bolded!
- feat(reminders): entry points
- feat(reminders): developer option
- feat(reminders): ReviewRemindersDatabase and ReviewReminder
- style: improve docstrings
- refactor: prefs for entry points
- refactor: ReviewReminderScope
- refactor: remove granular snooze settings
- refactor: clean up ReviewReminderScope.DeckSpecific.getDeckName
- refactor: make DeckDropDownAdapter SubtitleListener cast safe
- refactor: delete bulk deletion, use separate prefs file
- feat(reminders): add ScheduleReminders DeckSpinner init method
- feat(reminders): RecyclerView XML
- feat(reminders): ReviewReminder schema migration
- feat(reminders): make ReviewReminder Parcelable
- refactor: prepare BootService for review reminders
- refactor: prepare AnkiDroidApp, widget, and day-rollover for review reminders
- feat(reminders): review reminders RecyclerView
- improvement: permission explanations
- refactor: prepare AnkiActivity for review reminders
- feat(reminders): handle deck deletion
- feat(reminders): AddEditReminderDialog
- refactor: delete ReminderService
- feat(reminders): create global scope helper
- refactor(reminders): create allDecksCounts
- feat(reminders): create notification channel
- feat(reminders): AlarmManagerService and NotificationService
- feat(reminders): set alarms from ScheduleReminders
- improvement: delete TiramisuPermissionsFragment and streamline PermissionsItem
- feat(reminders): threshold filters
- feat(reminders): only notify if no reviews
- feat(reminders): request notification permissions
Most of my work is located in the reviewreminders directory, services, or ui/windows/permissions.
One of the major highlights of this project for me was handling ReviewReminder schema migration: basically, making sure the app wouldn't crash if a future developer decided to change the fields of the ReviewReminder data class stored in user devices. There were many unanticipated things I coded which I didn't expect to implement back in May, but this was the biggest unanticipated feature of the bunch. Nonetheless, I'm very happy with the way I solved the problem, complete with unit tests, and I hope that it will help future developers work with the code I've written.
It took a lot of time to get the UI for the AddEditReminderDialog right, especially because I ran into multiple bugs with implementing the MaterialUI TimePicker, but I eventually figured it all out. I'm very happy with the final visual result.
I learned a lot about writing good documentation while working on this project. With all the back-and-forth involved with reviewing code in an open source project, I'm quite confident this is some of the highest quality code I've ever written in my life.
The project changed a bit from the initial plan as I worked on the code and discussed with my mentors regarding which features I should implement and which features were unnecessary.
- Criteria 9 was not met because, after a maintainer debate, we decided it was better off as an add-on feature rather than one that should be included in the vanilla app.
- Criteria 10 was met in a different way than originally planned: we decided creating two types of review reminders (single and persistent) was too confusing. Instead, I added two simple snooze buttons to the review reminder notifications. This feature changed a lot over the course of the summer. At various points in June and July, we were planning to have snooze settings for each individual reminder, an app-wide snooze setting...
- The UI for the main review reminder editing screen was simplified and unnecessary features like multi-select deletion were removed. The UI for the AddEditReminderDialog was greatly simplified and streamlined so that users can easily edit which deck a review reminder is associated with, move review reminders around, etc.
- Regarding Criteria 11: some of the advanced options, such as "Include cards from subdecks", were removed for being overly confusing. We decided to focus on providing clean defaults rather than allowing for infinite customizability.
- Instead of adding Preferences Datastore as a new import to store review reminders, we decided to use the raw Preferences system instead, avoiding the introduction of a new dependency.
- Snoozing was accomplished via AlarmManager instead of WorkManager as originally planned due to AlarmManager's scheduling behaviour being more predictable.
While I've fulfilled all of the things I set forth in my original project proposal, there's still a few things I've thought of over the course of this summer and which I still would like to add:
- Add a button in the toolbar of ScheduleReminders linking to the OS permissions screen
- Refactor ScheduleReminders to use a PermissionsActivity instead of SingleFragmentActivity to minimize the use of new Activities
- Clean up the strings and move them into the resource files to facilitate translation
- Set up a logging service to help with bug reports
- Write some instrumented tests
- Handle locale changes for notification channels to address this recently-opened issue
- Maybe create a "are you having trouble with notifications" page to help people who aren't receiving notifications troubleshoot what's going wrong.
And of course, some of my PRs are still awaiting being merged. Over the next few months, I hope to revise them and fully merge my changes into main, implement the above features, and patch any bugs that show up in my code during beta testing.
Overall, I'm super proud of what I've accomplished this summer. Looking forward to getting review reminders into a stable release and pushing it out to all of AnkiDroid's users! 🚀
If you're looking to learn more about me, connect with me on LinkedIn or check out my website. Have a great day!









