Skip to content

Add support for periodically downloading puzzles in the background.#111

Merged
kebernet merged 1 commit intokebernet:masterfrom
jonzolla:background_download
Sep 4, 2017
Merged

Add support for periodically downloading puzzles in the background.#111
kebernet merged 1 commit intokebernet:masterfrom
jonzolla:background_download

Conversation

@jonzolla
Copy link
Contributor

This is implemented by using JobScheduler to periodically download puzzles that the user has selected. JobScheduler is only available on API version >=21, so this functionality is disabled for lower API versions.

Using the JobScheduler API allows us to easily provide options for downloading on wifi only, when charging, etc.

Currently just attempt to download every hour. There are more intelligent things we can do here, but this has been working well on my device.

The updated NYT authentication mechanism is supported by posting a notification requesting login when a background download fails instead of immediately launching the login activity.

A slight refactor of Downloaders was required to allow for downloading the most recent the most recent puzzle for each source instead of just the puzzle for the current (or specified) date. This is intended to work in concert with PR #88 which allows the NYT puzzles to be available before the puzzle date.

I'm not too familiar with Android development, and was having a hard time coming up with a way to unit test these changes. I'm open to adding some if you have some suggestions for how to do so.

BackgroundDownloadService.class.getName()));

builder.setPeriodic(TimeUnit.HOURS.toMillis(1))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would likely be better done at something like 07:00UTC. That generally means that the puzzles that update at Midnight pacific time will be there. Not a lot of reason to keep running all the DLs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did consider this, but the JobScheduler API doesn't support scheduling at a specific time of day (only periodically or after a given deadline) so scheduling the job consistently at 07:00UTC is non-trivial (the delay needs to change if the user changes time zones, DST, etc.). We'll also have to implement some handling of failed downloads, whereas now we just converge on the next hourly run.

If your main concern is device battery usage, I've been running this for the past few months and haven't seen Shortyz noticeable in my battery stats (obviously a pretty small sample size). My guess is JobScheduler batches pretty efficiently. There's also an option to download only while charging, which we could change to a default.

I also have a personal preference to make this work with PR #88 which would require also scheduling at 04:00UTC to get the NYT puzzle the night before. I could just hard code two daily runs to make this work for now if we go this route, so not a big deal.

Let me know how strongly you feel about this. I can spend some time figuring out a way to cut down the number of download attempts if you'd like.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turns out that this is a bit more complicated than planned. It's possible to listen for timezone (and it seems DST) changes on the user's device via the TIME_CHANGED and TIMEZONE_CHANGED intents and reschedule your job/alarm accordingly.

However, we're actually trying to set an alarm in a different time zone (12AM Pacific as you mentioned). Since not everyone changes DST at the same time (or at all, e.g. Arizona), we need to reschedule the job when the PDT<->PST transition happens to keep the alarm at the right time of day.

If we just ditch periodic jobs and reschedule after a successful completion, it might work alright since the consequences of a miss by an hour or so in either direction aren't too bad (deliver late a couple times a year, or schedule an extra job). We'd have to make this work with handling transient download failures though.

That said, the Downloaders class will already prevent re-downloading if the puzzle exists. I just updated the PR with a fix for a bug around notifications here (a notification still got posted even if all downloads were skipped).

Given that making this work for users in all time zones is as bit complex, and we already avoid unnecessary network access, would you be alright leaving this as is for now?

// user turns on the preference for the first time, and we want to ensure the UI is re-rendered
// when the exit the settings dialog.
private boolean checkBackgroundDownload() {
if (Build.VERSION.SDK_INT < 21) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This kind of thing can be abstracted into the AndroidVersionUtils class.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@kebernet
Copy link
Owner

BTW thanks for this. I have been going back and forth on a service for this, but using JobScheduler is the correct way, and, you know, fuck old versions.

I have a couple of nits picked, but for the most part this is solid.

@jonzolla
Copy link
Contributor Author

Thanks for the review! I should have some time to take care of these points this weekend.

It's definitely possible to backport this to older versions at some point. Evernote has a library that mostly abstracts this (evernote/android-job), but I figured it would be simpler to start with this for now.

@jonzolla jonzolla force-pushed the background_download branch from 6b506e1 to c3672f5 Compare July 24, 2017 01:04
This is implemented by using JobScheduler to periodically download
puzzles that the user has selected. JobScheduler is only available
on API version >=21, so  this functionality is disabled for lower
API versions.

Using the JobScheduler API allows us to easily
provide options for downloading on wifi only, when charging, etc.

Currently just attempt to download every hour. There are more
intelligent things we can do here, but this has been working well
on my device.

The updated NYT authentication mechanism is supported by posting a
notification requesting login when a background download fails
instead of immediately launching the login activity.

A slight refactor of Downloaders was required to allow for
downloading the most recent the most recent puzzle for each source
instead of just the puzzle for the current (or specified) date.
@jonzolla jonzolla force-pushed the background_download branch from c3672f5 to a418b0a Compare July 24, 2017 02:28
@kebernet kebernet merged commit c1ae575 into kebernet:master Sep 4, 2017
@jonzolla jonzolla deleted the background_download branch November 28, 2018 07:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants