Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 74797f84 authored by Jeff Tinker's avatar Jeff Tinker
Browse files

Add expiration update and keys change events

In support of unprefixed EME

bug: 19771612
bug: 19771431
Change-Id: Iddef695cfa1a56363a4c173249597e415cb93f50
parent 24f68352
Loading
Loading
Loading
Loading
+20 −0
Original line number Original line Diff line number Diff line
@@ -15330,6 +15330,8 @@ package android.media {
    method public void removeKeys(byte[]);
    method public void removeKeys(byte[]);
    method public void restoreKeys(byte[], byte[]);
    method public void restoreKeys(byte[], byte[]);
    method public void setOnEventListener(android.media.MediaDrm.OnEventListener);
    method public void setOnEventListener(android.media.MediaDrm.OnEventListener);
    method public void setOnExpirationUpdateListener(android.media.MediaDrm.OnExpirationUpdateListener, android.os.Handler);
    method public void setOnKeysChangeListener(android.media.MediaDrm.OnKeysChangeListener, android.os.Handler);
    method public void setPropertyByteArray(java.lang.String, byte[]);
    method public void setPropertyByteArray(java.lang.String, byte[]);
    method public void setPropertyString(java.lang.String, java.lang.String);
    method public void setPropertyString(java.lang.String, java.lang.String);
    field public static final int EVENT_KEY_EXPIRED = 3; // 0x3
    field public static final int EVENT_KEY_EXPIRED = 3; // 0x3
@@ -15337,6 +15339,11 @@ package android.media {
    field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1
    field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1
    field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5
    field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5
    field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4
    field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4
    field public static final int KEY_STATUS_EXPIRED = 1; // 0x1
    field public static final int KEY_STATUS_INTERNAL_ERROR = 4; // 0x4
    field public static final int KEY_STATUS_OUTPUT_NOT_ALLOWED = 2; // 0x2
    field public static final int KEY_STATUS_PENDING = 3; // 0x3
    field public static final int KEY_STATUS_USABLE = 0; // 0x0
    field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
    field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
    field public static final int KEY_TYPE_RELEASE = 3; // 0x3
    field public static final int KEY_TYPE_RELEASE = 3; // 0x3
    field public static final int KEY_TYPE_STREAMING = 1; // 0x1
    field public static final int KEY_TYPE_STREAMING = 1; // 0x1
@@ -15363,6 +15370,11 @@ package android.media {
    method public int getRequestType();
    method public int getRequestType();
  }
  }
  public static final class MediaDrm.KeyStatus {
    method public byte[] getKeyId();
    method public int getStatusCode();
  }
  public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException {
  public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException {
    method public java.lang.String getDiagnosticInfo();
    method public java.lang.String getDiagnosticInfo();
  }
  }
@@ -15371,6 +15383,14 @@ package android.media {
    method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]);
    method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]);
  }
  }
  public static abstract interface MediaDrm.OnExpirationUpdateListener {
    method public abstract void onExpirationUpdate(android.media.MediaDrm, byte[], long);
  }
  public static abstract interface MediaDrm.OnKeysChangeListener {
    method public abstract void onKeysChange(android.media.MediaDrm, byte[], java.util.List<android.media.MediaDrm.KeyStatus>, boolean);
  }
  public static final class MediaDrm.ProvisionRequest {
  public static final class MediaDrm.ProvisionRequest {
    method public byte[] getData();
    method public byte[] getData();
    method public java.lang.String getDefaultUrl();
    method public java.lang.String getDefaultUrl();
+20 −0
Original line number Original line Diff line number Diff line
@@ -16539,6 +16539,8 @@ package android.media {
    method public void removeKeys(byte[]);
    method public void removeKeys(byte[]);
    method public void restoreKeys(byte[], byte[]);
    method public void restoreKeys(byte[], byte[]);
    method public void setOnEventListener(android.media.MediaDrm.OnEventListener);
    method public void setOnEventListener(android.media.MediaDrm.OnEventListener);
    method public void setOnExpirationUpdateListener(android.media.MediaDrm.OnExpirationUpdateListener, android.os.Handler);
    method public void setOnKeysChangeListener(android.media.MediaDrm.OnKeysChangeListener, android.os.Handler);
    method public void setPropertyByteArray(java.lang.String, byte[]);
    method public void setPropertyByteArray(java.lang.String, byte[]);
    method public void setPropertyString(java.lang.String, java.lang.String);
    method public void setPropertyString(java.lang.String, java.lang.String);
    method public void unprovisionDevice();
    method public void unprovisionDevice();
@@ -16547,6 +16549,11 @@ package android.media {
    field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1
    field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1
    field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5
    field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5
    field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4
    field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4
    field public static final int KEY_STATUS_EXPIRED = 1; // 0x1
    field public static final int KEY_STATUS_INTERNAL_ERROR = 4; // 0x4
    field public static final int KEY_STATUS_OUTPUT_NOT_ALLOWED = 2; // 0x2
    field public static final int KEY_STATUS_PENDING = 3; // 0x3
    field public static final int KEY_STATUS_USABLE = 0; // 0x0
    field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
    field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
    field public static final int KEY_TYPE_RELEASE = 3; // 0x3
    field public static final int KEY_TYPE_RELEASE = 3; // 0x3
    field public static final int KEY_TYPE_STREAMING = 1; // 0x1
    field public static final int KEY_TYPE_STREAMING = 1; // 0x1
@@ -16573,6 +16580,11 @@ package android.media {
    method public int getRequestType();
    method public int getRequestType();
  }
  }
  public static final class MediaDrm.KeyStatus {
    method public byte[] getKeyId();
    method public int getStatusCode();
  }
  public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException {
  public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException {
    method public java.lang.String getDiagnosticInfo();
    method public java.lang.String getDiagnosticInfo();
  }
  }
@@ -16581,6 +16593,14 @@ package android.media {
    method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]);
    method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]);
  }
  }
  public static abstract interface MediaDrm.OnExpirationUpdateListener {
    method public abstract void onExpirationUpdate(android.media.MediaDrm, byte[], long);
  }
  public static abstract interface MediaDrm.OnKeysChangeListener {
    method public abstract void onKeysChange(android.media.MediaDrm, byte[], java.util.List<android.media.MediaDrm.KeyStatus>, boolean);
  }
  public static final class MediaDrm.ProvisionRequest {
  public static final class MediaDrm.ProvisionRequest {
    method public byte[] getData();
    method public byte[] getData();
    method public java.lang.String getDefaultUrl();
    method public java.lang.String getDefaultUrl();
+206 −12
Original line number Original line Diff line number Diff line
@@ -17,9 +17,10 @@
package android.media;
package android.media;


import java.lang.ref.WeakReference;
import java.lang.ref.WeakReference;
import java.util.UUID;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashMap;
import java.util.List;
import java.util.List;
import java.util.UUID;
import android.annotation.SystemApi;
import android.annotation.SystemApi;
import android.os.Handler;
import android.os.Handler;
import android.os.Looper;
import android.os.Looper;
@@ -98,12 +99,14 @@ import android.util.Log;
 */
 */
public final class MediaDrm {
public final class MediaDrm {


    private final static String TAG = "MediaDrm";
    private static final String TAG = "MediaDrm";


    private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES;
    private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES;


    private EventHandler mEventHandler;
    private EventHandler mEventHandler;
    private OnEventListener mOnEventListener;
    private OnEventListener mOnEventListener;
    private OnKeysChangeListener mOnKeysChangeListener;
    private OnExpirationUpdateListener mOnExpirationUpdateListener;


    private long mNativeContext;
    private long mNativeContext;


@@ -226,6 +229,148 @@ public final class MediaDrm {
        }
        }
    }
    }


    /**
     * Register a callback to be invoked when a session expiration update
     * occurs.  The app's OnExpirationUpdateListener will be notified
     * when the expiration time of the keys in the session have changed.
     * @param listener the callback that will be run
     * @param handler the handler on which the listener should be invoked, or
     *     null if the listener should be invoked on the calling thread's looper.
     */
    public void setOnExpirationUpdateListener(OnExpirationUpdateListener listener,
            Handler handler)
    {
        if (listener != null) {
            Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
            if (looper != null) {
                if (mEventHandler == null || mEventHandler.getLooper() != looper) {
                    mEventHandler = new EventHandler(this, looper);
                }
            }
        }
        mOnExpirationUpdateListener = listener;
    }

    /**
     * Interface definition for a callback to be invoked when a drm session
     * expiration update occurs
     */
    public interface OnExpirationUpdateListener
    {
        /**
         * Called when a session expiration update occurs, to inform the app
         * about the change in expiration time
         *
         * @param md the MediaDrm object on which the event occurred
         * @param sessionId the DRM session ID on which the event occurred
         * @param expirationTime the new expiration time for the keys in the session.
         *     The time is in milliseconds, relative to the Unix epoch.
         */
        void onExpirationUpdate(MediaDrm md, byte[] sessionId, long expirationTime);
    }

    /**
     * Register a callback to be invoked when the state of keys in a session
     * change, e.g. when a license update occurs or when a license expires.
     *
     * @param listener the callback that will be run when key status changes
     * @param handler the handler on which the listener should be invoked, or
     *     null if the listener should be invoked on the calling thread's looper.
     */
    public void setOnKeysChangeListener(OnKeysChangeListener listener,
            Handler handler)
    {
        if (listener != null) {
            Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
            if (looper != null) {
                if (mEventHandler == null || mEventHandler.getLooper() != looper) {
                    mEventHandler = new EventHandler(this, looper);
                }
            }
        }
        mOnKeysChangeListener = listener;
    }

    /**
     * Interface definition for a callback to be invoked when the keys in a drm
     * session change states.
     */
    public interface OnKeysChangeListener
    {
        /**
         * Called when the keys in a session change status, such as when the license
         * is renewed or expires.
         *
         * @param md the MediaDrm object on which the event occurred
         * @param sessionId the DRM session ID on which the event occurred
         * @param keyInformation a list of {@link MediaDrm.KeyStatus}
         *     instances indicating the status for each key in the session
         * @param hasNewUsableKey indicates if a key has been added that is usable,
         *     which may trigger an attempt to resume playback on the media stream
         *     if it is currently blocked waiting for a key.
         */
        void onKeysChange(MediaDrm md, byte[] sessionId, List<KeyStatus> keyInformation,
                boolean hasNewUsableKey);
    }

    /**
     * The key is currently usable to decrypt media data
     */
    public static final int KEY_STATUS_USABLE = 0;

    /**
     * The key is no longer usable to decrypt media data because its
     * expiration time has passed.
     */
    public static final int KEY_STATUS_EXPIRED = 1;

    /**
     * The key is not currently usable to decrypt media data because its
     * output requirements cannot currently be met.
     */
    public static final int KEY_STATUS_OUTPUT_NOT_ALLOWED = 2;

    /**
     * The status of the key is not yet known and is being determined.
     * The status will be updated with the actual status when it has
     * been determined.
     */
    public static final int KEY_STATUS_PENDING = 3;

    /**
     * The key is not currently usable to decrypt media data because of an
     * internal error in processing unrelated to input parameters.  This error
     * is not actionable by an app.
     */
    public static final int KEY_STATUS_INTERNAL_ERROR = 4;


    /**
     * Defines the status of a key.
     * A KeyStatus for each key in a session is provided to the
     * {@link OnKeysChangeListener#onKeysChange}
     * listener.
     */
    public static final class KeyStatus {
        private final byte[] mKeyId;
        private final int mStatusCode;

        KeyStatus(byte[] keyId, int statusCode) {
            mKeyId = keyId;
            mStatusCode = statusCode;
        }

        /**
         * Returns the status code for the key
         */
        public int getStatusCode() { return mStatusCode; }

        /**
         * Returns the id for the key
         */
        public byte[] getKeyId() { return mKeyId; }
    }

    /**
    /**
     * Register a callback to be invoked when an event occurs
     * Register a callback to be invoked when an event occurs
     *
     *
@@ -289,6 +434,8 @@ public final class MediaDrm {
    public static final int EVENT_SESSION_RECLAIMED = 5;
    public static final int EVENT_SESSION_RECLAIMED = 5;


    private static final int DRM_EVENT = 200;
    private static final int DRM_EVENT = 200;
    private static final int EXPIRATION_UPDATE = 201;
    private static final int KEYS_CHANGE = 202;


    private class EventHandler extends Handler
    private class EventHandler extends Handler
    {
    {
@@ -308,8 +455,6 @@ public final class MediaDrm {
            switch(msg.what) {
            switch(msg.what) {


            case DRM_EVENT:
            case DRM_EVENT:
                Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")");

                if (mOnEventListener != null) {
                if (mOnEventListener != null) {
                    if (msg.obj != null && msg.obj instanceof Parcel) {
                    if (msg.obj != null && msg.obj instanceof Parcel) {
                        Parcel parcel = (Parcel)msg.obj;
                        Parcel parcel = (Parcel)msg.obj;
@@ -321,11 +466,46 @@ public final class MediaDrm {
                        if (data.length == 0) {
                        if (data.length == 0) {
                            data = null;
                            data = null;
                        }
                        }

                        Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")");
                        mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data);
                        mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data);
                    }
                    }
                }
                }
                return;
                return;


            case KEYS_CHANGE:
                if (mOnKeysChangeListener != null) {
                    if (msg.obj != null && msg.obj instanceof Parcel) {
                        Parcel parcel = (Parcel)msg.obj;
                        byte[] sessionId = parcel.createByteArray();
                        if (sessionId.length > 0) {
                            List<KeyStatus> keyStatusList = keyStatusListFromParcel(parcel);
                            boolean hasNewUsableKey = (parcel.readInt() != 0);

                            Log.i(TAG, "Drm keys change");
                            mOnKeysChangeListener.onKeysChange(mMediaDrm, sessionId, keyStatusList,
                                    hasNewUsableKey);
                        }
                    }
                }
                return;

            case EXPIRATION_UPDATE:
                if (mOnExpirationUpdateListener != null) {
                    if (msg.obj != null && msg.obj instanceof Parcel) {
                        Parcel parcel = (Parcel)msg.obj;
                        byte[] sessionId = parcel.createByteArray();
                        if (sessionId.length > 0) {
                            long expirationTime = parcel.readLong();

                            Log.i(TAG, "Drm key expiration update: " + expirationTime);
                            mOnExpirationUpdateListener.onExpirationUpdate(mMediaDrm, sessionId,
                                    expirationTime);
                        }
                    }
                }
                return;

            default:
            default:
                Log.e(TAG, "Unknown message type " + msg.what);
                Log.e(TAG, "Unknown message type " + msg.what);
                return;
                return;
@@ -333,7 +513,21 @@ public final class MediaDrm {
        }
        }
    }
    }


    /*
    /**
     * Parse a list of KeyStatus objects from an event parcel
     */
    private List<KeyStatus> keyStatusListFromParcel(Parcel parcel) {
        int nelems = parcel.readInt();
        List<KeyStatus> keyStatusList = new ArrayList(nelems);
        while (nelems-- > 0) {
            byte[] keyId = parcel.createByteArray();
            int keyStatusCode = parcel.readInt();
            keyStatusList.add(new KeyStatus(keyId, keyStatusCode));
        }
        return keyStatusList;
    }

    /**
     * This method is called from native code when an event occurs.  This method
     * This method is called from native code when an event occurs.  This method
     * just uses the EventHandler system to post the event back to the main app thread.
     * just uses the EventHandler system to post the event back to the main app thread.
     * We use a weak reference to the original MediaPlayer object so that the native
     * We use a weak reference to the original MediaPlayer object so that the native
@@ -341,14 +535,14 @@ public final class MediaDrm {
     * the cookie passed to native_setup().)
     * the cookie passed to native_setup().)
     */
     */
    private static void postEventFromNative(Object mediadrm_ref,
    private static void postEventFromNative(Object mediadrm_ref,
            int eventType, int extra, Object obj)
            int what, int eventType, int extra, Object obj)
    {
    {
        MediaDrm md = (MediaDrm)((WeakReference)mediadrm_ref).get();
        MediaDrm md = (MediaDrm)((WeakReference<MediaDrm>)mediadrm_ref).get();
        if (md == null) {
        if (md == null) {
            return;
            return;
        }
        }
        if (md.mEventHandler != null) {
        if (md.mEventHandler != null) {
            Message m = md.mEventHandler.obtainMessage(DRM_EVENT, eventType, extra, obj);
            Message m = md.mEventHandler.obtainMessage(what, eventType, extra, obj);
            md.mEventHandler.sendMessage(m);
            md.mEventHandler.sendMessage(m);
        }
        }
    }
    }
@@ -404,7 +598,7 @@ public final class MediaDrm {
    /**
    /**
     * Contains the opaque data an app uses to request keys from a license server
     * Contains the opaque data an app uses to request keys from a license server
     */
     */
    public final static class KeyRequest {
    public static final class KeyRequest {
        private byte[] mData;
        private byte[] mData;
        private String mDefaultUrl;
        private String mDefaultUrl;
        private int mRequestType;
        private int mRequestType;
@@ -521,7 +715,7 @@ public final class MediaDrm {
     * Contains the opaque data an app uses to request a certificate from a provisioning
     * Contains the opaque data an app uses to request a certificate from a provisioning
     * server
     * server
     */
     */
    public final static class ProvisionRequest {
    public static final class ProvisionRequest {
        ProvisionRequest() {}
        ProvisionRequest() {}


        /**
        /**
@@ -812,7 +1006,7 @@ public final class MediaDrm {
     *
     *
     * @hide - not part of the public API at this time
     * @hide - not part of the public API at this time
     */
     */
    public final static class CertificateRequest {
    public static final class CertificateRequest {
        private byte[] mData;
        private byte[] mData;
        private String mDefaultUrl;
        private String mDefaultUrl;


@@ -860,7 +1054,7 @@ public final class MediaDrm {
     *
     *
     * @hide - not part of the public API at this time
     * @hide - not part of the public API at this time
     */
     */
    public final static class Certificate {
    public static final class Certificate {
        Certificate() {}
        Certificate() {}


        /**
        /**
+29 −4
Original line number Original line Diff line number Diff line
@@ -96,6 +96,12 @@ struct EventTypes {
    jint kEventSessionReclaimed;
    jint kEventSessionReclaimed;
} gEventTypes;
} gEventTypes;


struct EventWhat {
    jint kWhatDrmEvent;
    jint kWhatExpirationUpdate;
    jint kWhatKeysChange;
} gEventWhat;

struct KeyTypes {
struct KeyTypes {
    jint kKeyTypeStreaming;
    jint kKeyTypeStreaming;
    jint kKeyTypeOffline;
    jint kKeyTypeOffline;
@@ -186,25 +192,37 @@ JNIDrmListener::~JNIDrmListener()
void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
                            const Parcel *obj)
                            const Parcel *obj)
{
{
    jint jeventType;
    jint jwhat;
    jint jeventType = 0;


    // translate DrmPlugin event types into their java equivalents
    // translate DrmPlugin event types into their java equivalents
    switch (eventType) {
    switch (eventType) {
        case DrmPlugin::kDrmPluginEventProvisionRequired:
        case DrmPlugin::kDrmPluginEventProvisionRequired:
            jwhat = gEventWhat.kWhatDrmEvent;
            jeventType = gEventTypes.kEventProvisionRequired;
            jeventType = gEventTypes.kEventProvisionRequired;
            break;
            break;
        case DrmPlugin::kDrmPluginEventKeyNeeded:
        case DrmPlugin::kDrmPluginEventKeyNeeded:
            jwhat = gEventWhat.kWhatDrmEvent;
            jeventType = gEventTypes.kEventKeyRequired;
            jeventType = gEventTypes.kEventKeyRequired;
            break;
            break;
        case DrmPlugin::kDrmPluginEventKeyExpired:
        case DrmPlugin::kDrmPluginEventKeyExpired:
            jwhat = gEventWhat.kWhatDrmEvent;
            jeventType = gEventTypes.kEventKeyExpired;
            jeventType = gEventTypes.kEventKeyExpired;
            break;
            break;
        case DrmPlugin::kDrmPluginEventVendorDefined:
        case DrmPlugin::kDrmPluginEventVendorDefined:
            jwhat = gEventWhat.kWhatDrmEvent;
            jeventType = gEventTypes.kEventVendorDefined;
            jeventType = gEventTypes.kEventVendorDefined;
            break;
            break;
        case DrmPlugin::kDrmPluginEventSessionReclaimed:
        case DrmPlugin::kDrmPluginEventSessionReclaimed:
            jwhat = gEventWhat.kWhatDrmEvent;
            jeventType = gEventTypes.kEventSessionReclaimed;
            jeventType = gEventTypes.kEventSessionReclaimed;
            break;
            break;
        case DrmPlugin::kDrmPluginEventExpirationUpdate:
            jwhat = gEventWhat.kWhatExpirationUpdate;
            break;
         case DrmPlugin::kDrmPluginEventKeysChange:
            jwhat = gEventWhat.kWhatKeysChange;
            break;
        default:
        default:
            ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
            ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
            return;
            return;
@@ -217,7 +235,7 @@ void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
            Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
            Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
            nativeParcel->setData(obj->data(), obj->dataSize());
            nativeParcel->setData(obj->data(), obj->dataSize());
            env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
            env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
                    jeventType, extra, jParcel);
                    jwhat, jeventType, extra, jParcel);
            env->DeleteLocalRef(jParcel);
            env->DeleteLocalRef(jParcel);
        }
        }
    }
    }
@@ -573,7 +591,7 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) {
    FIND_CLASS(clazz, "android/media/MediaDrm");
    FIND_CLASS(clazz, "android/media/MediaDrm");
    GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
    GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
    GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
    GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
                         "(Ljava/lang/Object;IILjava/lang/Object;)V");
                         "(Ljava/lang/Object;IIILjava/lang/Object;)V");


    jfieldID field;
    jfieldID field;
    GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
    GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
@@ -587,6 +605,13 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) {
    GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
    GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
    gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
    gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);


    GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
    gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
    GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
    gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
    GET_STATIC_FIELD_ID(field, clazz, "KEYS_CHANGE", "I");
    gEventWhat.kWhatKeysChange = env->GetStaticIntField(clazz, field);

    GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
    GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
    gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
    gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
    GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
    GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
@@ -837,7 +862,7 @@ static jobject android_media_MediaDrm_getKeyRequest(
                env->SetIntField(keyObj, gFields.keyRequest.requestType,
                env->SetIntField(keyObj, gFields.keyRequest.requestType,
                        gKeyRequestTypes.kKeyRequestTypeRelease);
                        gKeyRequestTypes.kKeyRequestTypeRelease);
                break;
                break;
            case DrmPlugin::kKeyRequestType_Unknown:
            default:
                throwStateException(env, "DRM plugin failure: unknown key request type",
                throwStateException(env, "DRM plugin failure: unknown key request type",
                        ERROR_DRM_UNKNOWN);
                        ERROR_DRM_UNKNOWN);
                break;
                break;