simplify PlayerActivity towards using the media item only

PiperOrigin-RevId: 305300409
This commit is contained in:
bachinger 2020-04-07 19:23:19 +01:00 committed by Oliver Woodman
parent c84ac809e4
commit 4e2a0f6032
10 changed files with 121 additions and 68 deletions

View File

@ -62,6 +62,7 @@ import com.google.android.exoplayer2.ui.PlayerView;
import com.google.android.exoplayer2.ui.spherical.SphericalGLSurfaceView;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.ErrorMessageProvider;
import com.google.android.exoplayer2.util.EventLogger;
import com.google.android.exoplayer2.util.Util;
@ -71,9 +72,7 @@ import java.net.CookieManager;
import java.net.CookiePolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** An activity that plays media using {@link SimpleExoPlayer}. */
public class PlayerActivity extends AppCompatActivity
@ -410,28 +409,29 @@ public class PlayerActivity extends AppCompatActivity
? ((Sample.PlaylistSample) intentAsSample).children
: new UriSample[] {(UriSample) intentAsSample};
boolean seenAdsTagUri = false;
List<MediaSource> mediaSources = new ArrayList<>();
Uri adTagUri = null;
for (UriSample sample : samples) {
seenAdsTagUri |= sample.adTagUri != null;
if (!Util.checkCleartextTrafficPermitted(sample.uri)) {
MediaItem mediaItem = sample.toMediaItem();
Assertions.checkNotNull(mediaItem.playbackProperties);
if (!Util.checkCleartextTrafficPermitted(mediaItem)) {
showToast(R.string.error_cleartext_not_permitted);
return Collections.emptyList();
}
if (Util.maybeRequestReadExternalStoragePermission(/* activity= */ this, sample.uri)
|| (sample.subtitleInfo != null
&& Util.maybeRequestReadExternalStoragePermission(
/* activity= */ this, sample.subtitleInfo.uri))) {
if (Util.maybeRequestReadExternalStoragePermission(/* activity= */ this, mediaItem)) {
// The player will be reinitialized if the permission is granted.
return Collections.emptyList();
}
MediaSource mediaSource = createLeafMediaSource(sample);
MediaSource mediaSource = createLeafMediaSource(mediaItem);
if (mediaSource != null) {
adTagUri = sample.adTagUri;
mediaSources.add(mediaSource);
}
}
if (seenAdsTagUri && mediaSources.size() == 1) {
Uri adTagUri = samples[0].adTagUri;
if (adTagUri == null) {
releaseAdsLoader();
} else if (mediaSources.size() == 1) {
if (!adTagUri.equals(loadedAdTagUri)) {
releaseAdsLoader();
loadedAdTagUri = adTagUri;
@ -442,72 +442,42 @@ public class PlayerActivity extends AppCompatActivity
} else {
showToast(R.string.ima_not_loaded);
}
} else if (seenAdsTagUri && mediaSources.size() > 1) {
} else if (mediaSources.size() > 1) {
showToast(R.string.unsupported_ads_in_concatenation);
releaseAdsLoader();
} else {
releaseAdsLoader();
}
return mediaSources;
}
@Nullable
private MediaSource createLeafMediaSource(UriSample parameters) {
MediaItem.Builder builder = new MediaItem.Builder().setSourceUri(parameters.uri);
builder.setMimeType(Sample.inferAdaptiveStreamMimeType(parameters.uri, parameters.extension));
private MediaSource createLeafMediaSource(MediaItem mediaItem) {
Assertions.checkNotNull(mediaItem.playbackProperties);
HttpDataSource.Factory drmDataSourceFactory = null;
if (parameters.drmInfo != null) {
if (mediaItem.playbackProperties.drmConfiguration != null) {
if (Util.SDK_INT < 18) {
showToast(R.string.error_drm_unsupported_before_api_18);
finish();
return null;
} else if (!MediaDrm.isCryptoSchemeSupported(parameters.drmInfo.drmScheme)) {
} else if (!MediaDrm.isCryptoSchemeSupported(
mediaItem.playbackProperties.drmConfiguration.uuid)) {
showToast(R.string.error_drm_unsupported_scheme);
finish();
return null;
}
builder
.setDrmLicenseUri(parameters.drmInfo.drmLicenseUrl)
.setDrmLicenseRequestHeaders(
createLicenseHeaders(parameters.drmInfo.drmKeyRequestProperties))
.setDrmUuid(parameters.drmInfo.drmScheme)
.setDrmMultiSession(parameters.drmInfo.drmMultiSession)
.setDrmSessionForClearTypes(Util.toList(parameters.drmInfo.drmSessionForClearTypes));
drmDataSourceFactory = ((DemoApplication) getApplication()).buildHttpDataSourceFactory();
}
if (parameters.subtitleInfo != null) {
builder.setSubtitles(
Collections.singletonList(
new MediaItem.Subtitle(
parameters.subtitleInfo.uri,
parameters.subtitleInfo.mimeType,
parameters.subtitleInfo.language,
C.SELECTION_FLAG_DEFAULT)));
}
DownloadRequest downloadRequest =
((DemoApplication) getApplication())
.getDownloadTracker()
.getDownloadRequest(parameters.uri);
.getDownloadRequest(mediaItem.playbackProperties.sourceUri);
if (downloadRequest != null) {
return DownloadHelper.createMediaSource(downloadRequest, dataSourceFactory);
}
return mediaSourceFactory
.setDrmHttpDataSourceFactory(drmDataSourceFactory)
.createMediaSource(builder.build());
}
@Nullable
private Map<String, String> createLicenseHeaders(@Nullable String[] drmKeyRequestProperties) {
if (drmKeyRequestProperties == null || drmKeyRequestProperties.length == 0) {
return null;
}
Map<String, String> headers = new HashMap<>();
for (int i = 0; i < drmKeyRequestProperties.length; i += 2) {
headers.put(drmKeyRequestProperties[i], drmKeyRequestProperties[i + 1]);
}
return headers;
.createMediaSource(mediaItem);
}
private void releasePlayer() {

View File

@ -34,11 +34,15 @@ import android.content.Intent;
import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.UUID;
/* package */ abstract class Sample {
@ -140,6 +144,35 @@ import java.util.UUID;
subtitleInfo.addToIntent(intent, extrasKeySuffix);
}
}
public MediaItem toMediaItem() {
MediaItem.Builder builder = new MediaItem.Builder().setSourceUri(uri);
builder.setMimeType(inferAdaptiveStreamMimeType(uri, extension));
if (drmInfo != null) {
Map<String, String> headers = new HashMap<>();
if (drmInfo.drmKeyRequestProperties != null) {
for (int i = 0; i < drmInfo.drmKeyRequestProperties.length; i += 2) {
headers.put(drmInfo.drmKeyRequestProperties[i], drmInfo.drmKeyRequestProperties[i + 1]);
}
}
builder
.setDrmLicenseUri(drmInfo.drmLicenseUrl)
.setDrmLicenseRequestHeaders(headers)
.setDrmUuid(drmInfo.drmScheme)
.setDrmMultiSession(drmInfo.drmMultiSession)
.setDrmSessionForClearTypes(Util.toList(drmInfo.drmSessionForClearTypes));
}
if (subtitleInfo != null) {
builder.setSubtitles(
Collections.singletonList(
new MediaItem.Subtitle(
subtitleInfo.uri,
subtitleInfo.mimeType,
subtitleInfo.language,
C.SELECTION_FLAG_DEFAULT)));
}
return builder.build();
}
}
public static final class PlaylistSample extends Sample {

View File

@ -314,7 +314,7 @@ public final class MediaItem {
/**
* Sets the optional tag for custom attributes. The tag for the media source which will be
* published in the {@link com.google.android.exoplayer2.Timeline} of the source as {@link
* published in the {@code com.google.android.exoplayer2.Timeline} of the source as {@code
* com.google.android.exoplayer2.Timeline.Window#tag}.
*
* <p>If a {@link PlaybackProperties#sourceUri} is set, the tag is used to create a {@link
@ -466,7 +466,7 @@ public final class MediaItem {
/**
* Optional tag for custom attributes. The tag for the media source which will be published in
* the {@link com.google.android.exoplayer2.Timeline} of the source as {@link
* the {@code com.google.android.exoplayer2.Timeline} of the source as {@code
* com.google.android.exoplayer2.Timeline.Window#tag}.
*/
@Nullable public final Object tag;

View File

@ -50,6 +50,7 @@ import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.upstream.DataSource;
import java.io.ByteArrayOutputStream;
@ -185,36 +186,67 @@ public final class Util {
}
for (Uri uri : uris) {
if (isLocalFileUri(uri)) {
if (activity.checkSelfPermission(permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
activity.requestPermissions(new String[] {permission.READ_EXTERNAL_STORAGE}, 0);
return true;
}
break;
return requestExternalStoragePermission(activity);
}
}
return false;
}
/**
* Returns whether it may be possible to load the given URIs based on the network security
* policy's cleartext traffic permissions.
* Checks whether it's necessary to request the {@link permission#READ_EXTERNAL_STORAGE}
* permission for the specified {@link MediaItem media items}, requesting the permission if
* necessary.
*
* @param uris A list of URIs that will be loaded.
* @return Whether it may be possible to load the given URIs.
* @param activity The host activity for checking and requesting the permission.
* @param mediaItems {@link MediaItem Media items}s that may require {@link
* permission#READ_EXTERNAL_STORAGE} to read.
* @return Whether a permission request was made.
*/
public static boolean checkCleartextTrafficPermitted(Uri... uris) {
public static boolean maybeRequestReadExternalStoragePermission(
Activity activity, MediaItem... mediaItems) {
if (Util.SDK_INT < 23) {
return false;
}
for (MediaItem mediaItem : mediaItems) {
if (mediaItem.playbackProperties == null) {
continue;
}
if (isLocalFileUri(mediaItem.playbackProperties.sourceUri)) {
return requestExternalStoragePermission(activity);
}
for (int i = 0; i < mediaItem.playbackProperties.subtitles.size(); i++) {
if (isLocalFileUri(mediaItem.playbackProperties.subtitles.get(i).uri)) {
return requestExternalStoragePermission(activity);
}
}
}
return false;
}
/**
* Returns whether it may be possible to load the URIs of the given media items based on the
* network security policy's cleartext traffic permissions.
*
* @param mediaItems A list of {@link MediaItem media items}.
* @return Whether it may be possible to load the URIs of the given media items.
*/
public static boolean checkCleartextTrafficPermitted(MediaItem... mediaItems) {
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(Assertions.checkNotNull(uri.getHost()))) {
// The security policy prevents cleartext traffic.
for (MediaItem mediaItem : mediaItems) {
if (mediaItem.playbackProperties == null) {
continue;
}
if (isTrafficRestricted(mediaItem.playbackProperties.sourceUri)) {
return false;
}
for (int i = 0; i < mediaItem.playbackProperties.subtitles.size(); i++) {
if (isTrafficRestricted(mediaItem.playbackProperties.subtitles.get(i).uri)) {
return false;
}
}
}
return true;
}
@ -2185,6 +2217,24 @@ public final class Util {
return replacedLanguages;
}
@RequiresApi(api = Build.VERSION_CODES.M)
private static boolean requestExternalStoragePermission(Activity activity) {
if (activity.checkSelfPermission(permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
activity.requestPermissions(
new String[] {permission.READ_EXTERNAL_STORAGE}, /* requestCode= */ 0);
return true;
}
return false;
}
@RequiresApi(api = Build.VERSION_CODES.N)
private static boolean isTrafficRestricted(Uri uri) {
return "http".equals(uri.getScheme())
&& !NetworkSecurityPolicy.getInstance()
.isCleartextTrafficPermitted(Assertions.checkNotNull(uri.getHost()));
}
private static String maybeReplaceGrandfatheredLanguageTags(String languageTag) {
for (int i = 0; i < isoGrandfatheredTagReplacements.length; i += 2) {
if (languageTag.startsWith(isoGrandfatheredTagReplacements[i])) {