From d3f258ecd86faf8f658eec961604b42fcf9896ea Mon Sep 17 00:00:00 2001 From: Hong Ngoc Nguyen Date: Mon, 12 Feb 2024 11:27:09 -0500 Subject: [PATCH] [APT-9577] Add DRM for downloads for offline usage : when remove a downloaded audio, release and remove the downloaded license and its download info --- .../armadillo/download/DownloadEngine.kt | 10 ++++- .../download/drm/DashDrmLicenseDownloader.kt | 12 ++++++ .../download/drm/DrmLicenseDownloader.kt | 5 +++ .../download/drm/OfflineDrmManager.kt | 38 +++++++++++++++++++ 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/Armadillo/src/main/java/com/scribd/armadillo/download/DownloadEngine.kt b/Armadillo/src/main/java/com/scribd/armadillo/download/DownloadEngine.kt index c2e9e67..6bea4cb 100644 --- a/Armadillo/src/main/java/com/scribd/armadillo/download/DownloadEngine.kt +++ b/Armadillo/src/main/java/com/scribd/armadillo/download/DownloadEngine.kt @@ -76,9 +76,15 @@ internal class ExoplayerDownloadEngine @Inject constructor( }) } - override fun removeDownload(audiobook: AudioPlayable) = downloadManager.removeDownload(audiobook.request.url) + override fun removeDownload(audiobook: AudioPlayable) { + downloadManager.removeDownload(audiobook.request.url) + offlineDrmManager.removeDownloadedDrmLicense(audiobook) + } - override fun removeAllDownloads() = downloadManager.removeAllDownloads() + override fun removeAllDownloads() { + downloadManager.removeAllDownloads() + offlineDrmManager.removeAllDownloadedDrmLicenses() + } override fun updateProgress() = downloadTracker.updateProgress() diff --git a/Armadillo/src/main/java/com/scribd/armadillo/download/drm/DashDrmLicenseDownloader.kt b/Armadillo/src/main/java/com/scribd/armadillo/download/drm/DashDrmLicenseDownloader.kt index 5b509e8..8794ed5 100644 --- a/Armadillo/src/main/java/com/scribd/armadillo/download/drm/DashDrmLicenseDownloader.kt +++ b/Armadillo/src/main/java/com/scribd/armadillo/download/drm/DashDrmLicenseDownloader.kt @@ -55,6 +55,18 @@ internal class DashDrmLicenseDownloader @Inject constructor(context: Context) : } } + override suspend fun releaseDrmLicense(drmDownload: DrmDownload) { + val offlineHelper = when (drmDownload.drmType) { + DrmType.WIDEVINE -> OfflineLicenseHelper.newWidevineInstance(drmDownload.licenseServer, drmDataSourceFactory, drmEventDispatcher) + } + try { + offlineHelper.releaseLicense(drmDownload.drmKeyId) + } catch (e: Exception) { + Log.e(DrmLicenseDownloader.TAG, "Failure to release downloaded DRM license", e) + throw DrmDownloadException(e) + } + } + private fun DefaultHttpDataSource.Factory.addCustomHeaders(customHeaders: Map) { customHeaders.takeIf { it.isNotEmpty() }?.let { headers -> setDefaultRequestProperties(headers) diff --git a/Armadillo/src/main/java/com/scribd/armadillo/download/drm/DrmLicenseDownloader.kt b/Armadillo/src/main/java/com/scribd/armadillo/download/drm/DrmLicenseDownloader.kt index fafeec0..60ab4b2 100644 --- a/Armadillo/src/main/java/com/scribd/armadillo/download/drm/DrmLicenseDownloader.kt +++ b/Armadillo/src/main/java/com/scribd/armadillo/download/drm/DrmLicenseDownloader.kt @@ -21,4 +21,9 @@ internal interface DrmLicenseDownloader { customRequestHeaders: Map, drmInfo: DrmInfo, ): DrmDownload + + /** + * Release a downloaded DRM license so it's no longer valid for usage. + */ + suspend fun releaseDrmLicense(drmDownload: DrmDownload) } \ No newline at end of file diff --git a/Armadillo/src/main/java/com/scribd/armadillo/download/drm/OfflineDrmManager.kt b/Armadillo/src/main/java/com/scribd/armadillo/download/drm/OfflineDrmManager.kt index c52babb..8456488 100644 --- a/Armadillo/src/main/java/com/scribd/armadillo/download/drm/OfflineDrmManager.kt +++ b/Armadillo/src/main/java/com/scribd/armadillo/download/drm/OfflineDrmManager.kt @@ -12,6 +12,7 @@ import com.scribd.armadillo.models.AudioPlayable import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.supervisorScope import javax.inject.Inject import javax.inject.Named import javax.inject.Singleton @@ -48,4 +49,41 @@ internal class OfflineDrmManager @Inject constructor( } } } + + fun removeDownloadedDrmLicense(audiobook: AudioPlayable) { + globalScope.launch(Dispatchers.IO) { + audiobook.request.drmInfo?.let { drmInfo -> + secureStorage.getDrmDownload(context, audiobook.request.url, drmInfo.drmType)?.let { drmDownload -> + // Remove the persisted download info immediately so audio playback would stop using the offline license + secureStorage.removeDrmDownload(context, audiobook.request.url, drmInfo.drmType) + + // Release the DRM license + when (val type = drmDownload.audioType) { + C.TYPE_DASH -> dashDrmLicenseDownloader + else -> throw DrmContentTypeUnsupportedException(type) + }.releaseDrmLicense(drmDownload) + } + } + } + } + + fun removeAllDownloadedDrmLicenses() { + globalScope.launch(Dispatchers.IO) { + // Make sure that a removal fails, it won't affect the removal of other licenses + supervisorScope { + secureStorage.getAllDrmDownloads(context).forEach { drmDownloadPair -> + launch { + // Remove the persisted download info immediately so audio playback would stop using the offline license + secureStorage.removeDrmDownload(context, drmDownloadPair.key) + + // Release the DRM license + when (val type = drmDownloadPair.value.audioType) { + C.TYPE_DASH -> dashDrmLicenseDownloader + else -> throw DrmContentTypeUnsupportedException(type) + }.releaseDrmLicense(drmDownloadPair.value) + } + } + } + } + } } \ No newline at end of file