Fix drm nullability warnings.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=213650027
This commit is contained in:
tonihei 2018-09-19 10:27:11 -07:00 committed by Oliver Woodman
parent 6323c1904f
commit b07eef6d44
10 changed files with 179 additions and 126 deletions

View File

@ -28,14 +28,19 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest; import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest;
import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest; import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.EventDispatcher; import com.google.android.exoplayer2.util.EventDispatcher;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.Util;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/** /**
* A {@link DrmSession} that supports playbacks using {@link ExoMediaDrm}. * A {@link DrmSession} that supports playbacks using {@link ExoMediaDrm}.
@ -84,7 +89,7 @@ import java.util.UUID;
private final ExoMediaDrm<T> mediaDrm; private final ExoMediaDrm<T> mediaDrm;
private final ProvisioningManager<T> provisioningManager; private final ProvisioningManager<T> provisioningManager;
private final @DefaultDrmSessionManager.Mode int mode; private final @DefaultDrmSessionManager.Mode int mode;
private final HashMap<String, String> optionalKeyRequestParameters; private final @Nullable HashMap<String, String> optionalKeyRequestParameters;
private final EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher; private final EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher;
private final int initialDrmRequestRetryCount; private final int initialDrmRequestRetryCount;
@ -96,13 +101,13 @@ import java.util.UUID;
private int openCount; private int openCount;
private HandlerThread requestHandlerThread; private HandlerThread requestHandlerThread;
private PostRequestHandler postRequestHandler; private PostRequestHandler postRequestHandler;
private T mediaCrypto; private @Nullable T mediaCrypto;
private DrmSessionException lastException; private @Nullable DrmSessionException lastException;
private byte[] sessionId; private byte @MonotonicNonNull [] sessionId;
private @Nullable byte[] offlineLicenseKeySetId; private byte @MonotonicNonNull [] offlineLicenseKeySetId;
private KeyRequest currentKeyRequest; private @Nullable KeyRequest currentKeyRequest;
private ProvisionRequest currentProvisionRequest; private @Nullable ProvisionRequest currentProvisionRequest;
/** /**
* Instantiates a new DRM session. * Instantiates a new DRM session.
@ -129,18 +134,25 @@ import java.util.UUID;
@Nullable List<SchemeData> schemeDatas, @Nullable List<SchemeData> schemeDatas,
@DefaultDrmSessionManager.Mode int mode, @DefaultDrmSessionManager.Mode int mode,
@Nullable byte[] offlineLicenseKeySetId, @Nullable byte[] offlineLicenseKeySetId,
HashMap<String, String> optionalKeyRequestParameters, @Nullable HashMap<String, String> optionalKeyRequestParameters,
MediaDrmCallback callback, MediaDrmCallback callback,
Looper playbackLooper, Looper playbackLooper,
EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher, EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher,
int initialDrmRequestRetryCount) { int initialDrmRequestRetryCount) {
if (mode == DefaultDrmSessionManager.MODE_QUERY
|| mode == DefaultDrmSessionManager.MODE_RELEASE) {
Assertions.checkNotNull(offlineLicenseKeySetId);
}
this.uuid = uuid; this.uuid = uuid;
this.provisioningManager = provisioningManager; this.provisioningManager = provisioningManager;
this.mediaDrm = mediaDrm; this.mediaDrm = mediaDrm;
this.mode = mode; this.mode = mode;
if (offlineLicenseKeySetId != null) {
this.offlineLicenseKeySetId = offlineLicenseKeySetId; this.offlineLicenseKeySetId = offlineLicenseKeySetId;
this.schemeDatas = this.schemeDatas = null;
offlineLicenseKeySetId == null ? Collections.unmodifiableList(schemeDatas) : null; } else {
this.schemeDatas = Collections.unmodifiableList(Assertions.checkNotNull(schemeDatas));
}
this.optionalKeyRequestParameters = optionalKeyRequestParameters; this.optionalKeyRequestParameters = optionalKeyRequestParameters;
this.callback = callback; this.callback = callback;
this.initialDrmRequestRetryCount = initialDrmRequestRetryCount; this.initialDrmRequestRetryCount = initialDrmRequestRetryCount;
@ -166,9 +178,9 @@ import java.util.UUID;
} }
} }
/** /** @return True if the session is closed and cleaned up, false otherwise. */
* @return True if the session is closed and cleaned up, false otherwise. // Assigning null to various non-null variables for clean-up. Class won't be used after release.
*/ @SuppressWarnings("assignment.type.incompatible")
public boolean release() { public boolean release() {
if (--openCount == 0) { if (--openCount == 0) {
state = STATE_RELEASED; state = STATE_RELEASED;
@ -245,22 +257,22 @@ import java.util.UUID;
} }
@Override @Override
public final DrmSessionException getError() { public final @Nullable DrmSessionException getError() {
return state == STATE_ERROR ? lastException : null; return state == STATE_ERROR ? lastException : null;
} }
@Override @Override
public final T getMediaCrypto() { public final @Nullable T getMediaCrypto() {
return mediaCrypto; return mediaCrypto;
} }
@Override @Override
public Map<String, String> queryKeyStatus() { public @Nullable Map<String, String> queryKeyStatus() {
return sessionId == null ? null : mediaDrm.queryKeyStatus(sessionId); return sessionId == null ? null : mediaDrm.queryKeyStatus(sessionId);
} }
@Override @Override
public byte[] getOfflineLicenseKeySetId() { public @Nullable byte[] getOfflineLicenseKeySetId() {
return offlineLicenseKeySetId; return offlineLicenseKeySetId;
} }
@ -268,10 +280,12 @@ import java.util.UUID;
/** /**
* Try to open a session, do provisioning if necessary. * Try to open a session, do provisioning if necessary.
*
* @param allowProvisioning if provisioning is allowed, set this to false when calling from * @param allowProvisioning if provisioning is allowed, set this to false when calling from
* processing provision response. * processing provision response.
* @return true on success, false otherwise. * @return true on success, false otherwise.
*/ */
@EnsuresNonNullIf(result = true, expression = "sessionId")
private boolean openInternal(boolean allowProvisioning) { private boolean openInternal(boolean allowProvisioning) {
if (isOpen()) { if (isOpen()) {
// Already opened // Already opened
@ -319,19 +333,20 @@ import java.util.UUID;
provisioningManager.onProvisionCompleted(); provisioningManager.onProvisionCompleted();
} }
@RequiresNonNull("sessionId")
private void doLicense(boolean allowRetry) { private void doLicense(boolean allowRetry) {
switch (mode) { switch (mode) {
case DefaultDrmSessionManager.MODE_PLAYBACK: case DefaultDrmSessionManager.MODE_PLAYBACK:
case DefaultDrmSessionManager.MODE_QUERY: case DefaultDrmSessionManager.MODE_QUERY:
if (offlineLicenseKeySetId == null) { if (offlineLicenseKeySetId == null) {
postKeyRequest(ExoMediaDrm.KEY_TYPE_STREAMING, allowRetry); postKeyRequest(sessionId, ExoMediaDrm.KEY_TYPE_STREAMING, allowRetry);
} else if (state == STATE_OPENED_WITH_KEYS || restoreKeys()) { } else if (state == STATE_OPENED_WITH_KEYS || restoreKeys()) {
long licenseDurationRemainingSec = getLicenseDurationRemainingSec(); long licenseDurationRemainingSec = getLicenseDurationRemainingSec();
if (mode == DefaultDrmSessionManager.MODE_PLAYBACK if (mode == DefaultDrmSessionManager.MODE_PLAYBACK
&& licenseDurationRemainingSec <= MAX_LICENSE_DURATION_TO_RENEW) { && licenseDurationRemainingSec <= MAX_LICENSE_DURATION_TO_RENEW) {
Log.d(TAG, "Offline license has expired or will expire soon. " Log.d(TAG, "Offline license has expired or will expire soon. "
+ "Remaining seconds: " + licenseDurationRemainingSec); + "Remaining seconds: " + licenseDurationRemainingSec);
postKeyRequest(ExoMediaDrm.KEY_TYPE_OFFLINE, allowRetry); postKeyRequest(sessionId, ExoMediaDrm.KEY_TYPE_OFFLINE, allowRetry);
} else if (licenseDurationRemainingSec <= 0) { } else if (licenseDurationRemainingSec <= 0) {
onError(new KeysExpiredException()); onError(new KeysExpiredException());
} else { } else {
@ -342,19 +357,20 @@ import java.util.UUID;
break; break;
case DefaultDrmSessionManager.MODE_DOWNLOAD: case DefaultDrmSessionManager.MODE_DOWNLOAD:
if (offlineLicenseKeySetId == null) { if (offlineLicenseKeySetId == null) {
postKeyRequest(ExoMediaDrm.KEY_TYPE_OFFLINE, allowRetry); postKeyRequest(sessionId, ExoMediaDrm.KEY_TYPE_OFFLINE, allowRetry);
} else { } else {
// Renew // Renew
if (restoreKeys()) { if (restoreKeys()) {
postKeyRequest(ExoMediaDrm.KEY_TYPE_OFFLINE, allowRetry); postKeyRequest(sessionId, ExoMediaDrm.KEY_TYPE_OFFLINE, allowRetry);
} }
} }
break; break;
case DefaultDrmSessionManager.MODE_RELEASE: case DefaultDrmSessionManager.MODE_RELEASE:
Assertions.checkNotNull(offlineLicenseKeySetId);
// It's not necessary to restore the key (and open a session to do that) before releasing it // It's not necessary to restore the key (and open a session to do that) before releasing it
// but this serves as a good sanity/fast-failure check. // but this serves as a good sanity/fast-failure check.
if (restoreKeys()) { if (restoreKeys()) {
postKeyRequest(ExoMediaDrm.KEY_TYPE_RELEASE, allowRetry); postKeyRequest(offlineLicenseKeySetId, ExoMediaDrm.KEY_TYPE_RELEASE, allowRetry);
} }
break; break;
default: default:
@ -362,6 +378,7 @@ import java.util.UUID;
} }
} }
@RequiresNonNull({"sessionId", "offlineLicenseKeySetId"})
private boolean restoreKeys() { private boolean restoreKeys() {
try { try {
mediaDrm.restoreKeys(sessionId, offlineLicenseKeySetId); mediaDrm.restoreKeys(sessionId, offlineLicenseKeySetId);
@ -377,12 +394,12 @@ import java.util.UUID;
if (!C.WIDEVINE_UUID.equals(uuid)) { if (!C.WIDEVINE_UUID.equals(uuid)) {
return Long.MAX_VALUE; return Long.MAX_VALUE;
} }
Pair<Long, Long> pair = WidevineUtil.getLicenseDurationRemainingSec(this); Pair<Long, Long> pair =
Assertions.checkNotNull(WidevineUtil.getLicenseDurationRemainingSec(this));
return Math.min(pair.first, pair.second); return Math.min(pair.first, pair.second);
} }
private void postKeyRequest(int type, boolean allowRetry) { private void postKeyRequest(byte[] scope, int type, boolean allowRetry) {
byte[] scope = type == ExoMediaDrm.KEY_TYPE_RELEASE ? offlineLicenseKeySetId : sessionId;
try { try {
currentKeyRequest = currentKeyRequest =
mediaDrm.getKeyRequest(scope, schemeDatas, type, optionalKeyRequestParameters); mediaDrm.getKeyRequest(scope, schemeDatas, type, optionalKeyRequestParameters);
@ -407,7 +424,7 @@ import java.util.UUID;
try { try {
byte[] responseData = (byte[]) response; byte[] responseData = (byte[]) response;
if (mode == DefaultDrmSessionManager.MODE_RELEASE) { if (mode == DefaultDrmSessionManager.MODE_RELEASE) {
mediaDrm.provideKeyResponse(offlineLicenseKeySetId, responseData); mediaDrm.provideKeyResponse(Util.castNonNull(offlineLicenseKeySetId), responseData);
eventDispatcher.dispatch(DefaultDrmSessionEventListener::onDrmKeysRestored); eventDispatcher.dispatch(DefaultDrmSessionEventListener::onDrmKeysRestored);
} else { } else {
byte[] keySetId = mediaDrm.provideKeyResponse(sessionId, responseData); byte[] keySetId = mediaDrm.provideKeyResponse(sessionId, responseData);
@ -447,6 +464,8 @@ import java.util.UUID;
} }
} }
@EnsuresNonNullIf(result = true, expression = "sessionId")
@SuppressWarnings("contracts.conditional.postcondition.not.satisfied")
private boolean isOpen() { private boolean isOpen() {
return state == STATE_OPENED || state == STATE_OPENED_WITH_KEYS; return state == STATE_OPENED || state == STATE_OPENED_WITH_KEYS;
} }
@ -461,8 +480,9 @@ import java.util.UUID;
} }
@Override @Override
@SuppressWarnings("unchecked")
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
Pair<?, ?> requestAndResponse = (Pair<?, ?>) msg.obj; Pair<Object, Object> requestAndResponse = (Pair<Object, Object>) msg.obj;
Object request = requestAndResponse.first; Object request = requestAndResponse.first;
Object response = requestAndResponse.second; Object response = requestAndResponse.second;
switch (msg.what) { switch (msg.what) {

View File

@ -21,7 +21,7 @@ import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
import android.support.annotation.NonNull; import android.support.annotation.Nullable;
import android.text.TextUtils; import android.text.TextUtils;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.drm.DefaultDrmSession.ProvisioningManager; import com.google.android.exoplayer2.drm.DefaultDrmSession.ProvisioningManager;
@ -94,7 +94,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
private final UUID uuid; private final UUID uuid;
private final ExoMediaDrm<T> mediaDrm; private final ExoMediaDrm<T> mediaDrm;
private final MediaDrmCallback callback; private final MediaDrmCallback callback;
private final HashMap<String, String> optionalKeyRequestParameters; private final @Nullable HashMap<String, String> optionalKeyRequestParameters;
private final EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher; private final EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher;
private final boolean multiSession; private final boolean multiSession;
private final int initialDrmRequestRetryCount; private final int initialDrmRequestRetryCount;
@ -102,11 +102,11 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
private final List<DefaultDrmSession<T>> sessions; private final List<DefaultDrmSession<T>> sessions;
private final List<DefaultDrmSession<T>> provisioningSessions; private final List<DefaultDrmSession<T>> provisioningSessions;
private Looper playbackLooper; private @Nullable Looper playbackLooper;
private int mode; private int mode;
private byte[] offlineLicenseKeySetId; private @Nullable byte[] offlineLicenseKeySetId;
/* package */ volatile MediaDrmHandler mediaDrmHandler; /* package */ volatile @Nullable MediaDrmHandler mediaDrmHandler;
/** /**
* @deprecated Use {@link #newWidevineInstance(MediaDrmCallback, HashMap)} and {@link * @deprecated Use {@link #newWidevineInstance(MediaDrmCallback, HashMap)} and {@link
@ -115,9 +115,9 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
@Deprecated @Deprecated
public static DefaultDrmSessionManager<FrameworkMediaCrypto> newWidevineInstance( public static DefaultDrmSessionManager<FrameworkMediaCrypto> newWidevineInstance(
MediaDrmCallback callback, MediaDrmCallback callback,
HashMap<String, String> optionalKeyRequestParameters, @Nullable HashMap<String, String> optionalKeyRequestParameters,
Handler eventHandler, @Nullable Handler eventHandler,
DefaultDrmSessionEventListener eventListener) @Nullable DefaultDrmSessionEventListener eventListener)
throws UnsupportedDrmException { throws UnsupportedDrmException {
DefaultDrmSessionManager<FrameworkMediaCrypto> drmSessionManager = DefaultDrmSessionManager<FrameworkMediaCrypto> drmSessionManager =
newWidevineInstance(callback, optionalKeyRequestParameters); newWidevineInstance(callback, optionalKeyRequestParameters);
@ -136,7 +136,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
* @throws UnsupportedDrmException If the specified DRM scheme is not supported. * @throws UnsupportedDrmException If the specified DRM scheme is not supported.
*/ */
public static DefaultDrmSessionManager<FrameworkMediaCrypto> newWidevineInstance( public static DefaultDrmSessionManager<FrameworkMediaCrypto> newWidevineInstance(
MediaDrmCallback callback, HashMap<String, String> optionalKeyRequestParameters) MediaDrmCallback callback, @Nullable HashMap<String, String> optionalKeyRequestParameters)
throws UnsupportedDrmException { throws UnsupportedDrmException {
return newFrameworkInstance(C.WIDEVINE_UUID, callback, optionalKeyRequestParameters); return newFrameworkInstance(C.WIDEVINE_UUID, callback, optionalKeyRequestParameters);
} }
@ -148,9 +148,9 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
@Deprecated @Deprecated
public static DefaultDrmSessionManager<FrameworkMediaCrypto> newPlayReadyInstance( public static DefaultDrmSessionManager<FrameworkMediaCrypto> newPlayReadyInstance(
MediaDrmCallback callback, MediaDrmCallback callback,
String customData, @Nullable String customData,
Handler eventHandler, @Nullable Handler eventHandler,
DefaultDrmSessionEventListener eventListener) @Nullable DefaultDrmSessionEventListener eventListener)
throws UnsupportedDrmException { throws UnsupportedDrmException {
DefaultDrmSessionManager<FrameworkMediaCrypto> drmSessionManager = DefaultDrmSessionManager<FrameworkMediaCrypto> drmSessionManager =
newPlayReadyInstance(callback, customData); newPlayReadyInstance(callback, customData);
@ -171,7 +171,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
* @throws UnsupportedDrmException If the specified DRM scheme is not supported. * @throws UnsupportedDrmException If the specified DRM scheme is not supported.
*/ */
public static DefaultDrmSessionManager<FrameworkMediaCrypto> newPlayReadyInstance( public static DefaultDrmSessionManager<FrameworkMediaCrypto> newPlayReadyInstance(
MediaDrmCallback callback, String customData) throws UnsupportedDrmException { MediaDrmCallback callback, @Nullable String customData) throws UnsupportedDrmException {
HashMap<String, String> optionalKeyRequestParameters; HashMap<String, String> optionalKeyRequestParameters;
if (!TextUtils.isEmpty(customData)) { if (!TextUtils.isEmpty(customData)) {
optionalKeyRequestParameters = new HashMap<>(); optionalKeyRequestParameters = new HashMap<>();
@ -190,9 +190,9 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
public static DefaultDrmSessionManager<FrameworkMediaCrypto> newFrameworkInstance( public static DefaultDrmSessionManager<FrameworkMediaCrypto> newFrameworkInstance(
UUID uuid, UUID uuid,
MediaDrmCallback callback, MediaDrmCallback callback,
HashMap<String, String> optionalKeyRequestParameters, @Nullable HashMap<String, String> optionalKeyRequestParameters,
Handler eventHandler, @Nullable Handler eventHandler,
DefaultDrmSessionEventListener eventListener) @Nullable DefaultDrmSessionEventListener eventListener)
throws UnsupportedDrmException { throws UnsupportedDrmException {
DefaultDrmSessionManager<FrameworkMediaCrypto> drmSessionManager = DefaultDrmSessionManager<FrameworkMediaCrypto> drmSessionManager =
newFrameworkInstance(uuid, callback, optionalKeyRequestParameters); newFrameworkInstance(uuid, callback, optionalKeyRequestParameters);
@ -212,7 +212,9 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
* @throws UnsupportedDrmException If the specified DRM scheme is not supported. * @throws UnsupportedDrmException If the specified DRM scheme is not supported.
*/ */
public static DefaultDrmSessionManager<FrameworkMediaCrypto> newFrameworkInstance( public static DefaultDrmSessionManager<FrameworkMediaCrypto> newFrameworkInstance(
UUID uuid, MediaDrmCallback callback, HashMap<String, String> optionalKeyRequestParameters) UUID uuid,
MediaDrmCallback callback,
@Nullable HashMap<String, String> optionalKeyRequestParameters)
throws UnsupportedDrmException { throws UnsupportedDrmException {
return new DefaultDrmSessionManager<>( return new DefaultDrmSessionManager<>(
uuid, uuid,
@ -228,13 +230,14 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
* and {@link #addListener(Handler, DefaultDrmSessionEventListener)}. * and {@link #addListener(Handler, DefaultDrmSessionEventListener)}.
*/ */
@Deprecated @Deprecated
@SuppressWarnings("method.invocation.invalid")
public DefaultDrmSessionManager( public DefaultDrmSessionManager(
UUID uuid, UUID uuid,
ExoMediaDrm<T> mediaDrm, ExoMediaDrm<T> mediaDrm,
MediaDrmCallback callback, MediaDrmCallback callback,
HashMap<String, String> optionalKeyRequestParameters, @Nullable HashMap<String, String> optionalKeyRequestParameters,
Handler eventHandler, @Nullable Handler eventHandler,
DefaultDrmSessionEventListener eventListener) { @Nullable DefaultDrmSessionEventListener eventListener) {
this(uuid, mediaDrm, callback, optionalKeyRequestParameters); this(uuid, mediaDrm, callback, optionalKeyRequestParameters);
if (eventHandler != null && eventListener != null) { if (eventHandler != null && eventListener != null) {
addListener(eventHandler, eventListener); addListener(eventHandler, eventListener);
@ -252,7 +255,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
UUID uuid, UUID uuid,
ExoMediaDrm<T> mediaDrm, ExoMediaDrm<T> mediaDrm,
MediaDrmCallback callback, MediaDrmCallback callback,
HashMap<String, String> optionalKeyRequestParameters) { @Nullable HashMap<String, String> optionalKeyRequestParameters) {
this( this(
uuid, uuid,
mediaDrm, mediaDrm,
@ -267,13 +270,14 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
* boolean)} and {@link #addListener(Handler, DefaultDrmSessionEventListener)}. * boolean)} and {@link #addListener(Handler, DefaultDrmSessionEventListener)}.
*/ */
@Deprecated @Deprecated
@SuppressWarnings("method.invocation.invalid")
public DefaultDrmSessionManager( public DefaultDrmSessionManager(
UUID uuid, UUID uuid,
ExoMediaDrm<T> mediaDrm, ExoMediaDrm<T> mediaDrm,
MediaDrmCallback callback, MediaDrmCallback callback,
HashMap<String, String> optionalKeyRequestParameters, @Nullable HashMap<String, String> optionalKeyRequestParameters,
Handler eventHandler, @Nullable Handler eventHandler,
DefaultDrmSessionEventListener eventListener, @Nullable DefaultDrmSessionEventListener eventListener,
boolean multiSession) { boolean multiSession) {
this(uuid, mediaDrm, callback, optionalKeyRequestParameters, multiSession); this(uuid, mediaDrm, callback, optionalKeyRequestParameters, multiSession);
if (eventHandler != null && eventListener != null) { if (eventHandler != null && eventListener != null) {
@ -294,7 +298,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
UUID uuid, UUID uuid,
ExoMediaDrm<T> mediaDrm, ExoMediaDrm<T> mediaDrm,
MediaDrmCallback callback, MediaDrmCallback callback,
HashMap<String, String> optionalKeyRequestParameters, @Nullable HashMap<String, String> optionalKeyRequestParameters,
boolean multiSession) { boolean multiSession) {
this( this(
uuid, uuid,
@ -310,13 +314,14 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
* boolean, int)} and {@link #addListener(Handler, DefaultDrmSessionEventListener)}. * boolean, int)} and {@link #addListener(Handler, DefaultDrmSessionEventListener)}.
*/ */
@Deprecated @Deprecated
@SuppressWarnings("method.invocation.invalid")
public DefaultDrmSessionManager( public DefaultDrmSessionManager(
UUID uuid, UUID uuid,
ExoMediaDrm<T> mediaDrm, ExoMediaDrm<T> mediaDrm,
MediaDrmCallback callback, MediaDrmCallback callback,
HashMap<String, String> optionalKeyRequestParameters, @Nullable HashMap<String, String> optionalKeyRequestParameters,
Handler eventHandler, @Nullable Handler eventHandler,
DefaultDrmSessionEventListener eventListener, @Nullable DefaultDrmSessionEventListener eventListener,
boolean multiSession, boolean multiSession,
int initialDrmRequestRetryCount) { int initialDrmRequestRetryCount) {
this( this(
@ -346,7 +351,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
UUID uuid, UUID uuid,
ExoMediaDrm<T> mediaDrm, ExoMediaDrm<T> mediaDrm,
MediaDrmCallback callback, MediaDrmCallback callback,
HashMap<String, String> optionalKeyRequestParameters, @Nullable HashMap<String, String> optionalKeyRequestParameters,
boolean multiSession, boolean multiSession,
int initialDrmRequestRetryCount) { int initialDrmRequestRetryCount) {
Assertions.checkNotNull(uuid); Assertions.checkNotNull(uuid);
@ -443,6 +448,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
* required. * required.
* *
* <p>{@code mode} must be one of these: * <p>{@code mode} must be one of these:
*
* <ul> * <ul>
* <li>{@link #MODE_PLAYBACK}: If {@code offlineLicenseKeySetId} is null, a streaming license is * <li>{@link #MODE_PLAYBACK}: If {@code offlineLicenseKeySetId} is null, a streaming license is
* requested otherwise the offline license is restored. * requested otherwise the offline license is restored.
@ -450,14 +456,14 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
* is restored. * is restored.
* <li>{@link #MODE_DOWNLOAD}: If {@code offlineLicenseKeySetId} is null, an offline license is * <li>{@link #MODE_DOWNLOAD}: If {@code offlineLicenseKeySetId} is null, an offline license is
* requested otherwise the offline license is renewed. * requested otherwise the offline license is renewed.
* <li>{@link #MODE_RELEASE}: {@code offlineLicenseKeySetId} can not be null. The offline license * <li>{@link #MODE_RELEASE}: {@code offlineLicenseKeySetId} can not be null. The offline
* is released. * license is released.
* </ul> * </ul>
* *
* @param mode The mode to be set. * @param mode The mode to be set.
* @param offlineLicenseKeySetId The key set id of the license to be used with the given mode. * @param offlineLicenseKeySetId The key set id of the license to be used with the given mode.
*/ */
public void setMode(@Mode int mode, byte[] offlineLicenseKeySetId) { public void setMode(@Mode int mode, @Nullable byte[] offlineLicenseKeySetId) {
Assertions.checkState(sessions.isEmpty()); Assertions.checkState(sessions.isEmpty());
if (mode == MODE_QUERY || mode == MODE_RELEASE) { if (mode == MODE_QUERY || mode == MODE_RELEASE) {
Assertions.checkNotNull(offlineLicenseKeySetId); Assertions.checkNotNull(offlineLicenseKeySetId);
@ -469,7 +475,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
// DrmSessionManager implementation. // DrmSessionManager implementation.
@Override @Override
public boolean canAcquireSession(@NonNull DrmInitData drmInitData) { public boolean canAcquireSession(DrmInitData drmInitData) {
if (offlineLicenseKeySetId != null) { if (offlineLicenseKeySetId != null) {
// An offline license can be restored so a session can always be acquired. // An offline license can be restored so a session can always be acquired.
return true; return true;
@ -650,10 +656,14 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
private class MediaDrmEventListener implements OnEventListener<T> { private class MediaDrmEventListener implements OnEventListener<T> {
@Override @Override
public void onEvent(ExoMediaDrm<? extends T> md, byte[] sessionId, int event, int extra, public void onEvent(
byte[] data) { ExoMediaDrm<? extends T> md,
byte[] sessionId,
int event,
int extra,
@Nullable byte[] data) {
if (mode == DefaultDrmSessionManager.MODE_PLAYBACK) { if (mode == DefaultDrmSessionManager.MODE_PLAYBACK) {
mediaDrmHandler.obtainMessage(event, sessionId).sendToTarget(); Assertions.checkNotNull(mediaDrmHandler).obtainMessage(event, sessionId).sendToTarget();
} }
} }

View File

@ -85,10 +85,8 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
// Lazily initialized hashcode. // Lazily initialized hashcode.
private int hashCode; private int hashCode;
/** /** The protection scheme type, or null if not applicable or unknown. */
* The protection scheme type, or null if not applicable or unknown. public final @Nullable String schemeType;
*/
@Nullable public final String schemeType;
/** /**
* Number of {@link SchemeData}s. * Number of {@link SchemeData}s.
@ -106,7 +104,7 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
* @param schemeType See {@link #schemeType}. * @param schemeType See {@link #schemeType}.
* @param schemeDatas Scheme initialization data for possibly multiple DRM schemes. * @param schemeDatas Scheme initialization data for possibly multiple DRM schemes.
*/ */
public DrmInitData(String schemeType, List<SchemeData> schemeDatas) { public DrmInitData(@Nullable String schemeType, List<SchemeData> schemeDatas) {
this(schemeType, false, schemeDatas.toArray(new SchemeData[schemeDatas.size()])); this(schemeType, false, schemeDatas.toArray(new SchemeData[schemeDatas.size()]));
} }
@ -131,11 +129,11 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
if (cloneSchemeDatas) { if (cloneSchemeDatas) {
schemeDatas = schemeDatas.clone(); schemeDatas = schemeDatas.clone();
} }
// Sorting ensures that universal scheme data (i.e. data that applies to all schemes) is matched
// last. It's also required by the equals and hashcode implementations.
Arrays.sort(schemeDatas, this);
this.schemeDatas = schemeDatas; this.schemeDatas = schemeDatas;
schemeDataCount = schemeDatas.length; schemeDataCount = schemeDatas.length;
// Sorting ensures that universal scheme data (i.e. data that applies to all schemes) is matched
// last. It's also required by the equals and hashcode implementations.
Arrays.sort(this.schemeDatas, this);
} }
/* package */ DrmInitData(Parcel in) { /* package */ DrmInitData(Parcel in) {
@ -152,7 +150,7 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
* @return The initialization data for the scheme, or null if the scheme is not supported. * @return The initialization data for the scheme, or null if the scheme is not supported.
*/ */
@Deprecated @Deprecated
public SchemeData get(UUID uuid) { public @Nullable SchemeData get(UUID uuid) {
for (SchemeData schemeData : schemeDatas) { for (SchemeData schemeData : schemeDatas) {
if (schemeData.matches(uuid)) { if (schemeData.matches(uuid)) {
return schemeData; return schemeData;
@ -270,10 +268,8 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
public final @Nullable String licenseServerUrl; public final @Nullable String licenseServerUrl;
/** The mimeType of {@link #data}. */ /** The mimeType of {@link #data}. */
public final String mimeType; public final String mimeType;
/** /** The initialization data. May be null for scheme support checks only. */
* The initialization data. May be null for scheme support checks only. public final @Nullable byte[] data;
*/
public final byte[] data;
/** /**
* Whether secure decryption is required. * Whether secure decryption is required.
*/ */
@ -285,7 +281,7 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
* @param mimeType See {@link #mimeType}. * @param mimeType See {@link #mimeType}.
* @param data See {@link #data}. * @param data See {@link #data}.
*/ */
public SchemeData(UUID uuid, String mimeType, byte[] data) { public SchemeData(UUID uuid, String mimeType, @Nullable byte[] data) {
this(uuid, mimeType, data, false); this(uuid, mimeType, data, false);
} }
@ -296,7 +292,8 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
* @param data See {@link #data}. * @param data See {@link #data}.
* @param requiresSecureDecryption See {@link #requiresSecureDecryption}. * @param requiresSecureDecryption See {@link #requiresSecureDecryption}.
*/ */
public SchemeData(UUID uuid, String mimeType, byte[] data, boolean requiresSecureDecryption) { public SchemeData(
UUID uuid, String mimeType, @Nullable byte[] data, boolean requiresSecureDecryption) {
this(uuid, /* licenseServerUrl= */ null, mimeType, data, requiresSecureDecryption); this(uuid, /* licenseServerUrl= */ null, mimeType, data, requiresSecureDecryption);
} }
@ -312,7 +309,7 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
UUID uuid, UUID uuid,
@Nullable String licenseServerUrl, @Nullable String licenseServerUrl,
String mimeType, String mimeType,
byte[] data, @Nullable byte[] data,
boolean requiresSecureDecryption) { boolean requiresSecureDecryption) {
this.uuid = Assertions.checkNotNull(uuid); this.uuid = Assertions.checkNotNull(uuid);
this.licenseServerUrl = licenseServerUrl; this.licenseServerUrl = licenseServerUrl;
@ -324,7 +321,7 @@ public final class DrmInitData implements Comparator<SchemeData>, Parcelable {
/* package */ SchemeData(Parcel in) { /* package */ SchemeData(Parcel in) {
uuid = new UUID(in.readLong(), in.readLong()); uuid = new UUID(in.readLong(), in.readLong());
licenseServerUrl = in.readString(); licenseServerUrl = in.readString();
mimeType = in.readString(); mimeType = Util.castNonNull(in.readString());
data = in.createByteArray(); data = in.createByteArray();
requiresSecureDecryption = in.readByte() != 0; requiresSecureDecryption = in.readByte() != 0;
} }

View File

@ -18,6 +18,7 @@ package com.google.android.exoplayer2.drm;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.media.MediaDrm; import android.media.MediaDrm;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.Map; import java.util.Map;
@ -75,21 +76,24 @@ public interface DrmSession<T extends ExoMediaCrypto> {
@State int getState(); @State int getState();
/** /**
* Returns the cause of the error state. * Returns the cause of the error state, or null if {@link #getState()} is not {@link
* #STATE_ERROR}.
*/ */
@Nullable
DrmSessionException getError(); DrmSessionException getError();
/** /**
* Returns a {@link ExoMediaCrypto} for the open session, or null if called before the session has * Returns a {@link ExoMediaCrypto} for the open session, or null if called before the session has
* been opened or after it's been released. * been opened or after it's been released.
*/ */
@Nullable
T getMediaCrypto(); T getMediaCrypto();
/** /**
* Returns a map describing the key status for the session, or null if called before the session * Returns a map describing the key status for the session, or null if called before the session
* has been opened or after it's been released. * has been opened or after it's been released.
* <p> *
* Since DRM license policies vary by vendor, the specific status field names are determined by * <p>Since DRM license policies vary by vendor, the specific status field names are determined by
* each DRM vendor. Refer to your DRM provider documentation for definitions of the field names * each DRM vendor. Refer to your DRM provider documentation for definitions of the field names
* for a particular DRM engine plugin. * for a particular DRM engine plugin.
* *
@ -97,12 +101,13 @@ public interface DrmSession<T extends ExoMediaCrypto> {
* has been opened or after it's been released. * has been opened or after it's been released.
* @see MediaDrm#queryKeyStatus(byte[]) * @see MediaDrm#queryKeyStatus(byte[])
*/ */
@Nullable
Map<String, String> queryKeyStatus(); Map<String, String> queryKeyStatus();
/** /**
* Returns the key set id of the offline license loaded into this session, or null if there isn't * Returns the key set id of the offline license loaded into this session, or null if there isn't
* one. * one.
*/ */
@Nullable
byte[] getOfflineLicenseKeySetId(); byte[] getOfflineLicenseKeySetId();
} }

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.drm; package com.google.android.exoplayer2.drm;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import java.util.Map; import java.util.Map;
@ -33,22 +34,22 @@ public final class ErrorStateDrmSession<T extends ExoMediaCrypto> implements Drm
} }
@Override @Override
public DrmSessionException getError() { public @Nullable DrmSessionException getError() {
return error; return error;
} }
@Override @Override
public T getMediaCrypto() { public @Nullable T getMediaCrypto() {
return null; return null;
} }
@Override @Override
public Map<String, String> queryKeyStatus() { public @Nullable Map<String, String> queryKeyStatus() {
return null; return null;
} }
@Override @Override
public byte[] getOfflineLicenseKeySetId() { public @Nullable byte[] getOfflineLicenseKeySetId() {
return null; return null;
} }

View File

@ -131,7 +131,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
String mimeType = null; String mimeType = null;
if (schemeDatas != null) { if (schemeDatas != null) {
schemeData = getSchemeData(uuid, schemeDatas); schemeData = getSchemeData(uuid, schemeDatas);
initData = adjustRequestInitData(uuid, schemeData.data); initData = adjustRequestInitData(uuid, Assertions.checkNotNull(schemeData.data));
mimeType = adjustRequestMimeType(uuid, schemeData.mimeType); mimeType = adjustRequestMimeType(uuid, schemeData.mimeType);
} }
MediaDrm.KeyRequest request = MediaDrm.KeyRequest request =
@ -229,11 +229,12 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
boolean canConcatenateData = true; boolean canConcatenateData = true;
for (int i = 0; i < schemeDatas.size(); i++) { for (int i = 0; i < schemeDatas.size(); i++) {
SchemeData schemeData = schemeDatas.get(i); SchemeData schemeData = schemeDatas.get(i);
byte[] schemeDataData = Util.castNonNull(schemeData.data);
if (schemeData.requiresSecureDecryption == firstSchemeData.requiresSecureDecryption if (schemeData.requiresSecureDecryption == firstSchemeData.requiresSecureDecryption
&& Util.areEqual(schemeData.mimeType, firstSchemeData.mimeType) && Util.areEqual(schemeData.mimeType, firstSchemeData.mimeType)
&& Util.areEqual(schemeData.licenseServerUrl, firstSchemeData.licenseServerUrl) && Util.areEqual(schemeData.licenseServerUrl, firstSchemeData.licenseServerUrl)
&& PsshAtomUtil.isPsshAtom(schemeData.data)) { && PsshAtomUtil.isPsshAtom(schemeDataData)) {
concatenatedDataLength += schemeData.data.length; concatenatedDataLength += schemeDataData.length;
} else { } else {
canConcatenateData = false; canConcatenateData = false;
break; break;
@ -244,9 +245,10 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
int concatenatedDataPosition = 0; int concatenatedDataPosition = 0;
for (int i = 0; i < schemeDatas.size(); i++) { for (int i = 0; i < schemeDatas.size(); i++) {
SchemeData schemeData = schemeDatas.get(i); SchemeData schemeData = schemeDatas.get(i);
int schemeDataLength = schemeData.data.length; byte[] schemeDataData = Util.castNonNull(schemeData.data);
int schemeDataLength = schemeDataData.length;
System.arraycopy( System.arraycopy(
schemeData.data, 0, concatenatedData, concatenatedDataPosition, schemeDataLength); schemeDataData, 0, concatenatedData, concatenatedDataPosition, schemeDataLength);
concatenatedDataPosition += schemeDataLength; concatenatedDataPosition += schemeDataLength;
} }
return firstSchemeData.copyWithData(concatenatedData); return firstSchemeData.copyWithData(concatenatedData);
@ -257,7 +259,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
// the first V0 box. // the first V0 box.
for (int i = 0; i < schemeDatas.size(); i++) { for (int i = 0; i < schemeDatas.size(); i++) {
SchemeData schemeData = schemeDatas.get(i); SchemeData schemeData = schemeDatas.get(i);
int version = PsshAtomUtil.parseVersion(schemeData.data); int version = PsshAtomUtil.parseVersion(Util.castNonNull(schemeData.data));
if (Util.SDK_INT < 23 && version == 0) { if (Util.SDK_INT < 23 && version == 0) {
return schemeData; return schemeData;
} else if (Util.SDK_INT >= 23 && version == 1) { } else if (Util.SDK_INT >= 23 && version == 1) {

View File

@ -17,6 +17,7 @@ package com.google.android.exoplayer2.drm;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.net.Uri; import android.net.Uri;
import android.support.annotation.Nullable;
import android.text.TextUtils; import android.text.TextUtils;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest; import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest;
@ -135,8 +136,12 @@ public final class HttpMediaDrmCallback implements MediaDrmCallback {
return executePost(dataSourceFactory, url, request.getData(), requestProperties); return executePost(dataSourceFactory, url, request.getData(), requestProperties);
} }
private static byte[] executePost(HttpDataSource.Factory dataSourceFactory, String url, private static byte[] executePost(
byte[] data, Map<String, String> requestProperties) throws IOException { HttpDataSource.Factory dataSourceFactory,
String url,
byte[] data,
@Nullable Map<String, String> requestProperties)
throws IOException {
HttpDataSource dataSource = dataSourceFactory.createDataSource(); HttpDataSource dataSource = dataSourceFactory.createDataSource();
if (requestProperties != null) { if (requestProperties != null) {
for (Map.Entry<String, String> requestProperty : requestProperties.entrySet()) { for (Map.Entry<String, String> requestProperty : requestProperties.entrySet()) {
@ -164,17 +169,18 @@ public final class HttpMediaDrmCallback implements MediaDrmCallback {
boolean manuallyRedirect = boolean manuallyRedirect =
(e.responseCode == 307 || e.responseCode == 308) (e.responseCode == 307 || e.responseCode == 308)
&& manualRedirectCount++ < MAX_MANUAL_REDIRECTS; && manualRedirectCount++ < MAX_MANUAL_REDIRECTS;
url = manuallyRedirect ? getRedirectUrl(e) : null; String redirectUrl = manuallyRedirect ? getRedirectUrl(e) : null;
if (url == null) { if (redirectUrl == null) {
throw e; throw e;
} }
url = redirectUrl;
} finally { } finally {
Util.closeQuietly(inputStream); Util.closeQuietly(inputStream);
} }
} }
} }
private static String getRedirectUrl(InvalidResponseCodeException exception) { private static @Nullable String getRedirectUrl(InvalidResponseCodeException exception) {
Map<String, List<String>> headerFields = exception.headerFields; Map<String, List<String>> headerFields = exception.headerFields;
if (headerFields != null) { if (headerFields != null) {
List<String> locationHeaders = headerFields.get("Location"); List<String> locationHeaders = headerFields.get("Location");

View File

@ -19,6 +19,7 @@ import android.media.MediaDrm;
import android.os.ConditionVariable; import android.os.ConditionVariable;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.support.annotation.Nullable;
import android.util.Pair; import android.util.Pair;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager.Mode; import com.google.android.exoplayer2.drm.DefaultDrmSessionManager.Mode;
@ -34,6 +35,8 @@ import java.util.UUID;
*/ */
public final class OfflineLicenseHelper<T extends ExoMediaCrypto> { public final class OfflineLicenseHelper<T extends ExoMediaCrypto> {
private static final DrmInitData DUMMY_DRM_INIT_DATA = new DrmInitData();
private final ConditionVariable conditionVariable; private final ConditionVariable conditionVariable;
private final DefaultDrmSessionManager<T> drmSessionManager; private final DefaultDrmSessionManager<T> drmSessionManager;
private final HandlerThread handlerThread; private final HandlerThread handlerThread;
@ -95,7 +98,7 @@ public final class OfflineLicenseHelper<T extends ExoMediaCrypto> {
String defaultLicenseUrl, String defaultLicenseUrl,
boolean forceDefaultLicenseUrl, boolean forceDefaultLicenseUrl,
Factory httpDataSourceFactory, Factory httpDataSourceFactory,
HashMap<String, String> optionalKeyRequestParameters) @Nullable HashMap<String, String> optionalKeyRequestParameters)
throws UnsupportedDrmException { throws UnsupportedDrmException {
return new OfflineLicenseHelper<>(C.WIDEVINE_UUID, return new OfflineLicenseHelper<>(C.WIDEVINE_UUID,
FrameworkMediaDrm.newInstance(C.WIDEVINE_UUID), FrameworkMediaDrm.newInstance(C.WIDEVINE_UUID),
@ -118,7 +121,7 @@ public final class OfflineLicenseHelper<T extends ExoMediaCrypto> {
UUID uuid, UUID uuid,
ExoMediaDrm<T> mediaDrm, ExoMediaDrm<T> mediaDrm,
MediaDrmCallback callback, MediaDrmCallback callback,
HashMap<String, String> optionalKeyRequestParameters) { @Nullable HashMap<String, String> optionalKeyRequestParameters) {
handlerThread = new HandlerThread("OfflineLicenseHelper"); handlerThread = new HandlerThread("OfflineLicenseHelper");
handlerThread.start(); handlerThread.start();
conditionVariable = new ConditionVariable(); conditionVariable = new ConditionVariable();
@ -199,7 +202,8 @@ public final class OfflineLicenseHelper<T extends ExoMediaCrypto> {
public synchronized byte[] renewLicense(byte[] offlineLicenseKeySetId) public synchronized byte[] renewLicense(byte[] offlineLicenseKeySetId)
throws DrmSessionException { throws DrmSessionException {
Assertions.checkNotNull(offlineLicenseKeySetId); Assertions.checkNotNull(offlineLicenseKeySetId);
return blockingKeyRequest(DefaultDrmSessionManager.MODE_DOWNLOAD, offlineLicenseKeySetId, null); return blockingKeyRequest(
DefaultDrmSessionManager.MODE_DOWNLOAD, offlineLicenseKeySetId, DUMMY_DRM_INIT_DATA);
} }
/** /**
@ -211,7 +215,8 @@ public final class OfflineLicenseHelper<T extends ExoMediaCrypto> {
public synchronized void releaseLicense(byte[] offlineLicenseKeySetId) public synchronized void releaseLicense(byte[] offlineLicenseKeySetId)
throws DrmSessionException { throws DrmSessionException {
Assertions.checkNotNull(offlineLicenseKeySetId); Assertions.checkNotNull(offlineLicenseKeySetId);
blockingKeyRequest(DefaultDrmSessionManager.MODE_RELEASE, offlineLicenseKeySetId, null); blockingKeyRequest(
DefaultDrmSessionManager.MODE_RELEASE, offlineLicenseKeySetId, DUMMY_DRM_INIT_DATA);
} }
/** /**
@ -224,8 +229,9 @@ public final class OfflineLicenseHelper<T extends ExoMediaCrypto> {
public synchronized Pair<Long, Long> getLicenseDurationRemainingSec(byte[] offlineLicenseKeySetId) public synchronized Pair<Long, Long> getLicenseDurationRemainingSec(byte[] offlineLicenseKeySetId)
throws DrmSessionException { throws DrmSessionException {
Assertions.checkNotNull(offlineLicenseKeySetId); Assertions.checkNotNull(offlineLicenseKeySetId);
DrmSession<T> drmSession = openBlockingKeyRequest(DefaultDrmSessionManager.MODE_QUERY, DrmSession<T> drmSession =
offlineLicenseKeySetId, null); openBlockingKeyRequest(
DefaultDrmSessionManager.MODE_QUERY, offlineLicenseKeySetId, DUMMY_DRM_INIT_DATA);
DrmSessionException error = drmSession.getError(); DrmSessionException error = drmSession.getError();
Pair<Long, Long> licenseDurationRemainingSec = Pair<Long, Long> licenseDurationRemainingSec =
WidevineUtil.getLicenseDurationRemainingSec(drmSession); WidevineUtil.getLicenseDurationRemainingSec(drmSession);
@ -236,7 +242,7 @@ public final class OfflineLicenseHelper<T extends ExoMediaCrypto> {
} }
throw error; throw error;
} }
return licenseDurationRemainingSec; return Assertions.checkNotNull(licenseDurationRemainingSec);
} }
/** /**
@ -246,8 +252,9 @@ public final class OfflineLicenseHelper<T extends ExoMediaCrypto> {
handlerThread.quit(); handlerThread.quit();
} }
private byte[] blockingKeyRequest(@Mode int licenseMode, byte[] offlineLicenseKeySetId, private byte[] blockingKeyRequest(
DrmInitData drmInitData) throws DrmSessionException { @Mode int licenseMode, @Nullable byte[] offlineLicenseKeySetId, DrmInitData drmInitData)
throws DrmSessionException {
DrmSession<T> drmSession = openBlockingKeyRequest(licenseMode, offlineLicenseKeySetId, DrmSession<T> drmSession = openBlockingKeyRequest(licenseMode, offlineLicenseKeySetId,
drmInitData); drmInitData);
DrmSessionException error = drmSession.getError(); DrmSessionException error = drmSession.getError();
@ -256,11 +263,11 @@ public final class OfflineLicenseHelper<T extends ExoMediaCrypto> {
if (error != null) { if (error != null) {
throw error; throw error;
} }
return keySetId; return Assertions.checkNotNull(keySetId);
} }
private DrmSession<T> openBlockingKeyRequest(@Mode int licenseMode, byte[] offlineLicenseKeySetId, private DrmSession<T> openBlockingKeyRequest(
DrmInitData drmInitData) { @Mode int licenseMode, @Nullable byte[] offlineLicenseKeySetId, DrmInitData drmInitData) {
drmSessionManager.setMode(licenseMode, offlineLicenseKeySetId); drmSessionManager.setMode(licenseMode, offlineLicenseKeySetId);
conditionVariable.close(); conditionVariable.close();
DrmSession<T> drmSession = drmSessionManager.acquireSession(handlerThread.getLooper(), DrmSession<T> drmSession = drmSessionManager.acquireSession(handlerThread.getLooper(),

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.drm; package com.google.android.exoplayer2.drm;
import android.support.annotation.Nullable;
import android.util.Pair; import android.util.Pair;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import java.util.Map; import java.util.Map;
@ -38,7 +39,8 @@ public final class WidevineUtil {
* @return A {@link Pair} consisting of the remaining license and playback durations in seconds, * @return A {@link Pair} consisting of the remaining license and playback durations in seconds,
* or null if called before the session has been opened or after it's been released. * or null if called before the session has been opened or after it's been released.
*/ */
public static Pair<Long, Long> getLicenseDurationRemainingSec(DrmSession<?> drmSession) { public static @Nullable Pair<Long, Long> getLicenseDurationRemainingSec(
DrmSession<?> drmSession) {
Map<String, String> keyStatus = drmSession.queryKeyStatus(); Map<String, String> keyStatus = drmSession.queryKeyStatus();
if (keyStatus == null) { if (keyStatus == null) {
return null; return null;

View File

@ -92,9 +92,12 @@ public class OfflineLicenseHelperTest {
public void testDownloadLicenseFailsIfNoKeySetIdIsReturned() throws Exception { public void testDownloadLicenseFailsIfNoKeySetIdIsReturned() throws Exception {
setStubLicenseAndPlaybackDurationValues(1000, 200); setStubLicenseAndPlaybackDurationValues(1000, 200);
byte[] offlineLicenseKeySetId = offlineLicenseHelper.downloadLicense(newDrmInitData()); try {
offlineLicenseHelper.downloadLicense(newDrmInitData());
assertThat(offlineLicenseKeySetId).isNull(); fail();
} catch (Exception e) {
// Expected.
}
} }
@Test @Test