diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 02f82c7a3d..ef5a1df134 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -5,6 +5,7 @@
* Add a flag to opt-in to automatic audio focus handling via
`SimpleExoPlayer.setAudioAttributes`.
* Distribute Cronet extension via jCenter.
+* Set compileSdkVersion and targetSdkVersion to 28.
* Add `AudioListener` for listening to changes in audio configuration during
playback ([#3994](https://github.com/google/ExoPlayer/issues/3994)).
* Improved seeking support:
diff --git a/constants.gradle b/constants.gradle
index 4511eb86df..8016afbf8b 100644
--- a/constants.gradle
+++ b/constants.gradle
@@ -20,9 +20,9 @@ project.ext {
// However, please note that the core media playback functionality provided
// by the library requires API level 16 or greater.
minSdkVersion = 14
- targetSdkVersion = 27
- compileSdkVersion = 27
- buildToolsVersion = '27.0.3'
+ targetSdkVersion = 28
+ compileSdkVersion = 28
+ buildToolsVersion = '28.0.2'
testSupportLibraryVersion = '0.5'
supportLibraryVersion = '27.1.1'
dexmakerVersion = '1.2'
diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java
index 64eea24cac..6e3b7ee3d2 100644
--- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java
+++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java
@@ -360,7 +360,11 @@ public class PlayerActivity extends Activity
finish();
return;
}
- if (Util.maybeRequestReadExternalStoragePermission(this, uris)) {
+ if (!Util.checkCleartextTrafficPermitted(uris)) {
+ showToast(R.string.error_cleartext_not_permitted);
+ return;
+ }
+ if (Util.maybeRequestReadExternalStoragePermission(/* activity= */ this, uris)) {
// The player will be reinitialized if the permission is granted.
return;
}
diff --git a/demos/main/src/main/res/values/strings.xml b/demos/main/src/main/res/values/strings.xml
index beca93cfbc..54dff74600 100644
--- a/demos/main/src/main/res/values/strings.xml
+++ b/demos/main/src/main/res/values/strings.xml
@@ -19,6 +19,8 @@
Unexpected intent action: %1$s
+ Cleartext traffic not permitted
+
Playback failed
Unrecognized ABR algorithm
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java
index ef5591c535..5e13adb7ca 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java
@@ -33,6 +33,7 @@ import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Parcel;
+import android.security.NetworkSecurityPolicy;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.telephony.TelephonyManager;
@@ -184,6 +185,29 @@ public final class Util {
return false;
}
+ /**
+ * Returns whether it may be possible to load the given URIs based on the network security
+ * policy's cleartext traffic permissions.
+ *
+ * @param uris A list of URIs that will be loaded.
+ * @return Whether it may be possible to load the given URIs.
+ */
+ @TargetApi(24)
+ public static boolean checkCleartextTrafficPermitted(Uri... uris) {
+ if (Util.SDK_INT < 24) {
+ // We assume cleartext traffic is permitted.
+ return true;
+ }
+ for (Uri uri : uris) {
+ if ("http".equals(uri.getScheme())
+ && !NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted(uri.getHost())) {
+ // The security policy prevents cleartext traffic.
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Returns true if the URI is a path to a local file or a reference to a local file.
*