Skip to content

Cellular Data Usage: Download status fixes#4071

Open
bjtitus wants to merge 11 commits into
trunkfrom
bjtitus/cellular-download-status-fixes
Open

Cellular Data Usage: Download status fixes#4071
bjtitus wants to merge 11 commits into
trunkfrom
bjtitus/cellular-download-status-fixes

Conversation

@bjtitus

@bjtitus bjtitus commented Mar 14, 2026

Copy link
Copy Markdown
Contributor

Fixes cellular downloads by explicitly tracking when a user approves cellular download via the prompt, rather than inferring it from network state at download time.

Previously, the app inferred cellular approval by checking !isConnectedToUnexpensiveConnection() at download time. This was unreliable because:

  • Network state could change between when the user approved and when the download started
  • The check couldn't distinguish between "user approved cellular" vs "auto-download on cellular"

The theoretical pattern goes like this:

  1. User taps download while on WiFi, autoDownloadStatus = .notSpecified
  2. Network switches to cellular before performDownload runs
  3. !onWifi is now true, and status is .notSpecified (not .autoDownloaded)
  4. useCellularSession = true download uses cellular even though the user never approved it

NOTE This is a change in behavior and it may make sense for queued episodes to continue to download over cellular once the user has initiated the download.

To test

  • Begin a bunch of downloads on wifi manually
  • Switch to cellular while episodes are still downloading
  • Queued episodes should not begin downloading AFTER switching to cellular (this was the bug before where we had not prompted the user to use cellular but queued episodes would)

Checklist

  • I have considered if this change warrants user-facing release notes and have added them to CHANGELOG.md if necessary.
  • I have considered adding unit tests for my changes.
  • I have updated (or requested that someone edit) the spreadsheet to reflect any new or changed analytics.

Copilot AI review requested due to automatic review settings March 14, 2026 02:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a cellular-download TOCTOU issue by explicitly tracking whether the user approved a cellular download at queue time, and then using that persisted status (instead of runtime network checks) to choose the correct URLSession for the download.

Changes:

  • Extend NetworkUtils.downloadEpisodeRequested to return both “queue for later” and “explicit cellular approval” signals, and propagate that into DownloadManager.addToQueue.
  • Add AutoDownloadStatus.userApprovedCellular and update DownloadManager.performDownload session selection to rely on this status when the feature flag is enabled.
  • Add unit tests validating session selection behavior for the new status and regression coverage for the TOCTOU scenario.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
podcasts/PlaybackActionHelper.swift Records explicit cellular approval from the prompt and passes an appropriate autoDownloadStatus into the download queue.
podcasts/ListeningHistoryViewController+Table.swift Updates “Retry” flow to propagate explicit cellular approval into queued downloads.
podcasts/Extensions/NetworkUtils+Helpers.swift Updates download permission prompt helper to return (later, approvedCellular) and documents the behavior.
podcasts/DownloadsViewController+Table.swift Updates per-episode retry flow to pass .userApprovedCellular when the user confirms cellular.
podcasts/DownloadsViewController.swift Updates “Retry All Failed” flow to use the new prompt callback shape and propagate approval status.
podcasts/DownloadManager.swift Changes session selection logic to use .userApprovedCellular (feature-flagged) instead of inferring approval from current network state.
PocketCastsTests/Tests/Utilities/DownloadManagerCellularSessionTests.swift Adds tests validating session selection for .userApprovedCellular, .notSpecified, and .autoDownloaded.
Modules/DataModel/Sources/PocketCastsDataModel/Public/Enums.swift Adds the new AutoDownloadStatus.userApprovedCellular = 5 enum case.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread podcasts/DownloadManager.swift
Comment thread podcasts/DownloadManager.swift Outdated
Copilot AI review requested due to automatic review settings March 20, 2026 19:28
@bjtitus bjtitus force-pushed the bjtitus/cellular-download-status-fixes branch from 62e0036 to dce652f Compare March 20, 2026 19:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a cellular-download TOCTOU issue by explicitly tracking whether the user approved downloading over cellular at the time downloads are queued, rather than inferring approval from the network state at download start time.

Changes:

  • Adds a new AutoDownloadStatus.userApprovedCellular value and propagates it through multiple “download” entry points (single-episode actions and bulk downloads).
  • Updates DownloadManager session selection to use explicit approval (userApprovedCellular) when the cellularDownloadStatusFix feature flag is enabled.
  • Adds a new unit test suite validating session selection behavior and introduces a new feature flag to gate the change.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
podcasts/Podcasts/Podcast Page/PodcastViewController.swift Bulk “Download All” now forwards a userApprovedCellular signal into queueing.
podcasts/Podcasts/Podcast Page/EpisodeListSearchController.swift Bulk download confirmation now passes a cellular-approval boolean into the delegate call.
podcasts/PlaylistViewController.swift Bulk playlist download confirmation/queueing now passes a cellular-approval boolean and uses it to set autoDownloadStatus.
podcasts/PlaybackActionHelper.swift Single-episode download flows now receive explicit cellular approval from NetworkUtils and queue with the correct status.
podcasts/ListeningHistoryViewController+Table.swift Retry-download flow now records explicit cellular approval when queueing.
podcasts/Extensions/NetworkUtils+Helpers.swift Extends downloadEpisodeRequested callback to include an approvedCellular flag when the prompt is shown/accepted.
podcasts/DownloadsViewController+Table.swift Retry-download flow now records explicit cellular approval when queueing.
podcasts/DownloadsViewController.swift “Retry all failed” now queues with explicit cellular approval status when applicable.
podcasts/DownloadManager.swift Session selection logic updated to rely on explicit approval status under the feature flag; queued-startup now preserves stored status.
podcasts/Common Components/MultiSelect/MultiSelectHelper.swift Multi-select download flow now records whether the user approved cellular for the bulk action.
PocketCastsTests/Tests/Utilities/DownloadManagerCellularSessionTests.swift New tests validating session selection for various AutoDownloadStatus/settings combinations.
Modules/Utils/Sources/PocketCastsUtils/Feature Flags/FeatureFlag.swift Adds cellularDownloadStatusFix feature flag.
Modules/DataModel/Sources/PocketCastsDataModel/Public/Enums.swift Adds AutoDownloadStatus.userApprovedCellular = 5.

