13551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
23551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
33551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// found in the LICENSE file.
43551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
53551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)package org.chromium.media;
63551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
73551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import android.media.MediaCrypto;
83551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import android.media.MediaDrm;
93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import android.os.AsyncTask;
10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import android.os.Build;
113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import android.os.Handler;
123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import android.util.Log;
133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import org.apache.http.HttpResponse;
153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import org.apache.http.client.ClientProtocolException;
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import org.apache.http.client.HttpClient;
17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import org.apache.http.client.methods.HttpPost;
183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import org.apache.http.impl.client.DefaultHttpClient;
193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import org.apache.http.util.EntityUtils;
203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import org.chromium.base.CalledByNative;
213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import org.chromium.base.JNINamespace;
223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import java.io.IOException;
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import java.nio.ByteBuffer;
256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)import java.nio.ByteOrder;
26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import java.util.ArrayDeque;
273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import java.util.HashMap;
283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import java.util.UUID;
293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)/**
313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * A wrapper of the android MediaDrm class. Each MediaDrmBridge manages multiple
323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * sessions for a single MediaSourcePlayer.
333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) */
343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)@JNINamespace("media")
356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)public class MediaDrmBridge {
36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Implementation Notes:
37a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // - A media crypto session (mMediaCryptoSession) is opened after MediaDrm
38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   is created. This session will be added to mSessionIds.
39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    //   a) In multiple session mode, this session will only be used to create
40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    //      the MediaCrypto object. It's associated mime type is always null and
41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    //      it's session ID is always INVALID_SESSION_ID.
42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   b) In single session mode, this session will be used to create the
43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //      MediaCrypto object and will be used to call getKeyRequest() and
44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    //      manage all keys.  The session ID will always be the lastest session
45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    //      ID passed by the caller.
46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // - Each createSession() call creates a new session. All sessions are
47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   managed in mSessionIds.
48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // - Whenever NotProvisionedException is thrown, we will clean up the
49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   current state and start the provisioning process.
50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // - When provisioning is finished, we will try to resume suspended
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   operations:
52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   a) Create the media crypto session if it's not created.
53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    //   b) Finish createSession() if previous createSession() was interrupted
54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    //      by a NotProvisionedException.
55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // - Whenever an unexpected error occurred, we'll call release() to release
56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   all resources and clear all states. In that case all calls to this
57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   object will be no-op. All public APIs and callbacks should check
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   mMediaBridge to make sure release() hasn't been called. Also, we call
59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   release() immediately after the error happens (e.g. after mMediaDrm)
60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   calls. Indirect calls should not call release() again to avoid
61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //   duplication (even though it doesn't hurt to call release() twice).
623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private static final String TAG = "MediaDrmBridge";
6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static final String SECURITY_LEVEL = "securityLevel";
6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static final String PRIVACY_MODE = "privacyMode";
66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private static final String SESSION_SHARING = "sessionSharing";
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private static final String ENABLE = "enable";
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private static final int INVALID_SESSION_ID = 0;
69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private MediaDrm mMediaDrm;
71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private long mNativeMediaDrmBridge;
723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private UUID mSchemeUUID;
73424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private Handler mHandler;
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // In this mode, we only open one session, i.e. mMediaCryptoSession.
76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private boolean mSingleSessionMode;
77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // A session only for the purpose of creating a MediaCrypto object.
79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // This session is opened when createSession() is called for the first
80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // time.
81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // - In multiple session mode, all following createSession() calls
82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // should create a new session and use it to call getKeyRequest(). No
83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // getKeyRequest() should ever be called on this media crypto session.
84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // - In single session mode, all createSession() calls use the same
85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // media crypto session. When createSession() is called with a new
86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // initData, previously added keys may not be available anymore.
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private ByteBuffer mMediaCryptoSession;
88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private MediaCrypto mMediaCrypto;
89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // The map of all opened sessions to their session reference IDs.
91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private HashMap<ByteBuffer, Integer> mSessionIds;
92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // The map of all opened sessions to their mime types.
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private HashMap<ByteBuffer, String> mSessionMimeTypes;
94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // The queue of all pending createSession() data.
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private ArrayDeque<PendingCreateSessionData> mPendingCreateSessionDataQueue;
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
9868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    private boolean mResetDeviceCredentialsPending;
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // MediaDrmBridge is waiting for provisioning response from the server.
101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //
102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Notes about NotProvisionedException: This exception can be thrown in a
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // lot of cases. To streamline implementation, we do not catch it in private
104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // non-native methods and only catch it in public APIs.
105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private boolean mProvisioningPending;
106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    /**
108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     *  This class contains data needed to call createSession().
109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     */
110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private static class PendingCreateSessionData {
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        private final int mSessionId;
112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        private final byte[] mInitData;
113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        private final String mMimeType;
114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        private PendingCreateSessionData(int sessionId, byte[] initData, String mimeType) {
116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            mSessionId = sessionId;
117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            mInitData = initData;
118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            mMimeType = mimeType;
119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        private int sessionId() { return mSessionId; }
122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        private byte[] initData() { return mInitData; }
123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        private String mimeType() { return mMimeType; }
124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private static UUID getUUIDFromBytes(byte[] data) {
1273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (data.length != 16) {
1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            return null;
1293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        long mostSigBits = 0;
1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        long leastSigBits = 0;
1323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        for (int i = 0; i < 8; i++) {
1333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            mostSigBits = (mostSigBits << 8) | (data[i] & 0xff);
1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        for (int i = 8; i < 16; i++) {
1363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            leastSigBits = (leastSigBits << 8) | (data[i] & 0xff);
1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return new UUID(mostSigBits, leastSigBits);
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    /**
142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     *  Gets session associated with the sessionId.
143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     *
144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     *  @return session if sessionId maps a valid opened session. Returns null
145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     *  otherwise.
146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     */
147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private ByteBuffer getSession(int sessionId) {
148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        for (ByteBuffer session : mSessionIds.keySet()) {
149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            if (mSessionIds.get(session) == sessionId) {
150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                return session;
151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            }
152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        }
153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        return null;
154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
155a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private MediaDrmBridge(UUID schemeUUID, long nativeMediaDrmBridge, boolean singleSessionMode)
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            throws android.media.UnsupportedSchemeException {
15858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        mSchemeUUID = schemeUUID;
15958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        mMediaDrm = new MediaDrm(schemeUUID);
16058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        mNativeMediaDrmBridge = nativeMediaDrmBridge;
161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        mHandler = new Handler();
162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        mSingleSessionMode = singleSessionMode;
163a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        mSessionIds = new HashMap<ByteBuffer, Integer>();
164a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        mSessionMimeTypes = new HashMap<ByteBuffer, String>();
165a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        mPendingCreateSessionDataQueue = new ArrayDeque<PendingCreateSessionData>();
16668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        mResetDeviceCredentialsPending = false;
167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        mProvisioningPending = false;
168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
16958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        mMediaDrm.setOnEventListener(new MediaDrmListener());
170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        mMediaDrm.setPropertyString(PRIVACY_MODE, ENABLE);
171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (!mSingleSessionMode) {
172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            mMediaDrm.setPropertyString(SESSION_SHARING, ENABLE);
173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // We could open a MediaCrypto session here to support faster start of
176a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // clear lead (no need to wait for createSession()). But on
177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // Android, memory and battery resources are precious and we should
178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // only create a session when we are sure we'll use it.
179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // TODO(xhwang): Investigate other options to support fast start.
1803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    /**
183424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * Create a MediaCrypto object.
184424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     *
185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     * @return whether a MediaCrypto object is successfully created.
186424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     */
187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private boolean createMediaCrypto() throws android.media.NotProvisionedException {
188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (mMediaDrm == null) {
189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            return false;
190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
191a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        assert !mProvisioningPending;
192a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        assert mMediaCryptoSession == null;
193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        assert mMediaCrypto == null;
194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
195f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // Open media crypto session.
196a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        mMediaCryptoSession = openSession();
197a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        if (mMediaCryptoSession == null) {
198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            Log.e(TAG, "Cannot create MediaCrypto Session.");
199f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            return false;
200f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
201a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        Log.d(TAG, "MediaCrypto Session created: " + mMediaCryptoSession);
202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
203f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // Create MediaCrypto object.
204424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        try {
205424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            if (MediaCrypto.isCryptoSchemeSupported(mSchemeUUID)) {
206a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                final byte[] mediaCryptoSession = mMediaCryptoSession.array();
207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                mMediaCrypto = new MediaCrypto(mSchemeUUID, mediaCryptoSession);
208a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                assert mMediaCrypto != null;
209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                Log.d(TAG, "MediaCrypto successfully created!");
210a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                mSessionIds.put(mMediaCryptoSession, INVALID_SESSION_ID);
211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                // Notify the native code that MediaCrypto is ready.
212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                nativeOnMediaCryptoReady(mNativeMediaDrmBridge);
213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                return true;
214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            } else {
215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                Log.e(TAG, "Cannot create MediaCrypto for unsupported scheme.");
216424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            }
217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        } catch (android.media.MediaCryptoException e) {
218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            Log.e(TAG, "Cannot create MediaCrypto", e);
219424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        }
220424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        release();
222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        return false;
223424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
224424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
225424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    /**
226a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     * Open a new session..
2273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     *
228a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     * @return the session opened. Returns null if unexpected error happened.
2293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     */
230a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private ByteBuffer openSession() throws android.media.NotProvisionedException {
231a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        assert mMediaDrm != null;
232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        try {
233a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            byte[] session = mMediaDrm.openSession();
234a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            // ByteBuffer.wrap() is backed by the byte[]. Make a clone here in
235a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            // case the underlying byte[] is modified.
236a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            return ByteBuffer.wrap(session.clone());
237f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        } catch (java.lang.RuntimeException e) {  // TODO(xhwang): Drop this?
238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            Log.e(TAG, "Cannot open a new session", e);
239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            release();
240a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            return null;
2412f22f038970e0d1927c41b04bbf5589bd12c5316Torne (Richard Coles)        } catch (android.media.NotProvisionedException e) {
2422f22f038970e0d1927c41b04bbf5589bd12c5316Torne (Richard Coles)            // Throw NotProvisionedException so that we can startProvisioning().
2432f22f038970e0d1927c41b04bbf5589bd12c5316Torne (Richard Coles)            throw e;
2442f22f038970e0d1927c41b04bbf5589bd12c5316Torne (Richard Coles)        } catch (android.media.MediaDrmException e) {
2452f22f038970e0d1927c41b04bbf5589bd12c5316Torne (Richard Coles)            // Other MediaDrmExceptions (e.g. ResourceBusyException) are not
2462f22f038970e0d1927c41b04bbf5589bd12c5316Torne (Richard Coles)            // recoverable.
2472f22f038970e0d1927c41b04bbf5589bd12c5316Torne (Richard Coles)            Log.e(TAG, "Cannot open a new session", e);
2482f22f038970e0d1927c41b04bbf5589bd12c5316Torne (Richard Coles)            release();
2492f22f038970e0d1927c41b04bbf5589bd12c5316Torne (Richard Coles)            return null;
250424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        }
251f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
252424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
253f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    /**
254f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     * Close a session.
255f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     *
256a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     * @param session to be closed.
257f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     */
258a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private void closeSession(ByteBuffer session) {
259a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        assert mMediaDrm != null;
260a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        mMediaDrm.closeSession(session.array());
2613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
263d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    /**
264d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     * Check whether the crypto scheme is supported for the given container.
265d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     * If |containerMimeType| is an empty string, we just return whether
266d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     * the crypto scheme is supported.
267d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     *
268d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     * @return true if the container and the crypto scheme is supported, or
269d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     * false otherwise.
270d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     */
27158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    @CalledByNative
27258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static boolean isCryptoSchemeSupported(byte[] schemeUUID, String containerMimeType) {
27358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        UUID cryptoScheme = getUUIDFromBytes(schemeUUID);
274c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
275c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        if (containerMimeType.isEmpty()) {
276c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            return MediaDrm.isCryptoSchemeSupported(cryptoScheme);
277c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        }
278c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
279c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        return MediaDrm.isCryptoSchemeSupported(cryptoScheme, containerMimeType);
28058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
28158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    /**
2833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * Create a new MediaDrmBridge from the crypto scheme UUID.
2843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     *
2853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * @param schemeUUID Crypto scheme UUID.
28658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)     * @param securityLevel Security level to be used.
2873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * @param nativeMediaDrmBridge Native object of this class.
2883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     */
2893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @CalledByNative
290010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    private static MediaDrmBridge create(byte[] schemeUUID, long nativeMediaDrmBridge) {
2913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        UUID cryptoScheme = getUUIDFromBytes(schemeUUID);
29258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        if (cryptoScheme == null || !MediaDrm.isCryptoSchemeSupported(cryptoScheme)) {
29358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            return null;
2943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
29558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        boolean singleSessionMode = false;
297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (Build.VERSION.RELEASE.equals("4.4")) {
298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            singleSessionMode = true;
299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        Log.d(TAG, "MediaDrmBridge uses " +
301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                (singleSessionMode ? "single" : "multiple") + "-session mode.");
302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
303a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        MediaDrmBridge mediaDrmBridge = null;
30458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        try {
305a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            mediaDrmBridge = new MediaDrmBridge(
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                cryptoScheme, nativeMediaDrmBridge, singleSessionMode);
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            Log.d(TAG, "MediaDrmBridge successfully created.");
30858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        } catch (android.media.UnsupportedSchemeException e) {
309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            Log.e(TAG, "Unsupported DRM scheme", e);
31058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        } catch (java.lang.IllegalArgumentException e) {
311f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            Log.e(TAG, "Failed to create MediaDrmBridge", e);
31258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        } catch (java.lang.IllegalStateException e) {
313f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            Log.e(TAG, "Failed to create MediaDrmBridge", e);
31458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        }
31558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
316a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        return mediaDrmBridge;
3173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
3183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    /**
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)     * Set the security level that the MediaDrm object uses.
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)     * This function should be called right after we construct MediaDrmBridge
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)     * and before we make any other calls.
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)     */
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    @CalledByNative
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private boolean setSecurityLevel(String securityLevel) {
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (mMediaDrm == null || mMediaCrypto != null) {
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            return false;
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        String currentSecurityLevel = mMediaDrm.getPropertyString(SECURITY_LEVEL);
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        Log.e(TAG, "Security level: current " + currentSecurityLevel + ", new " + securityLevel);
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (securityLevel.equals(currentSecurityLevel)) {
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            // No need to set the same security level again. This is not just
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            // a shortcut! Setting the same security level actually causes an
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            // exception in MediaDrm!
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            return true;
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        try {
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            mMediaDrm.setPropertyString(SECURITY_LEVEL, securityLevel);
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            return true;
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        } catch (java.lang.IllegalArgumentException e) {
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            Log.e(TAG, "Failed to set security level " + securityLevel, e);
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        } catch (java.lang.IllegalStateException e) {
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            Log.e(TAG, "Failed to set security level " + securityLevel, e);
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        Log.e(TAG, "Security level " + securityLevel + " not supported!");
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return false;
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    /**
353424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * Return the MediaCrypto object if available.
3543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     */
3553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @CalledByNative
3563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private MediaCrypto getMediaCrypto() {
3573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return mMediaCrypto;
3583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
3593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    /**
36168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)     * Reset the device DRM credentials.
36268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)     */
36368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    @CalledByNative
36468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    private void resetDeviceCredentials() {
36568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        mResetDeviceCredentialsPending = true;
36668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        MediaDrm.ProvisionRequest request = mMediaDrm.getProvisionRequest();
36768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        PostRequestTask postTask = new PostRequestTask(request.getData());
36868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        postTask.execute(request.getDefaultUrl());
36968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
37068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
37168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    /**
3723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * Release the MediaDrmBridge object.
3733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     */
3743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @CalledByNative
3753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private void release() {
376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // Do not reset mHandler and mNativeMediaDrmBridge so that we can still
377f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // post KeyError back to native code.
378f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
379a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        mPendingCreateSessionDataQueue.clear();
380a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        mPendingCreateSessionDataQueue = null;
381f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
382a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        for (ByteBuffer session : mSessionIds.keySet()) {
383a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            closeSession(session);
384f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
385f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        mSessionIds.clear();
386f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        mSessionIds = null;
387a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        mSessionMimeTypes.clear();
388a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        mSessionMimeTypes = null;
389f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
390f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // This session was closed in the "for" loop above.
391a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        mMediaCryptoSession = null;
392f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (mMediaCrypto != null) {
3943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            mMediaCrypto.release();
39558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            mMediaCrypto = null;
3963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
397f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
39858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        if (mMediaDrm != null) {
39958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            mMediaDrm.release();
40058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            mMediaDrm = null;
4013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
4023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
4033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    /**
405a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     * Get a key request.
406f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     *
407a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     * @param session Session on which we need to get the key request.
408f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     * @param data Data needed to get the key request.
409f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     * @param mime Mime type to get the key request.
410f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     *
411a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     * @return the key request.
412f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     */
413a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private MediaDrm.KeyRequest getKeyRequest(ByteBuffer session, byte[] data, String mime)
414f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            throws android.media.NotProvisionedException {
415a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        assert mMediaDrm != null;
416a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        assert mMediaCrypto != null;
417a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        assert !mProvisioningPending;
418a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
419a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        HashMap<String, String> optionalParameters = new HashMap<String, String>();
420a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        MediaDrm.KeyRequest request = mMediaDrm.getKeyRequest(
421a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                session.array(), data, mime, MediaDrm.KEY_TYPE_STREAMING, optionalParameters);
422a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        String result = (request != null) ? "successed" : "failed";
423a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        Log.d(TAG, "getKeyRequest " + result + "!");
424a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        return request;
425f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
426f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
427f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    /**
428a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     * Save data to |mPendingCreateSessionDataQueue| so that we can resume the
429a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     * createSession() call later.
430f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     */
431a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private void savePendingCreateSessionData(int sessionId, byte[] initData, String mime) {
432a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        Log.d(TAG, "savePendingCreateSessionData()");
433a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        mPendingCreateSessionDataQueue.offer(
434a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                new PendingCreateSessionData(sessionId, initData, mime));
435f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
436f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
437f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    /**
438a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     * Process all pending createSession() calls synchronously.
439f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     */
440a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private void processPendingCreateSessionData() {
441a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        Log.d(TAG, "processPendingCreateSessionData()");
442a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        assert mMediaDrm != null;
443f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
444a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // Check mMediaDrm != null because error may happen in createSession().
445f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // Check !mProvisioningPending because NotProvisionedException may be
446a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // thrown in createSession().
447a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        while (mMediaDrm != null && !mProvisioningPending &&
448a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                !mPendingCreateSessionDataQueue.isEmpty()) {
449a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            PendingCreateSessionData pendingData = mPendingCreateSessionDataQueue.poll();
450a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            int sessionId = pendingData.sessionId();
451a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            byte[] initData = pendingData.initData();
452a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            String mime = pendingData.mimeType();
453a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            createSession(sessionId, initData, mime);
454f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
455f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
456f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
457f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    /**
458f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     * Process pending operations asynchrnously.
459f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     */
460f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private void resumePendingOperations() {
461f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        mHandler.post(new Runnable(){
462a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            @Override
463f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            public void run() {
464a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                processPendingCreateSessionData();
465f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            }
466f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        });
467f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
468f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
469f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    /**
470a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     * Create a session with |sessionId|, |initData| and |mime|.
471f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     * In multiple session mode, a new session will be open. In single session
472a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     * mode, the mMediaCryptoSession will be used.
4733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     *
474a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     * @param sessionId ID for the session to be created.
4753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * @param initData Data needed to generate the key request.
4763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * @param mime Mime type.
4773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     */
4783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @CalledByNative
479a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private void createSession(int sessionId, byte[] initData, String mime) {
480a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        Log.d(TAG, "createSession()");
481f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (mMediaDrm == null) {
482a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Log.e(TAG, "createSession() called when MediaDrm is null.");
483f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            return;
484f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
485424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
486f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (mProvisioningPending) {
487a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            assert mMediaCrypto == null;
488a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            savePendingCreateSessionData(sessionId, initData, mime);
4893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            return;
4903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
491424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
492f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        boolean newSessionOpened = false;
493a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        ByteBuffer session = null;
494f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        try {
495f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            // Create MediaCrypto if necessary.
496f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            if (mMediaCrypto == null && !createMediaCrypto()) {
497a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)              onSessionError(sessionId);
498a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                return;
499424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            }
500a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            assert mMediaCrypto != null;
501a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            assert mSessionIds.containsKey(mMediaCryptoSession);
502f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
503f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            if (mSingleSessionMode) {
504a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                session = mMediaCryptoSession;
505a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                if (mSessionMimeTypes.get(session) != null &&
506a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        !mSessionMimeTypes.get(session).equals(mime)) {
507f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    Log.e(TAG, "Only one mime type is supported in single session mode.");
508a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    onSessionError(sessionId);
509f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    return;
510f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                }
511f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            } else {
512a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                session = openSession();
513a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                if (session == null) {
514a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    Log.e(TAG, "Cannot open session in createSession().");
515a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    onSessionError(sessionId);
516424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                    return;
517424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                }
518f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                newSessionOpened = true;
519a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                assert !mSessionIds.containsKey(session);
520f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            }
521424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
522a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            MediaDrm.KeyRequest request = null;
523a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            request = getKeyRequest(session, initData, mime);
524a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            if (request == null) {
525a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                if (newSessionOpened) {
526a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    closeSession(session);
527a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                }
528a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                onSessionError(sessionId);
529424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                return;
530424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            }
531424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
532a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            onSessionCreated(sessionId, getWebSessionId(session));
533a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            onSessionMessage(sessionId, request);
534f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            if (newSessionOpened) {
535a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                Log.d(TAG, "createSession(): Session " + getWebSessionId(session) +
536a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        " (" + sessionId + ") created.");
537f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            }
538a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
539a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            mSessionIds.put(session, sessionId);
540a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            mSessionMimeTypes.put(session, mime);
5413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        } catch (android.media.NotProvisionedException e) {
542f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            Log.e(TAG, "Device not provisioned", e);
543f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            if (newSessionOpened) {
544a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                closeSession(session);
545f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            }
546a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            savePendingCreateSessionData(sessionId, initData, mime);
547f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            startProvisioning();
548f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
549f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
550f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
551f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    /**
552f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     * Returns whether |sessionId| is a valid key session, excluding the media
553f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     * crypto session in multi-session mode.
554f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     *
555f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     * @param sessionId Crypto session Id.
556f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     */
557a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private boolean sessionExists(ByteBuffer session) {
558a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        if (mMediaCryptoSession == null) {
559a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            assert mSessionIds.isEmpty();
560f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            Log.e(TAG, "Session doesn't exist because media crypto session is not created.");
561f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            return false;
5623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
563a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        assert mSessionIds.containsKey(mMediaCryptoSession);
564f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
565f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (mSingleSessionMode) {
566a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            return mMediaCryptoSession.equals(session);
567f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
568f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
569a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        return !session.equals(mMediaCryptoSession) && mSessionIds.containsKey(session);
5703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
5713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    /**
5733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * Cancel a key request for a session Id.
5743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     *
575a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     * @param sessionId Reference ID of session to be released.
5763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     */
5773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @CalledByNative
578a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private void releaseSession(int sessionId) {
579a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        Log.d(TAG, "releaseSession(): " + sessionId);
580f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (mMediaDrm == null) {
581a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Log.e(TAG, "releaseSession() called when MediaDrm is null.");
582f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            return;
583f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
584f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
585a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        ByteBuffer session = getSession(sessionId);
586a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        if (session == null) {
587a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Log.e(TAG, "Invalid sessionId in releaseSession.");
588a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            onSessionError(sessionId);
5893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            return;
5903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
591f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
592a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        mMediaDrm.removeKeys(session.array());
593f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
594f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // We don't close the media crypto session in single session mode.
595f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (!mSingleSessionMode) {
596f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            Log.d(TAG, "Session " + sessionId + "closed.");
597a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            closeSession(session);
598a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            mSessionIds.remove(session);
599a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            onSessionClosed(sessionId);
6003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
6013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
6023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
6033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    /**
6043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * Add a key for a session Id.
6053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     *
606a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     * @param sessionId Reference ID of session to be updated.
6073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * @param key Response data from the server.
6083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     */
6093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @CalledByNative
610a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private void updateSession(int sessionId, byte[] key) {
611a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        Log.d(TAG, "updateSession(): " + sessionId);
612f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (mMediaDrm == null) {
613a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Log.e(TAG, "updateSession() called when MediaDrm is null.");
6143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            return;
6153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
616f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
617f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // TODO(xhwang): We should be able to DCHECK this when WD EME is implemented.
618a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        ByteBuffer session = getSession(sessionId);
619a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        if (!sessionExists(session)) {
620a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Log.e(TAG, "Invalid session in updateSession.");
621a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            onSessionError(sessionId);
622f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            return;
623f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
624f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
6253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        try {
626424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            try {
627a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                mMediaDrm.provideKeyResponse(session.array(), key);
628424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            } catch (java.lang.IllegalStateException e) {
629424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                // This is not really an exception. Some error code are incorrectly
630424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                // reported as an exception.
631424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                // TODO(qinmin): remove this exception catch when b/10495563 is fixed.
632f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                Log.e(TAG, "Exception intentionally caught when calling provideKeyResponse()", e);
633424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            }
634a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            onSessionReady(sessionId);
635f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            Log.d(TAG, "Key successfully added for session " + sessionId);
6363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            return;
6373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        } catch (android.media.NotProvisionedException e) {
638a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            // TODO(xhwang): Should we handle this?
639f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            Log.e(TAG, "failed to provide key response", e);
6403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        } catch (android.media.DeniedByServerException e) {
641f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            Log.e(TAG, "failed to provide key response", e);
6423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
643a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        onSessionError(sessionId);
644f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        release();
6453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
6463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
6473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    /**
648424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * Return the security level of this DRM object.
649424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     */
650424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    @CalledByNative
651424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private String getSecurityLevel() {
652f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (mMediaDrm == null) {
653f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            Log.e(TAG, "getSecurityLevel() called when MediaDrm is null.");
654f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            return null;
655f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
656424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        return mMediaDrm.getPropertyString("securityLevel");
657424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
658424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
659f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private void startProvisioning() {
660f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        Log.d(TAG, "startProvisioning");
661a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        assert mMediaDrm != null;
662a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        assert !mProvisioningPending;
663f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        mProvisioningPending = true;
664f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        MediaDrm.ProvisionRequest request = mMediaDrm.getProvisionRequest();
665f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        PostRequestTask postTask = new PostRequestTask(request.getData());
666f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        postTask.execute(request.getDefaultUrl());
667f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
668f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
669424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    /**
6703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * Called when the provision response is received.
6713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     *
6723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * @param response Response data from the provision server.
6733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     */
6743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private void onProvisionResponse(byte[] response) {
67558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        Log.d(TAG, "onProvisionResponse()");
676a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        assert mProvisioningPending;
677f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        mProvisioningPending = false;
678424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
67968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        // If |mMediaDrm| is released, there is no need to callback native.
68068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        if (mMediaDrm == null) {
68168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            return;
68268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        }
68368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
68468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        boolean success = provideProvisionResponse(response);
685f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
68668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        if (mResetDeviceCredentialsPending) {
68768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            nativeOnResetDeviceCredentialsCompleted(mNativeMediaDrmBridge, success);
68868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            mResetDeviceCredentialsPending = false;
68968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        }
69068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
691f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (success) {
692f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            resumePendingOperations();
69368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        }
69468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
69568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
69668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    /**
69768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)     * Provide the provisioning response to MediaDrm.
69868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)     * @returns false if the response is invalid or on error, true otherwise.
69968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)     */
70068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    boolean provideProvisionResponse(byte[] response) {
701424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        if (response == null || response.length == 0) {
702424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            Log.e(TAG, "Invalid provision response.");
70368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            return false;
704424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        }
705424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
7063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        try {
7073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            mMediaDrm.provideProvisionResponse(response);
708f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            return true;
7093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        } catch (android.media.DeniedByServerException e) {
710f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            Log.e(TAG, "failed to provide provision response", e);
71158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        } catch (java.lang.IllegalStateException e) {
712f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            Log.e(TAG, "failed to provide provision response", e);
713424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        }
714f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        return false;
715f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
716424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
717a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private void onSessionCreated(final int sessionId, final String webSessionId) {
718f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        mHandler.post(new Runnable(){
719a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            @Override
720f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            public void run() {
721a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                nativeOnSessionCreated(mNativeMediaDrmBridge, sessionId, webSessionId);
722f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            }
723f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        });
724f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
725f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
726a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private void onSessionMessage(final int sessionId, final MediaDrm.KeyRequest request) {
727a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        mHandler.post(new Runnable(){
728a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            @Override
729a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            public void run() {
730a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                nativeOnSessionMessage(mNativeMediaDrmBridge, sessionId,
731a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        request.getData(), request.getDefaultUrl());
732a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            }
733a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        });
734a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
735a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
736a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private void onSessionReady(final int sessionId) {
737f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        mHandler.post(new Runnable() {
738a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            @Override
739f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            public void run() {
740a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                nativeOnSessionReady(mNativeMediaDrmBridge, sessionId);
741f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            }
742f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        });
7433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
7443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
745a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private void onSessionClosed(final int sessionId) {
746a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        mHandler.post(new Runnable() {
747a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            @Override
748a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            public void run() {
749a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                nativeOnSessionClosed(mNativeMediaDrmBridge, sessionId);
750a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            }
751a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        });
752a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
753a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
754a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private void onSessionError(final int sessionId) {
7553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        // TODO(qinmin): pass the error code to native.
756424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        mHandler.post(new Runnable() {
757a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            @Override
7583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            public void run() {
759a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                nativeOnSessionError(mNativeMediaDrmBridge, sessionId);
7603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            }
7613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        });
7623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
7633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
764a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private String getWebSessionId(ByteBuffer session) {
765a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        String webSessionId = null;
766f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        try {
767a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            webSessionId = new String(session.array(), "UTF-8");
768f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        } catch (java.io.UnsupportedEncodingException e) {
769a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Log.e(TAG, "getWebSessionId failed", e);
770f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        } catch (java.lang.NullPointerException e) {
771a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Log.e(TAG, "getWebSessionId failed", e);
772f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
773a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        return webSessionId;
774f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
775f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
7763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private class MediaDrmListener implements MediaDrm.OnEventListener {
7773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        @Override
778a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        public void onEvent(
779a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                MediaDrm mediaDrm, byte[] session_array, int event, int extra, byte[] data) {
780a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            if (session_array == null) {
781a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                Log.e(TAG, "MediaDrmListener: Null session.");
782a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                return;
783a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            }
784a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            ByteBuffer session = ByteBuffer.wrap(session_array);
785a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            if (!sessionExists(session)) {
786a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                Log.e(TAG, "MediaDrmListener: Invalid session.");
787a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                return;
788a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            }
789a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            Integer sessionId = mSessionIds.get(session);
790a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            if (sessionId == null || sessionId == INVALID_SESSION_ID) {
791a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                Log.e(TAG, "MediaDrmListener: Invalid session ID.");
792a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                return;
793a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            }
7943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            switch(event) {
7953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                case MediaDrm.EVENT_PROVISION_REQUIRED:
796f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    Log.d(TAG, "MediaDrm.EVENT_PROVISION_REQUIRED");
7973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    break;
7983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                case MediaDrm.EVENT_KEY_REQUIRED:
799f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    Log.d(TAG, "MediaDrm.EVENT_KEY_REQUIRED");
800a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    if (mProvisioningPending) {
801a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        return;
802a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    }
803a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    String mime = mSessionMimeTypes.get(session);
804a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    MediaDrm.KeyRequest request = null;
805a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    try {
806a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        request = getKeyRequest(session, data, mime);
807a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    } catch (android.media.NotProvisionedException e) {
808a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        Log.e(TAG, "Device not provisioned", e);
809a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        startProvisioning();
810a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        return;
811a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    }
812a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    if (request != null) {
813a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        onSessionMessage(sessionId, request);
814a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    } else {
815a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        onSessionError(sessionId);
816f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    }
8173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    break;
8183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                case MediaDrm.EVENT_KEY_EXPIRED:
819f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    Log.d(TAG, "MediaDrm.EVENT_KEY_EXPIRED");
820a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    onSessionError(sessionId);
8213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    break;
8223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                case MediaDrm.EVENT_VENDOR_DEFINED:
823f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    Log.d(TAG, "MediaDrm.EVENT_VENDOR_DEFINED");
824a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    assert false;  // Should never happen.
8253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    break;
8263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                default:
827a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    Log.e(TAG, "Invalid DRM event " + event);
8283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    return;
8293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            }
8303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
8313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
8323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private class PostRequestTask extends AsyncTask<String, Void, Void> {
8343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        private static final String TAG = "PostRequestTask";
8353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        private byte[] mDrmRequest;
8373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        private byte[] mResponseBody;
8383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        public PostRequestTask(byte[] drmRequest) {
8403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            mDrmRequest = drmRequest;
8413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
8423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        @Override
8443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        protected Void doInBackground(String... urls) {
8453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            mResponseBody = postRequest(urls[0], mDrmRequest);
8463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            if (mResponseBody != null) {
8473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                Log.d(TAG, "response length=" + mResponseBody.length);
8483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            }
8493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            return null;
8503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
8513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        private byte[] postRequest(String url, byte[] drmRequest) {
8533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            HttpClient httpClient = new DefaultHttpClient();
8543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            HttpPost httpPost = new HttpPost(url + "&signedRequest=" + new String(drmRequest));
8553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            Log.d(TAG, "PostRequest:" + httpPost.getRequestLine());
8573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            try {
8583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                // Add data
8593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                httpPost.setHeader("Accept", "*/*");
8603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                httpPost.setHeader("User-Agent", "Widevine CDM v1.0");
8613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                httpPost.setHeader("Content-Type", "application/json");
8623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                // Execute HTTP Post Request
8643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                HttpResponse response = httpClient.execute(httpPost);
8653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                byte[] responseBody;
8673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                int responseCode = response.getStatusLine().getStatusCode();
8683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                if (responseCode == 200) {
8693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    responseBody = EntityUtils.toByteArray(response.getEntity());
8703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                } else {
8713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    Log.d(TAG, "Server returned HTTP error code " + responseCode);
8723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    return null;
8733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                }
8743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                return responseBody;
8753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            } catch (ClientProtocolException e) {
8763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                e.printStackTrace();
8773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            } catch (IOException e) {
8783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                e.printStackTrace();
8793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            }
8803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            return null;
8813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
8823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        @Override
8843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        protected void onPostExecute(Void v) {
8853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            onProvisionResponse(mResponseBody);
8863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
8873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
8883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    public static void addKeySystemUuidMapping(String keySystem, UUID uuid) {
8906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        ByteBuffer uuidBuffer = ByteBuffer.allocateDirect(16);
8916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        // MSB (byte) should be positioned at the first element.
8926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        uuidBuffer.order(ByteOrder.BIG_ENDIAN);
8936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        uuidBuffer.putLong(uuid.getMostSignificantBits());
8946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        uuidBuffer.putLong(uuid.getLeastSignificantBits());
8956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        nativeAddKeySystemUuidMapping(keySystem, uuidBuffer);
8966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    }
8976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
898f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private native void nativeOnMediaCryptoReady(long nativeMediaDrmBridge);
899424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
900a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private native void nativeOnSessionCreated(long nativeMediaDrmBridge, int sessionId,
901a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                               String webSessionId);
902a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
903a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private native void nativeOnSessionMessage(long nativeMediaDrmBridge, int sessionId,
904a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                               byte[] message, String destinationUrl);
905a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
906a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private native void nativeOnSessionReady(long nativeMediaDrmBridge, int sessionId);
9073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
908a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private native void nativeOnSessionClosed(long nativeMediaDrmBridge, int sessionId);
9093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
910a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private native void nativeOnSessionError(long nativeMediaDrmBridge, int sessionId);
91168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
91268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    private native void nativeOnResetDeviceCredentialsCompleted(
913f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            long nativeMediaDrmBridge, boolean success);
9146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
9156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    private static native void nativeAddKeySystemUuidMapping(String keySystem, ByteBuffer uuid);
9163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
917