diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 3323402192..78a7e7233b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,6 +1,6 @@ # Release notes # -### 2.11.5 (2020-06-03) ### +### 2.11.5 (2020-06-04) ### * Improve the smoothness of video playback immediately after starting, seeking or resuming a playback @@ -17,6 +17,9 @@ * Fix issue in `AudioTrackPositionTracker` that could cause negative positions to be reported at the start of playback and immediately after seeking ([#7456](https://github.com/google/ExoPlayer/issues/7456). +* Fix further cases where downloads would sometimes not resume after their + network requirements are met + ([#7453](https://github.com/google/ExoPlayer/issues/7453). * DASH: * Merge trick play adaptation sets (i.e., adaptation sets marked with `http://dashif.org/guidelines/trickmode`) into the same `TrackGroup` as diff --git a/library/core/src/main/java/com/google/android/exoplayer2/scheduler/Requirements.java b/library/core/src/main/java/com/google/android/exoplayer2/scheduler/Requirements.java index 8919a26720..f4183897eb 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/scheduler/Requirements.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/scheduler/Requirements.java @@ -129,11 +129,9 @@ public final class Requirements implements Parcelable { } ConnectivityManager connectivityManager = - (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo networkInfo = Assertions.checkNotNull(connectivityManager).getActiveNetworkInfo(); - if (networkInfo == null - || !networkInfo.isConnected() - || !isInternetConnectivityValidated(connectivityManager)) { + (ConnectivityManager) + Assertions.checkNotNull(context.getSystemService(Context.CONNECTIVITY_SERVICE)); + if (!isInternetConnectivityValidated(connectivityManager)) { return requirements & (NETWORK | NETWORK_UNMETERED); } @@ -156,23 +154,28 @@ public final class Requirements implements Parcelable { } private boolean isDeviceIdle(Context context) { - PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + PowerManager powerManager = + (PowerManager) Assertions.checkNotNull(context.getSystemService(Context.POWER_SERVICE)); return Util.SDK_INT >= 23 ? powerManager.isDeviceIdleMode() : Util.SDK_INT >= 20 ? !powerManager.isInteractive() : !powerManager.isScreenOn(); } private static boolean isInternetConnectivityValidated(ConnectivityManager connectivityManager) { - // It's possible to query NetworkCapabilities from API level 23, but RequirementsWatcher only - // fires an event to update its Requirements when NetworkCapabilities change from API level 24. - // Since Requirements won't be updated, we assume connectivity is validated on API level 23. + // It's possible to check NetworkCapabilities.NET_CAPABILITY_VALIDATED from API level 23, but + // RequirementsWatcher only fires an event to re-check the requirements when NetworkCapabilities + // change from API level 24. We use the legacy path for API level 23 here to keep in sync. if (Util.SDK_INT < 24) { - return true; + // Legacy path. + @Nullable NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); + return networkInfo != null && networkInfo.isConnected(); } - Network activeNetwork = connectivityManager.getActiveNetwork(); + + @Nullable Network activeNetwork = connectivityManager.getActiveNetwork(); if (activeNetwork == null) { return false; } + @Nullable NetworkCapabilities networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork); return networkCapabilities != null diff --git a/library/core/src/main/java/com/google/android/exoplayer2/scheduler/RequirementsWatcher.java b/library/core/src/main/java/com/google/android/exoplayer2/scheduler/RequirementsWatcher.java index f55978c28a..80015cf3a7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/scheduler/RequirementsWatcher.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/scheduler/RequirementsWatcher.java @@ -150,6 +150,23 @@ public final class RequirementsWatcher { } } + /** + * Re-checks the requirements if there are network requirements that are currently not met. + * + *

When we receive an event that implies newly established network connectivity, we re-check + * the requirements by calling {@link #checkRequirements()}. This check sometimes sees that there + * is still no active network, meaning that any network requirements will remain not met. By + * calling this method when we receive other events that imply continued network connectivity, we + * can detect that the requirements are met once an active network does exist. + */ + private void recheckNotMetNetworkRequirements() { + if ((notMetRequirements & (Requirements.NETWORK | Requirements.NETWORK_UNMETERED)) == 0) { + // No unmet network requirements to recheck. + return; + } + checkRequirements(); + } + private class DeviceStatusChangeReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { @@ -161,17 +178,25 @@ public final class RequirementsWatcher { @RequiresApi(24) private final class NetworkCallback extends ConnectivityManager.NetworkCallback { - boolean receivedCapabilitiesChange; - boolean networkValidated; + + private boolean receivedCapabilitiesChange; + private boolean networkValidated; @Override public void onAvailable(Network network) { - onNetworkCallback(); + postCheckRequirements(); } @Override public void onLost(Network network) { - onNetworkCallback(); + postCheckRequirements(); + } + + @Override + public void onBlockedStatusChanged(Network network, boolean blocked) { + if (!blocked) { + postRecheckNotMetNetworkRequirements(); + } } @Override @@ -181,11 +206,13 @@ public final class RequirementsWatcher { if (!receivedCapabilitiesChange || this.networkValidated != networkValidated) { receivedCapabilitiesChange = true; this.networkValidated = networkValidated; - onNetworkCallback(); + postCheckRequirements(); + } else if (networkValidated) { + postRecheckNotMetNetworkRequirements(); } } - private void onNetworkCallback() { + private void postCheckRequirements() { handler.post( () -> { if (networkCallback != null) { @@ -193,5 +220,14 @@ public final class RequirementsWatcher { } }); } + + private void postRecheckNotMetNetworkRequirements() { + handler.post( + () -> { + if (networkCallback != null) { + recheckNotMetNetworkRequirements(); + } + }); + } } }