diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/DownloadTracker.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/DownloadTracker.java index 8109263e55..b448dd40de 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/DownloadTracker.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/DownloadTracker.java @@ -16,10 +16,12 @@ package com.google.android.exoplayer2.demo; import static com.google.android.exoplayer2.util.Assertions.checkNotNull; +import static com.google.android.exoplayer2.util.Assertions.checkStateNotNull; import android.content.Context; import android.content.DialogInterface; import android.net.Uri; +import android.os.AsyncTask; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -170,6 +172,7 @@ public class DownloadTracker { private TrackSelectionDialog trackSelectionDialog; private MappedTrackInfo mappedTrackInfo; + private WidevineOfflineLicenseFetchTask widevineOfflineLicenseFetchTask; @Nullable private byte[] keySetId; public StartDownloadDialogHelper( @@ -185,6 +188,9 @@ public class DownloadTracker { if (trackSelectionDialog != null) { trackSelectionDialog.dismiss(); } + if (widevineOfflineLicenseFetchTask != null) { + widevineOfflineLicenseFetchTask.cancel(false); + } } // DownloadHelper.Callback implementation. @@ -192,59 +198,32 @@ public class DownloadTracker { @Override public void onPrepared(@NonNull DownloadHelper helper) { @Nullable Format format = getFirstFormatWithDrmInitData(helper); - if (format != null) { - if (Util.SDK_INT < 18) { - Toast.makeText(context, R.string.error_drm_unsupported_before_api_18, Toast.LENGTH_LONG) - .show(); - Log.e(TAG, "Downloading DRM protected content is not supported on API versions below 18"); - return; - } - // TODO(internal b/163107948): Support cases where DrmInitData are not in the manifest. - if (!hasSchemaData(format.drmInitData)) { - Toast.makeText(context, R.string.download_start_error_offline_license, Toast.LENGTH_LONG) - .show(); - Log.e( - TAG, - "Downloading content where DRM scheme data is not located in the manifest is not" - + " supported"); - return; - } - try { - // TODO(internal b/163107948): Download the license on another thread to keep the UI - // thread unblocked. - fetchOfflineLicense(format); - } catch (DrmSession.DrmSessionException e) { - Toast.makeText(context, R.string.download_start_error_offline_license, Toast.LENGTH_LONG) - .show(); - Log.e(TAG, "Failed to fetch offline DRM license", e); - return; - } - } - - if (helper.getPeriodCount() == 0) { - Log.d(TAG, "No periods found. Downloading entire stream."); - startDownload(); - downloadHelper.release(); + if (format == null) { + onDownloadPrepared(helper); return; } - mappedTrackInfo = downloadHelper.getMappedTrackInfo(/* periodIndex= */ 0); - if (!TrackSelectionDialog.willHaveContent(mappedTrackInfo)) { - Log.d(TAG, "No dialog content. Downloading entire stream."); - startDownload(); - downloadHelper.release(); + // The content is DRM protected. We need to acquire an offline license. + if (Util.SDK_INT < 18) { + Toast.makeText(context, R.string.error_drm_unsupported_before_api_18, Toast.LENGTH_LONG) + .show(); + Log.e(TAG, "Downloading DRM protected content is not supported on API versions below 18"); return; } - trackSelectionDialog = - TrackSelectionDialog.createForMappedTrackInfoAndParameters( - /* titleId= */ R.string.exo_download_description, - mappedTrackInfo, - trackSelectorParameters, - /* allowAdaptiveSelections =*/ false, - /* allowMultipleOverrides= */ true, - /* onClickListener= */ this, - /* onDismissListener= */ this); - trackSelectionDialog.show(fragmentManager, /* tag= */ null); + // TODO(internal b/163107948): Support cases where DrmInitData are not in the manifest. + if (!hasSchemaData(format.drmInitData)) { + Toast.makeText(context, R.string.download_start_error_offline_license, Toast.LENGTH_LONG) + .show(); + Log.e( + TAG, + "Downloading content where DRM scheme data is not located in the manifest is not" + + " supported"); + return; + } + widevineOfflineLicenseFetchTask = + new WidevineOfflineLicenseFetchTask( + format, mediaItem.playbackProperties.drmConfiguration.licenseUri, this, helper); + widevineOfflineLicenseFetchTask.execute(); } @Override @@ -292,6 +271,44 @@ public class DownloadTracker { // Internal methods. + private void onOfflineLicenseFetched(DownloadHelper helper, byte[] keySetId) { + this.keySetId = keySetId; + onDownloadPrepared(helper); + } + + private void onOfflineLicenseFetchedError(DrmSession.DrmSessionException e) { + Toast.makeText(context, R.string.download_start_error_offline_license, Toast.LENGTH_LONG) + .show(); + Log.e(TAG, "Failed to fetch offline DRM license", e); + } + + private void onDownloadPrepared(DownloadHelper helper) { + if (helper.getPeriodCount() == 0) { + Log.d(TAG, "No periods found. Downloading entire stream."); + startDownload(); + downloadHelper.release(); + return; + } + + mappedTrackInfo = downloadHelper.getMappedTrackInfo(/* periodIndex= */ 0); + if (!TrackSelectionDialog.willHaveContent(mappedTrackInfo)) { + Log.d(TAG, "No dialog content. Downloading entire stream."); + startDownload(); + downloadHelper.release(); + return; + } + trackSelectionDialog = + TrackSelectionDialog.createForMappedTrackInfoAndParameters( + /* titleId= */ R.string.exo_download_description, + mappedTrackInfo, + trackSelectorParameters, + /* allowAdaptiveSelections =*/ false, + /* allowMultipleOverrides= */ true, + /* onClickListener= */ this, + /* onDismissListener= */ this); + trackSelectionDialog.show(fragmentManager, /* tag= */ null); + } + private void startDownload() { startDownload(buildDownloadRequest()); } @@ -306,15 +323,54 @@ public class DownloadTracker { .getDownloadRequest(Util.getUtf8Bytes(checkNotNull(mediaItem.mediaMetadata.title))) .copyWithKeySetId(keySetId); } + } - @RequiresApi(18) - private void fetchOfflineLicense(Format format) throws DrmSession.DrmSessionException { + /** Downloads a Widevine offline license in a background thread. */ + @RequiresApi(18) + private final class WidevineOfflineLicenseFetchTask extends AsyncTask { + private final Format format; + private final Uri licenseUri; + private final StartDownloadDialogHelper dialogHelper; + private final DownloadHelper downloadHelper; + + @Nullable private byte[] keySetId; + @Nullable private DrmSession.DrmSessionException drmSessionException; + + public WidevineOfflineLicenseFetchTask( + Format format, + Uri licenseUri, + StartDownloadDialogHelper dialogHelper, + DownloadHelper downloadHelper) { + this.format = format; + this.licenseUri = licenseUri; + this.dialogHelper = dialogHelper; + this.downloadHelper = downloadHelper; + } + + @Override + protected Void doInBackground(Void... voids) { OfflineLicenseHelper offlineLicenseHelper = OfflineLicenseHelper.newWidevineInstance( - mediaItem.playbackProperties.drmConfiguration.licenseUri.toString(), + licenseUri.toString(), httpDataSourceFactory, new DrmSessionEventListener.EventDispatcher()); - keySetId = offlineLicenseHelper.downloadLicense(format); + try { + keySetId = offlineLicenseHelper.downloadLicense(format); + } catch (DrmSession.DrmSessionException e) { + drmSessionException = e; + } finally { + offlineLicenseHelper.release(); + } + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + if (drmSessionException != null) { + dialogHelper.onOfflineLicenseFetchedError(drmSessionException); + } else { + dialogHelper.onOfflineLicenseFetched(downloadHelper, checkStateNotNull(keySetId)); + } } }