Comment thread podcasts/Podcasts/Podcast Page/EpisodeListSearchController.swift
Comment thread podcasts/PlaylistViewController.swift
Comment thread podcasts/DownloadManager.swift Outdated
@bjtitus bjtitus marked this pull request as ready for review March 20, 2026 19:34
@bjtitus bjtitus requested a review from a team as a code owner March 20, 2026 19:34
@bjtitus bjtitus requested review from SergioEstevao and removed request for a team March 20, 2026 19:34
@bjtitus bjtitus added this to the 8.9 milestone Mar 20, 2026
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 23, 2026 18:40
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Comment thread podcasts/Podcasts/Podcast Page/PodcastViewController.swift
Comment thread podcasts/DownloadManager.swift

@SergioEstevao SergioEstevao left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Working correctly.
:shipit:

Copilot AI review requested due to automatic review settings March 23, 2026 21:52
@dangermattic

Copy link
Copy Markdown
Collaborator
1 Warning
⚠️ View files have been modified, but no screenshot or video is included in the pull request. Consider adding some for clarity.

Generated by 🚫 Danger

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.

Comment thread podcasts/Common Components/MainEpisodeActionView.swift
Comment thread CHANGELOG.md Outdated
Comment thread podcasts/PlaybackActionHelper.swift
Comment thread PocketCastsTests/Tests/Utilities/DownloadManagerCellularSessionTests.swift Outdated
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 23, 2026 22:04
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.

Comment on lines 541 to +550
let tempFilePath = tempPathForEpisode(episode)
let mobileDataAllowed = autoDownloadStatus == .autoDownloaded ? Settings.autoDownloadMobileDataAllowed() : Settings.mobileDataAllowed()
let useCellularSession = (mobileDataAllowed || (!NetworkUtils.shared.isConnectedToUnexpensiveConnection() && autoDownloadStatus != .autoDownloaded)) // allow cellular downloads if not on WiFi and not auto downloaded, because it means the user said yes to a confirmation prompt
let useCellularSession: Bool
if FeatureFlag.cellularDownloadStatusFix.enabled {
// Allow cellular downloads if mobile data is allowed by settings, if the user explicitly approved cellular download at queue time, or for episodes downloaded by the player for streaming
useCellularSession = mobileDataAllowed || autoDownloadStatus == .userApprovedCellular || autoDownloadStatus == .playerDownloadedForStreaming
} else {
// allow cellular downloads if not on WiFi and not auto downloaded, because it means the user said yes to a confirmation prompt
useCellularSession = (mobileDataAllowed || (!NetworkUtils.shared.isConnectedToUnexpensiveConnection() && autoDownloadStatus != .autoDownloaded))
}

Copilot AI Mar 23, 2026

Copy link

Choose a reason for hiding this comment

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

With cellularDownloadStatusFix enabled, useCellularSession is now driven purely by mobileDataAllowed or autoDownloadStatus == .userApprovedCellular (plus streaming). Any UI flow that shows a “Not on Wi‑Fi” confirmation but still queues episodes with .notSpecified will now create a Wi‑Fi-only task that won’t run on cellular. For example, podcasts/New Detail/PlaylistDetailViewController+EditActions.swift still enqueues bulk downloads with .notSpecified even when the user explicitly confirms on cellular. Please update those call sites to pass .userApprovedCellular when the user confirms cellular download (and keep .notSpecified for Wi‑Fi / queue-for-later).

Copilot uses AI. Check for mistakes.
@pocketcasts pocketcasts modified the milestones: 8.9, 8.10 Mar 30, 2026
@pocketcasts

Copy link
Copy Markdown
Contributor

Version 8.9 has now entered code-freeze, so the milestone of this PR has been updated to 8.10.

@pocketcasts pocketcasts modified the milestones: 8.10, 8.11 Apr 14, 2026
@pocketcasts

Copy link
Copy Markdown
Contributor

Version 8.10 has now entered code-freeze, so the milestone of this PR has been updated to 8.11.

@pocketcasts pocketcasts modified the milestones: 8.11, 8.12 Apr 27, 2026
@pocketcasts

Copy link
Copy Markdown
Contributor

Version 8.11 has now entered code-freeze, so the milestone of this PR has been updated to 8.12.

@pocketcasts pocketcasts modified the milestones: 8.12, 8.13 May 11, 2026
@pocketcasts

Copy link
Copy Markdown
Contributor

Version 8.12 has now entered code-freeze, so the milestone of this PR has been updated to 8.13.

@pocketcasts pocketcasts modified the milestones: 8.13, 8.14 May 25, 2026
@pocketcasts

Copy link
Copy Markdown
Contributor

Version 8.13 has now entered code-freeze, so the milestone of this PR has been updated to 8.14.

@pocketcasts pocketcasts modified the milestones: 8.14, 8.15 Jun 8, 2026
@pocketcasts

Copy link
Copy Markdown
Contributor

Version 8.14 has now entered code-freeze, so the milestone of this PR has been updated to 8.15.

@kean kean modified the milestones: 8.15, Future Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants