/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package android.media.drmframework.cts;

import android.media.MediaCodecInfo.CodecCapabilities;
import android.media.MediaDrm;
import android.media.MediaDrm.KeyStatus;
import android.media.MediaDrm.MediaDrmStateException;
import android.media.MediaDrmException;
import android.media.MediaFormat;
import android.media.NotProvisionedException;
import android.media.ResourceBusyException;
import android.media.UnsupportedSchemeException;
import android.media.cts.AudioManagerStub;
import android.media.cts.AudioManagerStubHelper;
import android.media.cts.CodecState;
import android.media.cts.ConnectionStatus;
import android.media.cts.IConnectionStatus;
import android.media.cts.InputSurface;
import android.media.cts.InputSurfaceInterface;
import android.media.cts.MediaCodecClearKeyPlayer;
import android.media.cts.MediaCodecPlayerTestBase;
import android.media.cts.MediaCodecWrapper;
import android.media.cts.MediaTimeProvider;
import android.media.cts.MediaStubActivity;
import android.media.cts.NdkInputSurface;
import android.media.cts.NdkMediaCodec;
import android.media.cts.TestUtils.Monitor;
import android.media.cts.Utils;
import android.net.Uri;
import android.os.Build;
import android.os.Looper;
import android.platform.test.annotations.Presubmit;
import android.util.Base64;
import android.util.Log;

import android.view.Surface;

import com.android.compatibility.common.util.ApiLevelUtil;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.Vector;

import androidx.annotation.NonNull;
import androidx.test.filters.SdkSuppress;


/**
 * Tests of MediaPlayer streaming capabilities.
 */
public class MediaDrmClearkeyTest extends MediaCodecPlayerTestBase<MediaStubActivity> {

    private static final String TAG = MediaDrmClearkeyTest.class.getSimpleName();

    // Add additional keys here if the content has more keys.
    private static final byte[] CLEAR_KEY_CENC = {
            (byte)0x3f, (byte)0x0a, (byte)0x33, (byte)0xf3, (byte)0x40, (byte)0x98, (byte)0xb9, (byte)0xe2,
            (byte)0x2b, (byte)0xc0, (byte)0x78, (byte)0xe0, (byte)0xa1, (byte)0xb5, (byte)0xe8, (byte)0x54 };

    private static final byte[] CLEAR_KEY_WEBM = "_CLEAR_KEY_WEBM_".getBytes();

    private static final int NUMBER_OF_SECURE_STOPS = 10;
    private static final int VIDEO_WIDTH_CENC = 1280;
    private static final int VIDEO_HEIGHT_CENC = 720;
    private static final int VIDEO_WIDTH_WEBM = 352;
    private static final int VIDEO_HEIGHT_WEBM = 288;
    private static final int VIDEO_WIDTH_MPEG2TS = 320;
    private static final int VIDEO_HEIGHT_MPEG2TS = 240;
    private static final String MIME_VIDEO_AVC = MediaFormat.MIMETYPE_VIDEO_AVC;
    private static final String MIME_VIDEO_VP8 = MediaFormat.MIMETYPE_VIDEO_VP8;

    // Property Keys
    private static final String ALGORITHMS_PROPERTY_KEY = MediaDrm.PROPERTY_ALGORITHMS;
    private static final String DESCRIPTION_PROPERTY_KEY = MediaDrm.PROPERTY_DESCRIPTION;
    private static final String DEVICEID_PROPERTY_KEY = "deviceId";
    private static final String INVALID_PROPERTY_KEY = "invalid property key";
    private static final String LISTENER_TEST_SUPPORT_PROPERTY_KEY = "listenerTestSupport";
    private static final String VENDOR_PROPERTY_KEY = MediaDrm.PROPERTY_VENDOR;
    private static final String VERSION_PROPERTY_KEY = MediaDrm.PROPERTY_VERSION;

    // Error message
    private static final String ERR_MSG_CRYPTO_SCHEME_NOT_SUPPORTED = "Crypto scheme is not supported";

    private static final String CENC_AUDIO_PATH = "/clear/h264/llama/llama_aac_audio.mp4";
    private static final String CENC_VIDEO_PATH = "/clearkey/llama_h264_main_720p_8000.mp4";
    private static final Uri WEBM_URL = Uri.parse(
            "android.resource://android.media.drmframework.cts/" + R.raw.video_320x240_webm_vp8_800kbps_30fps_vorbis_stereo_128kbps_44100hz_crypt);
    private static final Uri MPEG2TS_SCRAMBLED_URL = Uri.parse(
            "android.resource://android.media.drmframework.cts/" + R.raw.segment000001_scrambled);
    private static final Uri MPEG2TS_CLEAR_URL = Uri.parse(
            "android.resource://android.media.drmframework.cts/" + R.raw.segment000001);

    private static final UUID COMMON_PSSH_SCHEME_UUID =
            new UUID(0x1077efecc0b24d02L, 0xace33c1e52e2fb4bL);
    private static final UUID CLEARKEY_SCHEME_UUID =
            new UUID(0xe2719d58a985b3c9L, 0x781ab030af78d30eL);

    private byte[] mDrmInitData;
    private byte[] mKeySetId;
    private byte[] mSessionId;
    private Monitor mSessionMonitor = new Monitor();
    private Looper mLooper;
    private MediaDrm mDrm = null;
    private final Object mLock = new Object();
    private boolean mEventListenerCalled;
    private boolean mExpirationUpdateReceived;
    private boolean mLostStateReceived;

    private static boolean sIsAtLeastS = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S);

    public MediaDrmClearkeyTest() {
        super(MediaStubActivity.class);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        if (false == deviceHasMediaDrm()) {
            tearDown();
        }
    }

    @Override
    protected void tearDown() throws Exception {
        super.tearDown();
    }

    private boolean deviceHasMediaDrm() {
        // ClearKey is introduced after KitKat.
        if (ApiLevelUtil.isAtMost(android.os.Build.VERSION_CODES.KITKAT)) {
            return false;
        }
        return true;
    }

    /**
     * Extracts key ids from the pssh blob returned by getKeyRequest() and
     * places it in keyIds.
     * keyRequestBlob format (section 5.1.3.1):
     * https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#clear-key
     *
     * @return size of keyIds vector that contains the key ids, 0 for error
     */
    private static int getKeyIds(byte[] keyRequestBlob, Vector<String> keyIds) {
        if (0 == keyRequestBlob.length || keyIds == null)
            return 0;

        String jsonLicenseRequest = new String(keyRequestBlob);
        keyIds.clear();

        try {
            JSONObject license = new JSONObject(jsonLicenseRequest);
            final JSONArray ids = license.getJSONArray("kids");
            for (int i = 0; i < ids.length(); ++i) {
                keyIds.add(ids.getString(i));
            }
        } catch (JSONException e) {
            Log.e(TAG, "Invalid JSON license = " + jsonLicenseRequest);
            return 0;
        }
        return keyIds.size();
    }

    /**
     * Creates the JSON Web Key string.
     *
     * @return JSON Web Key string.
     */
    private static String createJsonWebKeySet(
            Vector<String> keyIds, Vector<String> keys, int keyType) {
        String jwkSet = "{\"keys\":[";
        for (int i = 0; i < keyIds.size(); ++i) {
            String id = new String(keyIds.get(i).getBytes(Charset.forName("UTF-8")));
            String key = new String(keys.get(i).getBytes(Charset.forName("UTF-8")));

            jwkSet += "{\"kty\":\"oct\",\"kid\":\"" + id +
                    "\",\"k\":\"" + key + "\"}";
        }
        jwkSet += "], \"type\":";
        if (keyType == MediaDrm.KEY_TYPE_OFFLINE || keyType == MediaDrm.KEY_TYPE_RELEASE) {
            jwkSet += "\"persistent-license\" }";
        } else {
            jwkSet += "\"temporary\" }";
        }
        return jwkSet;
    }

    /**
     * Retrieves clear key ids from getKeyRequest(), create JSON Web Key
     * set and send it to the CDM via provideKeyResponse().
     *
     * @return key set ID
     */
    public static byte[] retrieveKeys(MediaDrm drm, String initDataType,
            byte[] sessionId, byte[] drmInitData, int keyType, byte[][] clearKeyIds) {
        MediaDrm.KeyRequest drmRequest = null;
        try {
            drmRequest = drm.getKeyRequest(sessionId, drmInitData, initDataType,
                    keyType, null);
        } catch (Exception e) {
            e.printStackTrace();
            Log.i(TAG, "Failed to get key request: " + e.toString());
        }
        if (drmRequest == null) {
            Log.e(TAG, "Failed getKeyRequest");
            return null;
        }

        Vector<String> keyIds = new Vector<String>();
        if (0 == getKeyIds(drmRequest.getData(), keyIds)) {
            Log.e(TAG, "No key ids found in initData");
            return null;
        }

        if (clearKeyIds.length != keyIds.size()) {
            Log.e(TAG, "Mismatch number of key ids and keys: ids=" +
                    keyIds.size() + ", keys=" + clearKeyIds.length);
            return null;
        }

        // Base64 encodes clearkeys. Keys are known to the application.
        Vector<String> keys = new Vector<String>();
        for (int i = 0; i < clearKeyIds.length; ++i) {
            String clearKey = Base64.encodeToString(clearKeyIds[i],
                    Base64.NO_PADDING | Base64.NO_WRAP);
            keys.add(clearKey);
        }

        String jwkSet = createJsonWebKeySet(keyIds, keys, keyType);
        byte[] jsonResponse = jwkSet.getBytes(Charset.forName("UTF-8"));

        try {
            try {
                return drm.provideKeyResponse(sessionId, jsonResponse);
            } catch (IllegalStateException e) {
                Log.e(TAG, "Failed to provide key response: " + e.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "Failed to provide key response: " + e.toString());
        }
        return null;
    }

    /**
     * Retrieves clear key ids from getKeyRequest(), create JSON Web Key
     * set and send it to the CDM via provideKeyResponse().
     */
    private void getKeys(MediaDrm drm, String initDataType,
            byte[] sessionId, byte[] drmInitData, int keyType, byte[][] clearKeyIds) {
        mKeySetId = retrieveKeys(drm, initDataType, sessionId, drmInitData, keyType, clearKeyIds);
    }

    private @NonNull MediaDrm startDrm(final byte[][] clearKeyIds, final String initDataType,
                                       final UUID drmSchemeUuid, int keyType) {
        if (!MediaDrm.isCryptoSchemeSupported(drmSchemeUuid)) {
            throw new Error(ERR_MSG_CRYPTO_SCHEME_NOT_SUPPORTED);
        }

        new Thread() {
            @Override
            public void run() {
                if (mDrm != null) {
                    Log.e(TAG, "Failed to startDrm: already started");
                    return;
                }
                // Set up a looper to handle events
                Looper.prepare();

                // Save the looper so that we can terminate this thread
                // after we are done with it.
                mLooper = Looper.myLooper();

                try {
                    mDrm = new MediaDrm(drmSchemeUuid);
                } catch (MediaDrmException e) {
                    Log.e(TAG, "Failed to create MediaDrm: " + e.getMessage());
                    return;
                }

                synchronized(mLock) {
                    mDrm.setOnEventListener(new MediaDrm.OnEventListener() {
                            @Override
                            public void onEvent(MediaDrm md, byte[] sid, int event,
                                    int extra, byte[] data) {
                                if (md != mDrm) {
                                    Log.e(TAG, "onEvent callback: drm object mismatch");
                                    return;
                                } else if (!Arrays.equals(mSessionId, sid)) {
                                    Log.e(TAG, "onEvent callback: sessionId mismatch: |" +
                                            Arrays.toString(mSessionId) + "| vs |" + Arrays.toString(sid) + "|");
                                    return;
                                }

                                mEventListenerCalled = true;
                                if (event == MediaDrm.EVENT_PROVISION_REQUIRED) {
                                    Log.i(TAG, "MediaDrm event: Provision required");
                                } else if (event == MediaDrm.EVENT_KEY_REQUIRED) {
                                    Log.i(TAG, "MediaDrm event: Key required");
                                    getKeys(mDrm, initDataType, mSessionId, mDrmInitData,
                                            keyType, clearKeyIds);
                                } else if (event == MediaDrm.EVENT_KEY_EXPIRED) {
                                    Log.i(TAG, "MediaDrm event: Key expired");
                                    getKeys(mDrm, initDataType, mSessionId, mDrmInitData,
                                            keyType, clearKeyIds);
                                } else if (event == MediaDrm.EVENT_VENDOR_DEFINED) {
                                    Log.i(TAG, "MediaDrm event: Vendor defined");
                                } else if (event == MediaDrm.EVENT_SESSION_RECLAIMED) {
                                    Log.i(TAG, "MediaDrm event: Session reclaimed");
                                } else {
                                    Log.e(TAG, "MediaDrm event not supported: " + event);
                                }
                            }
                        });
                    mDrm.setOnExpirationUpdateListener(new MediaDrm.OnExpirationUpdateListener() {
                            @Override
                            public void onExpirationUpdate(MediaDrm md, byte[] sid, long expirationTime) {
                                if (md != mDrm) {
                                    Log.e(TAG, "onExpirationUpdate callback: drm object mismatch");
                                } else if (!Arrays.equals(mSessionId, sid)) {
                                    Log.e(TAG, "onExpirationUpdate callback: sessionId mismatch: |" +
                                            Arrays.toString(mSessionId) + "| vs |" + Arrays.toString(sid) + "|");
                                } else {
                                    mExpirationUpdateReceived = true;
                                }
                            }
                        }, null);
                    mDrm.setOnSessionLostStateListener(new MediaDrm.OnSessionLostStateListener() {
                            @Override
                            public void onSessionLostState(MediaDrm md, byte[] sid) {
                                if (md != mDrm) {
                                    Log.e(TAG, "onSessionLostState callback: drm object mismatch");
                                } else if (!Arrays.equals(mSessionId, sid)) {
                                    Log.e(TAG, "onSessionLostState callback: sessionId mismatch: |" +
                                            Arrays.toString(mSessionId) + "| vs |" + Arrays.toString(sid) + "|");
                                } else {
                                    mLostStateReceived = true;
                                }
                            }
                        }, null);
                    mDrm.setOnKeyStatusChangeListener(new MediaDrm.OnKeyStatusChangeListener() {
                            @Override
                            public void onKeyStatusChange(MediaDrm md, byte[] sessionId,
                                    List<KeyStatus> keyInformation, boolean hasNewUsableKey) {
                                Log.d(TAG, "onKeyStatusChange");
                                assertTrue(md == mDrm);
                                assertTrue(Arrays.equals(sessionId, mSessionId));
                                mSessionMonitor.signal();
                                assertTrue(hasNewUsableKey);

                                assertEquals(3, keyInformation.size());
                                KeyStatus keyStatus = keyInformation.get(0);
                                assertTrue(Arrays.equals(keyStatus.getKeyId(), new byte[] {0xa, 0xb, 0xc}));
                                assertTrue(keyStatus.getStatusCode() == MediaDrm.KeyStatus.STATUS_USABLE);
                                keyStatus = keyInformation.get(1);
                                assertTrue(Arrays.equals(keyStatus.getKeyId(), new byte[] {0xd, 0xe, 0xf}));
                                assertTrue(keyStatus.getStatusCode() == MediaDrm.KeyStatus.STATUS_EXPIRED);
                                keyStatus = keyInformation.get(2);
                                assertTrue(Arrays.equals(keyStatus.getKeyId(), new byte[] {0x0, 0x1, 0x2}));
                                assertTrue(keyStatus.getStatusCode() == MediaDrm.KeyStatus.STATUS_USABLE_IN_FUTURE);
                            }
                        }, null);

                    mLock.notify();
                }
                Looper.loop();  // Blocks forever until Looper.quit() is called.
            }
        }.start();

        // wait for mDrm to be created
        synchronized(mLock) {
            try {
                mLock.wait(1000);
            } catch (Exception e) {
            }
        }
        return mDrm;
    }

    private void stopDrm(MediaDrm drm) {
        if (drm != mDrm) {
            Log.e(TAG, "invalid drm specified in stopDrm");
        }
        mLooper.quit();
        mDrm.close();
        mDrm = null;
    }

    private @NonNull byte[] openSession(MediaDrm drm) {
        byte[] mSessionId = null;
        boolean mRetryOpen;
        do {
            try {
                mRetryOpen = false;
                mSessionId = drm.openSession();
            } catch (Exception e) {
                mRetryOpen = true;
            }
        } while (mRetryOpen);
        return mSessionId;
    }

    private void closeSession(MediaDrm drm, byte[] sessionId) {
        drm.closeSession(sessionId);
    }

    /**
     * Tests clear key system playback.
     */
    private void testClearKeyPlayback(
            UUID drmSchemeUuid,
            String videoMime, String[] videoFeatures,
            String initDataType, byte[][] clearKeyIds,
            Uri audioUrl, boolean audioEncrypted,
            Uri videoUrl, boolean videoEncrypted,
            int videoWidth, int videoHeight, boolean scrambled, int keyType) throws Exception {

        if (isWatchDevice()) {
            return;
        }

        MediaDrm drm = null;
        mSessionId = null;
        final boolean hasDrm = !scrambled && drmSchemeUuid != null;
        if (hasDrm) {
            drm = startDrm(clearKeyIds, initDataType, drmSchemeUuid, keyType);
            mSessionId = openSession(drm);
        }

        if (!preparePlayback(videoMime, videoFeatures, audioUrl, audioEncrypted, videoUrl,
                videoEncrypted, videoWidth, videoHeight, scrambled, mSessionId, getSurfaces())) {
            // Allow device to skip test to keep existing behavior.
            // We should throw an exception for new tests.
            return;
        }

        if (hasDrm) {
            mDrmInitData = mMediaCodecPlayer.getDrmInitData();
            getKeys(mDrm, initDataType, mSessionId, mDrmInitData, keyType, clearKeyIds);
        }

        if (hasDrm && keyType == MediaDrm.KEY_TYPE_OFFLINE) {
            closeSession(drm, mSessionId);
            mSessionMonitor.waitForSignal();
            mSessionId = openSession(drm);
            if (mKeySetId.length > 0) {
                drm.restoreKeys(mSessionId, mKeySetId);
            } else {
                closeSession(drm, mSessionId);
                stopDrm(drm);
                throw new Error("Invalid keySetId size for offline license");
            }
        }

        // starts video playback
        playUntilEnd();
        if (hasDrm) {
            closeSession(drm, mSessionId);
            stopDrm(drm);
        }
    }

    /**
     * Tests KEY_TYPE_RELEASE for offline license.
     */
    @Presubmit
    public void testReleaseOfflineLicense() throws Exception {
        if (isWatchDevice()) {
            return;
        }

        byte[][] clearKeyIds = new byte[][] { CLEAR_KEY_CENC };
        mSessionId = null;
        String initDataType = "cenc";

        MediaDrm drm = startDrm(clearKeyIds, initDataType,
                CLEARKEY_SCHEME_UUID, MediaDrm.KEY_TYPE_OFFLINE);
        mSessionId = openSession(drm);

        Uri videoUrl = Uri.parse(Utils.getMediaPath() + CENC_VIDEO_PATH);
        if (false == playbackPreCheck(MIME_VIDEO_AVC,
                new String[] { CodecCapabilities.FEATURE_SecurePlayback }, videoUrl,
                VIDEO_WIDTH_CENC, VIDEO_HEIGHT_CENC)) {
            // retry with unsecure codec
            if (false == playbackPreCheck(MIME_VIDEO_AVC,
                    new String[0], videoUrl,
                    VIDEO_WIDTH_CENC, VIDEO_HEIGHT_CENC)) {
                Log.e(TAG, "Failed playback precheck");
                return;
            }
        }

        mMediaCodecPlayer = new MediaCodecClearKeyPlayer(
                getSurfaces(),
                mSessionId, false /*scrambled */,
                mContext);

        Uri audioUrl = Uri.parse(Utils.getMediaPath() + CENC_AUDIO_PATH);
        mMediaCodecPlayer.setAudioDataSource(audioUrl, null, false);
        mMediaCodecPlayer.setVideoDataSource(videoUrl, null, true);
        mMediaCodecPlayer.start();
        mMediaCodecPlayer.prepare();
        mDrmInitData = mMediaCodecPlayer.getDrmInitData();

        // Create and store the offline license
        getKeys(mDrm, initDataType, mSessionId, mDrmInitData, MediaDrm.KEY_TYPE_OFFLINE,
                clearKeyIds);

        // Verify the offline license is valid
        closeSession(drm, mSessionId);
        mSessionMonitor.waitForSignal();
        mDrm.clearOnKeyStatusChangeListener();
        mSessionId = openSession(drm);
        drm.restoreKeys(mSessionId, mKeySetId);
        closeSession(drm, mSessionId);

        // Release the offline license
        getKeys(mDrm, initDataType, mKeySetId, mDrmInitData, MediaDrm.KEY_TYPE_RELEASE,
                clearKeyIds);

        // Verify restoreKeys will throw an exception if the offline license
        // has already been released
        mSessionId = openSession(drm);
        try {
            drm.restoreKeys(mSessionId, mKeySetId);
        } catch (MediaDrmStateException e) {
            // Expected exception caught, all is good
            return;
        } finally {
            closeSession(drm, mSessionId);
            stopDrm(drm);
        }

        // Did not receive expected exception, throw an Error
        throw new Error("Did not receive expected exception from restoreKeys");
    }

    private boolean queryKeyStatus(@NonNull final MediaDrm drm, @NonNull final byte[] sessionId) {
        final HashMap<String, String> keyStatus = drm.queryKeyStatus(sessionId);
        if (keyStatus.isEmpty()) {
            Log.e(TAG, "queryKeyStatus: empty key status");
            return false;
        }

        final Set<String> keySet = keyStatus.keySet();
        final int numKeys = keySet.size();
        final String[] keys = keySet.toArray(new String[numKeys]);
        for (int i = 0; i < numKeys; ++i) {
            final String key = keys[i];
            Log.i(TAG, "queryKeyStatus: key=" + key + ", value=" + keyStatus.get(key));
        }

        return true;
    }

    @Presubmit
    public void testQueryKeyStatus() throws Exception {
        if (isWatchDevice()) {
            // skip this test on watch because it calls
            // addTrack that requires codec
            return;
        }

        MediaDrm drm = startDrm(new byte[][] { CLEAR_KEY_CENC }, "cenc",
                CLEARKEY_SCHEME_UUID, MediaDrm.KEY_TYPE_STREAMING);

        mSessionId = openSession(drm);

        // Test default key status, should not be defined
        final HashMap<String, String> keyStatus = drm.queryKeyStatus(mSessionId);
        if (!keyStatus.isEmpty()) {
            closeSession(drm, mSessionId);
            stopDrm(drm);
            throw new Error("query default key status failed");
        }

        // Test valid key status
        mMediaCodecPlayer = new MediaCodecClearKeyPlayer(
                getSurfaces(),
                mSessionId, false,
                mContext);
        mMediaCodecPlayer.setAudioDataSource(
                Uri.parse(Utils.getMediaPath() + CENC_AUDIO_PATH), null, false);
        mMediaCodecPlayer.setVideoDataSource(
                Uri.parse(Utils.getMediaPath() + CENC_VIDEO_PATH), null, true);
        mMediaCodecPlayer.start();
        mMediaCodecPlayer.prepare();

        mDrmInitData = mMediaCodecPlayer.getDrmInitData();
        getKeys(drm, "cenc", mSessionId, mDrmInitData, MediaDrm.KEY_TYPE_STREAMING,
                new byte[][] { CLEAR_KEY_CENC });
        boolean success = true;
        if (!queryKeyStatus(drm, mSessionId)) {
            success = false;
        }

        mMediaCodecPlayer.reset();
        closeSession(drm, mSessionId);
        stopDrm(drm);
        if (!success) {
            throw new Error("query key status failed");
        }
    }

    @Presubmit
    public void testOfflineKeyManagement() throws Exception {
        if (isWatchDevice()) {
            // skip this test on watch because it calls
            // addTrack that requires codec
            return;
        }

        MediaDrm drm = startDrm(new byte[][] { CLEAR_KEY_CENC }, "cenc",
                CLEARKEY_SCHEME_UUID, MediaDrm.KEY_TYPE_OFFLINE);

        if (getClearkeyVersion(drm).matches("1.[01]")) {
            Log.i(TAG, "Skipping testsOfflineKeyManagement: clearkey 1.2 required");
            return;
        }

        mSessionId = openSession(drm);

        // Test get offline keys
        mMediaCodecPlayer = new MediaCodecClearKeyPlayer(
                getSurfaces(),
                mSessionId, false,
                mContext);
        mMediaCodecPlayer.setAudioDataSource(
                Uri.parse(Utils.getMediaPath() + CENC_AUDIO_PATH), null, false);
        mMediaCodecPlayer.setVideoDataSource(
                Uri.parse(Utils.getMediaPath() + CENC_VIDEO_PATH), null, true);
        mMediaCodecPlayer.start();
        mMediaCodecPlayer.prepare();

        try {
            mDrmInitData = mMediaCodecPlayer.getDrmInitData();

            List<byte[]> keySetIds = drm.getOfflineLicenseKeySetIds();
            int preCount = keySetIds.size();

            getKeys(drm, "cenc", mSessionId, mDrmInitData, MediaDrm.KEY_TYPE_OFFLINE,
                    new byte[][] { CLEAR_KEY_CENC });

            if (drm.getOfflineLicenseState(mKeySetId) != MediaDrm.OFFLINE_LICENSE_STATE_USABLE) {
                throw new Error("Offline license state is not usable");
            }

            keySetIds = drm.getOfflineLicenseKeySetIds();

            if (keySetIds.size() != preCount + 1) {
                throw new Error("KeySetIds size did not increment");
            }

            boolean found = false;
            for (int i = 0; i < keySetIds.size(); i++) {
                if (Arrays.equals(keySetIds.get(i), mKeySetId)) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                throw new Error("New KeySetId is missing from KeySetIds");
            }

            drm.removeOfflineLicense(mKeySetId);

            keySetIds = drm.getOfflineLicenseKeySetIds();
            if (keySetIds.size() != preCount) {
                throw new Error("KeySetIds size is incorrect");
            }

            found = false;
            for (int i = 0; i < keySetIds.size(); i++) {
                if (Arrays.equals(keySetIds.get(i), mKeySetId)) {
                    found = true;
                    break;
                }
            }

            if (found) {
                throw new Error("New KeySetId is still in from KeySetIds after removal");
            }

            // TODO: after RELEASE is implemented: add offline key, release it
            // get offline key status, check state is inactive
        } finally {
            mMediaCodecPlayer.reset();
            closeSession(drm, mSessionId);
            stopDrm(drm);
        }
    }

    // returns FEATURE_SecurePlayback if device supports secure codec,
    // else returns an empty string for the codec feature
    private String[] determineCodecFeatures(String mime,
            int videoWidth, int videoHeight) {
        String[] codecFeatures = { CodecCapabilities.FEATURE_SecurePlayback };
        if (!isResolutionSupported(MIME_VIDEO_AVC, codecFeatures,
            VIDEO_WIDTH_CENC, VIDEO_HEIGHT_CENC)) {
            // for device that does not support secure codec
            codecFeatures = new String[0];
        }
        return codecFeatures;
    }

    public void testClearKeyPlaybackCenc() throws Exception {
        String[] codecFeatures = determineCodecFeatures(MIME_VIDEO_AVC,
            VIDEO_WIDTH_CENC, VIDEO_HEIGHT_CENC);
        testClearKeyPlayback(
            COMMON_PSSH_SCHEME_UUID,
            // using secure codec even though it is clear key DRM
            MIME_VIDEO_AVC, codecFeatures,
            "cenc", new byte[][] { CLEAR_KEY_CENC },
            Uri.parse(Utils.getMediaPath() + CENC_AUDIO_PATH), false  /* audioEncrypted */,
            Uri.parse(Utils.getMediaPath() + CENC_VIDEO_PATH), true /* videoEncrypted */,
            VIDEO_WIDTH_CENC, VIDEO_HEIGHT_CENC, false /* scrambled */,
            MediaDrm.KEY_TYPE_STREAMING);
    }

    @Presubmit
    public void testClearKeyPlaybackCenc2() throws Exception {
        String[] codecFeatures = determineCodecFeatures(MIME_VIDEO_AVC,
            VIDEO_WIDTH_CENC, VIDEO_HEIGHT_CENC);
        testClearKeyPlayback(
            CLEARKEY_SCHEME_UUID,
            // using secure codec even though it is clear key DRM
            MIME_VIDEO_AVC, codecFeatures,
            "cenc", new byte[][] { CLEAR_KEY_CENC },
            Uri.parse(Utils.getMediaPath() + CENC_AUDIO_PATH), false /* audioEncrypted */ ,
            Uri.parse(Utils.getMediaPath() + CENC_VIDEO_PATH), true /* videoEncrypted */,
            VIDEO_WIDTH_CENC, VIDEO_HEIGHT_CENC, false /* scrambled */,
            MediaDrm.KEY_TYPE_STREAMING);
    }

    @Presubmit
    public void testClearKeyPlaybackOfflineCenc() throws Exception {
        String[] codecFeatures = determineCodecFeatures(MIME_VIDEO_AVC,
            VIDEO_WIDTH_CENC, VIDEO_HEIGHT_CENC);
        testClearKeyPlayback(
                CLEARKEY_SCHEME_UUID,
                // using secure codec even though it is clear key DRM
                MIME_VIDEO_AVC, codecFeatures,
                "cenc", new byte[][] { CLEAR_KEY_CENC },
                Uri.parse(Utils.getMediaPath() + CENC_AUDIO_PATH), false /* audioEncrypted */ ,
                Uri.parse(Utils.getMediaPath() + CENC_VIDEO_PATH), true /* videoEncrypted */,
                VIDEO_WIDTH_CENC, VIDEO_HEIGHT_CENC, false /* scrambled */,
                MediaDrm.KEY_TYPE_OFFLINE);
    }

    public void testClearKeyPlaybackWebm() throws Exception {
        testClearKeyPlayback(
            CLEARKEY_SCHEME_UUID,
            MIME_VIDEO_VP8, new String[0],
            "webm", new byte[][] { CLEAR_KEY_WEBM },
            WEBM_URL, true /* audioEncrypted */,
            WEBM_URL, true /* videoEncrypted */,
            VIDEO_WIDTH_WEBM, VIDEO_HEIGHT_WEBM, false /* scrambled */,
            MediaDrm.KEY_TYPE_STREAMING);
    }

    public void testClearKeyPlaybackMpeg2ts() throws Exception {
        testClearKeyPlayback(
            CLEARKEY_SCHEME_UUID,
            MIME_VIDEO_AVC, new String[0],
            "mpeg2ts", null,
            MPEG2TS_SCRAMBLED_URL, false /* audioEncrypted */,
            MPEG2TS_SCRAMBLED_URL, false /* videoEncrypted */,
            VIDEO_WIDTH_MPEG2TS, VIDEO_HEIGHT_MPEG2TS, true /* scrambled */,
            MediaDrm.KEY_TYPE_STREAMING);
    }

    public void testPlaybackMpeg2ts() throws Exception {
        testClearKeyPlayback(
            CLEARKEY_SCHEME_UUID,
            MIME_VIDEO_AVC, new String[0],
            "mpeg2ts", null,
            MPEG2TS_CLEAR_URL, false /* audioEncrypted */,
            MPEG2TS_CLEAR_URL, false /* videoEncrypted */,
            VIDEO_WIDTH_MPEG2TS, VIDEO_HEIGHT_MPEG2TS, false /* scrambled */,
            MediaDrm.KEY_TYPE_STREAMING);
    }

    private String getStringProperty(final MediaDrm drm,  final String key) {
        String value = "";
        try {
            value = drm.getPropertyString(key);
        } catch (IllegalArgumentException e) {
            // Expected exception for invalid key
            Log.d(TAG, "Expected result: " + e.getMessage());
        } catch (Exception e) {
            throw new Error(e.getMessage() + "-" + key);
        }
        return value;
    }

    private byte[] getByteArrayProperty(final MediaDrm drm,  final String key) {
        byte[] bytes = new byte[0];
        try {
            bytes = drm.getPropertyByteArray(key);
        } catch (IllegalArgumentException e) {
            // Expected exception for invalid key
            Log.d(TAG, "Expected: " + e.getMessage() + " - " + key);
        } catch (Exception e) {
            throw new Error(e.getMessage() + "-" + key);
        }
        return bytes;
    }

    private void setStringProperty(final MediaDrm drm, final String key, final String value) {
        try {
            drm.setPropertyString(key, value);
        } catch (IllegalArgumentException e) {
            // Expected exception for invalid key
            Log.d(TAG, "Expected: " + e.getMessage() + " - " + key);
        } catch (Exception e) {
            throw new Error(e.getMessage() + "-" + key);
        }
    }

    private void setByteArrayProperty(final MediaDrm drm, final String key, final byte[] bytes) {
        try {
            drm.setPropertyByteArray(key, bytes);
        } catch (IllegalArgumentException e) {
            // Expected exception for invalid key
            Log.d(TAG, "Expected: " + e.getMessage() + " - " + key);
        } catch (Exception e) {
            throw new Error(e.getMessage() + "-" + key);
        }
    }

    @Presubmit
    public void testGetProperties() throws Exception {
        if (watchHasNoClearkeySupport()) {
            return;
        }

        MediaDrm drm = startDrm(new byte[][] { CLEAR_KEY_CENC },
                "cenc", CLEARKEY_SCHEME_UUID, MediaDrm.KEY_TYPE_STREAMING);

        try {
            // The following tests will not verify the value we are getting
            // back since it could change in the future.
            final String[] sKeys = {
                    DESCRIPTION_PROPERTY_KEY, LISTENER_TEST_SUPPORT_PROPERTY_KEY,
                    VENDOR_PROPERTY_KEY, VERSION_PROPERTY_KEY};
            String value;
            for (String key : sKeys) {
                value = getStringProperty(drm, key);
                Log.d(TAG, "getPropertyString returns: " + key + ", " + value);
                if (value.isEmpty()) {
                    throw new Error("Failed to get property for: " + key);
                }
            }

            if (cannotHandleGetPropertyByteArray(drm)) {
                Log.i(TAG, "Skipping testGetProperties: byte array properties not implemented "
                        + "on devices launched before P");
                return;
            }

            byte[] bytes = getByteArrayProperty(drm, DEVICEID_PROPERTY_KEY);
            if (0 == bytes.length) {
                throw new Error("Failed to get property for: " + DEVICEID_PROPERTY_KEY);
            }

            // Test with an invalid property key.
            value = getStringProperty(drm, INVALID_PROPERTY_KEY);
            bytes = getByteArrayProperty(drm, INVALID_PROPERTY_KEY);
            if (!value.isEmpty() || 0 != bytes.length) {
                throw new Error("get property failed using an invalid property key");
            }
        } finally {
            stopDrm(drm);
        }
    }

    @Presubmit
    public void testSetProperties() throws Exception {
        if (watchHasNoClearkeySupport()) {
            return;
        }

        MediaDrm drm = startDrm(new byte[][]{CLEAR_KEY_CENC},
                "cenc", CLEARKEY_SCHEME_UUID, MediaDrm.KEY_TYPE_STREAMING);

        try {
            if (cannotHandleSetPropertyString(drm)) {
                Log.i(TAG, "Skipping testSetProperties: set property string not implemented "
                        + "on devices launched before P");
                return;
            }

            // Test setting predefined string property
            // - Save the value to be restored later
            // - Set the property value
            // - Check the value that was set
            // - Restore previous value
            String listenerTestSupport = getStringProperty(drm, LISTENER_TEST_SUPPORT_PROPERTY_KEY);

            setStringProperty(drm, LISTENER_TEST_SUPPORT_PROPERTY_KEY, "testing");

            String value = getStringProperty(drm, LISTENER_TEST_SUPPORT_PROPERTY_KEY);
            if (!value.equals("testing")) {
                throw new Error("Failed to set property: " + LISTENER_TEST_SUPPORT_PROPERTY_KEY);
            }

            setStringProperty(drm, LISTENER_TEST_SUPPORT_PROPERTY_KEY, listenerTestSupport);

            // Test setting immutable properties
            HashMap<String, String> defaultImmutableProperties = new HashMap<String, String>();
            defaultImmutableProperties.put(ALGORITHMS_PROPERTY_KEY,
                    getStringProperty(drm, ALGORITHMS_PROPERTY_KEY));
            defaultImmutableProperties.put(DESCRIPTION_PROPERTY_KEY,
                    getStringProperty(drm, DESCRIPTION_PROPERTY_KEY));
            defaultImmutableProperties.put(VENDOR_PROPERTY_KEY,
                    getStringProperty(drm, VENDOR_PROPERTY_KEY));
            defaultImmutableProperties.put(VERSION_PROPERTY_KEY,
                    getStringProperty(drm, VERSION_PROPERTY_KEY));

            HashMap<String, String> immutableProperties = new HashMap<String, String>();
            immutableProperties.put(ALGORITHMS_PROPERTY_KEY, "brute force");
            immutableProperties.put(DESCRIPTION_PROPERTY_KEY, "testing only");
            immutableProperties.put(VENDOR_PROPERTY_KEY, "my Google");
            immutableProperties.put(VERSION_PROPERTY_KEY, "undefined");

            for (String key : immutableProperties.keySet()) {
                setStringProperty(drm, key, immutableProperties.get(key));
            }

            // Verify the immutable properties have not been set
            for (String key : immutableProperties.keySet()) {
                value = getStringProperty(drm, key);
                if (!defaultImmutableProperties.get(key).equals(getStringProperty(drm, key))) {
                    throw new Error("Immutable property has changed, key=" + key);
                }
            }

            // Test setPropertyByteArray for immutable property
            final byte[] bytes = new byte[] {
                    0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8,
                    0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0};

            final byte[] deviceId = getByteArrayProperty(drm, DEVICEID_PROPERTY_KEY);

            setByteArrayProperty(drm, DEVICEID_PROPERTY_KEY, bytes);

            // Verify deviceId has not changed
            if (!Arrays.equals(deviceId, getByteArrayProperty(drm, DEVICEID_PROPERTY_KEY))) {
                throw new Error("Failed to set byte array for key=" + DEVICEID_PROPERTY_KEY);
            }
        } finally {
            stopDrm(drm);
        }
    }

    private final static int CLEARKEY_MAX_SESSIONS = 10;

    @Presubmit
    public void testGetNumberOfSessions() {
        if (watchHasNoClearkeySupport()) {
            return;
        }

        MediaDrm drm = startDrm(new byte[][] { CLEAR_KEY_CENC },
                "cenc", CLEARKEY_SCHEME_UUID, MediaDrm.KEY_TYPE_STREAMING);

        try {
            if (getClearkeyVersion(drm).equals("1.0")) {
                Log.i(TAG, "Skipping testGetNumberOfSessions: not supported by clearkey 1.0");
                return;
            }

            int maxSessionCount = drm.getMaxSessionCount();
            if (maxSessionCount != CLEARKEY_MAX_SESSIONS) {
                throw new Error("expected max session count to be " +
                        CLEARKEY_MAX_SESSIONS);
            }
            int initialOpenSessionCount = drm.getOpenSessionCount();
            if (initialOpenSessionCount == maxSessionCount) {
                throw new Error("all sessions open, can't do increment test");
            }
            mSessionId = openSession(drm);
            try {
                if (drm.getOpenSessionCount() != initialOpenSessionCount + 1) {
                    throw new Error("openSessionCount didn't increment");
                }
            } finally {
                closeSession(drm, mSessionId);
            }
        } finally {
            stopDrm(drm);
        }
    }

    @Presubmit
    public void testHdcpLevels() {
        if (watchHasNoClearkeySupport()) {
            return;
        }

        MediaDrm drm = null;
        try {
            drm = new MediaDrm(CLEARKEY_SCHEME_UUID);

            if (getClearkeyVersion(drm).equals("1.0")) {
                Log.i(TAG, "Skipping testHdcpLevels: not supported by clearkey 1.0");
                return;
            }

            if (drm.getConnectedHdcpLevel() != MediaDrm.HDCP_NONE) {
                throw new Error("expected connected hdcp level to be HDCP_NONE");
            }

            if (drm.getMaxHdcpLevel() != MediaDrm.HDCP_NO_DIGITAL_OUTPUT) {
                throw new Error("expected max hdcp level to be HDCP_NO_DIGITAL_OUTPUT");
            }
        } catch(Exception e) {
            throw new Error("Unexpected exception ", e);
        } finally {
            if (drm != null) {
                drm.close();
            }
        }
    }

    @Presubmit
    public void testSecurityLevels() {
        if (watchHasNoClearkeySupport()) {
            return;
        }

        MediaDrm drm = null;
        byte[] sessionId = null;
        try {
            drm = new MediaDrm(CLEARKEY_SCHEME_UUID);

            if (getClearkeyVersion(drm).equals("1.0")) {
                Log.i(TAG, "Skipping testSecurityLevels: not supported by clearkey 1.0");
                return;
            }

            sessionId = drm.openSession(MediaDrm.SECURITY_LEVEL_SW_SECURE_CRYPTO);
            if (drm.getSecurityLevel(sessionId) != MediaDrm.SECURITY_LEVEL_SW_SECURE_CRYPTO) {
                throw new Error("expected security level to be SECURITY_LEVEL_SW_SECURE_CRYPTO");
            }
            drm.closeSession(sessionId);
            sessionId = null;

            sessionId = drm.openSession();
            if (drm.getSecurityLevel(sessionId) != MediaDrm.SECURITY_LEVEL_SW_SECURE_CRYPTO) {
                throw new Error("expected security level to be SECURITY_LEVEL_SW_SECURE_CRYPTO");
            }
            drm.closeSession(sessionId);
            sessionId = null;

            try {
                sessionId = drm.openSession(MediaDrm.SECURITY_LEVEL_SW_SECURE_DECODE);
            } catch (IllegalArgumentException e) {
                /* caught expected exception */
            } catch (Exception e) {
                throw new Exception ("did't get expected IllegalArgumentException" +
                        " while opening a session with disallowed security level");
            } finally  {
                if (sessionId != null) {
                    drm.closeSession(sessionId);
                    sessionId = null;
                }
            }
        } catch(Exception e) {
            throw new Error("Unexpected exception ", e);
        } finally  {
            if (sessionId != null) {
                drm.closeSession(sessionId);
            }
            if (drm != null) {
                drm.close();
            }
        }
     }

    @Presubmit
    public void testSecureStop() {
        if (watchHasNoClearkeySupport()) {
            return;
        }

        MediaDrm drm = startDrm(new byte[][] {CLEAR_KEY_CENC}, "cenc",
                CLEARKEY_SCHEME_UUID, MediaDrm.KEY_TYPE_STREAMING);

        byte[] sessionId = null;
        try {
            if (getClearkeyVersion(drm).equals("1.0")) {
                Log.i(TAG, "Skipping testSecureStop: not supported in ClearKey v1.0");
                return;
            }

            drm.removeAllSecureStops();
            Log.d(TAG, "Test getSecureStops from an empty list.");
            List<byte[]> secureStops = drm.getSecureStops();
            assertTrue(secureStops.isEmpty());

            Log.d(TAG, "Test getSecureStopIds from an empty list.");
            List<byte[]> secureStopIds = drm.getSecureStopIds();
            assertTrue(secureStopIds.isEmpty());

            mSessionId = openSession(drm);

            mMediaCodecPlayer = new MediaCodecClearKeyPlayer(
                    getSurfaces(), mSessionId, false, mContext);
            mMediaCodecPlayer.setAudioDataSource(
                    Uri.parse(Utils.getMediaPath() + CENC_AUDIO_PATH), null, false);
            mMediaCodecPlayer.setVideoDataSource(
                    Uri.parse(Utils.getMediaPath() + CENC_VIDEO_PATH), null, true);
            mMediaCodecPlayer.start();
            mMediaCodecPlayer.prepare();
            mDrmInitData = mMediaCodecPlayer.getDrmInitData();

            for (int i = 0; i < NUMBER_OF_SECURE_STOPS; ++i) {
                getKeys(drm, "cenc", mSessionId, mDrmInitData,
                        MediaDrm.KEY_TYPE_STREAMING, new byte[][] {CLEAR_KEY_CENC});
            }
            Log.d(TAG, "Test getSecureStops.");
            secureStops = drm.getSecureStops();
            assertEquals(NUMBER_OF_SECURE_STOPS, secureStops.size());

            Log.d(TAG, "Test getSecureStopIds.");
            secureStopIds = drm.getSecureStopIds();
            assertEquals(NUMBER_OF_SECURE_STOPS, secureStopIds.size());

            Log.d(TAG, "Test getSecureStop using secure stop Ids.");
            for (int i = 0; i < secureStops.size(); ++i) {
                byte[] secureStop = drm.getSecureStop(secureStopIds.get(i));
                assertTrue(Arrays.equals(secureStops.get(i), secureStop));
            }

            Log.d(TAG, "Test removeSecureStop given a secure stop Id.");
            drm.removeSecureStop(secureStopIds.get(NUMBER_OF_SECURE_STOPS - 1));
            secureStops = drm.getSecureStops();
            secureStopIds = drm.getSecureStopIds();
            assertEquals(NUMBER_OF_SECURE_STOPS - 1, secureStops.size());
            assertEquals(NUMBER_OF_SECURE_STOPS - 1, secureStopIds.size());

            Log.d(TAG, "Test releaseSecureStops given a release message.");
            // Simulate server response message by removing
            // every other secure stops to make it interesting.
            List<byte[]> releaseList = new ArrayList<byte[]>();
            int releaseListSize = 0;
            for (int i = 0; i < secureStops.size(); i += 2) {
                byte[] secureStop = secureStops.get(i);
                releaseList.add(secureStop);
                releaseListSize += secureStop.length;
            }

            // ClearKey's release message format (this is a format shared between
            // the server and the drm service).
            // The clearkey implementation expects the message to contain
            // a 4 byte count of the number of fixed length secure stops
            // to follow.
            String count = String.format("%04d", releaseList.size());
            byte[] releaseMessage = new byte[count.length() + releaseListSize];

            byte[] buffer = count.getBytes();
            System.arraycopy(buffer, 0, releaseMessage, 0, count.length());

            int destPosition = count.length();
            for (int i = 0; i < releaseList.size(); ++i) {
                byte[] secureStop = releaseList.get(i);
                int secureStopSize = secureStop.length;
                System.arraycopy(secureStop, 0, releaseMessage, destPosition, secureStopSize);
                destPosition += secureStopSize;
            }

            drm.releaseSecureStops(releaseMessage);
            secureStops = drm.getSecureStops();
            secureStopIds = drm.getSecureStopIds();
            // All odd numbered secure stops are removed in the test,
            // leaving 2nd, 4th, 6th and the 8th element.
            assertEquals((NUMBER_OF_SECURE_STOPS - 1) / 2, secureStops.size());
            assertEquals((NUMBER_OF_SECURE_STOPS - 1 ) / 2, secureStopIds.size());

            Log.d(TAG, "Test removeAllSecureStops.");
            drm.removeAllSecureStops();
            secureStops = drm.getSecureStops();
            assertTrue(secureStops.isEmpty());
            secureStopIds = drm.getSecureStopIds();
            assertTrue(secureStopIds.isEmpty());

            mMediaCodecPlayer.reset();
            closeSession(drm, mSessionId);
        } catch (Exception e) {
            throw new Error("Unexpected exception", e);
        } finally {
            if (sessionId != null) {
                drm.closeSession(sessionId);
            }
            stopDrm(drm);
        }
    }

    /**
     * Test that the framework handles a device returning
     * ::android::hardware::drm@1.2::Status::ERROR_DRM_RESOURCE_CONTENTION.
     * Expected behavior: throws MediaDrm.SessionException with
     * errorCode ERROR_RESOURCE_CONTENTION
     */
    @Presubmit
    public void testResourceContentionError() {

        if (watchHasNoClearkeySupport()) {
            return;
        }

        MediaDrm drm = null;
        boolean gotException = false;

        try {
            drm = new MediaDrm(CLEARKEY_SCHEME_UUID);
            drm.setPropertyString("drmErrorTest", "resourceContention");
            byte[] sessionId = drm.openSession();

            try {
                byte[] ignoredInitData = new byte[] { 1 };
                drm.getKeyRequest(sessionId, ignoredInitData, "cenc", MediaDrm.KEY_TYPE_STREAMING, null);
            } catch (MediaDrm.SessionException e) {
                if (e.getErrorCode() != MediaDrm.SessionException.ERROR_RESOURCE_CONTENTION) {
                    throw new Error("Expected transient ERROR_RESOURCE_CONTENTION");
                }
                if(sIsAtLeastS && !e.isTransient()) {
                        throw new Error("Expected transient ERROR_RESOURCE_CONTENTION");
                }
                gotException = true;
            }
        } catch(Exception e) {
            throw new Error("Unexpected exception ", e);
        } finally {
            if (drm != null) {
                drm.close();
            }
        }
        if (!gotException) {
            throw new Error("Didn't receive expected MediaDrm.SessionException");
        }
    }

    /**
     * Test sendExpirationUpdate and onExpirationUpdateListener
     *
     * Expected behavior: the EXPIRATION_UPDATE event arrives
     * at the onExpirationUpdateListener with the expiry time
     */
    @Presubmit
    public void testOnExpirationUpdateListener() {

        if (watchHasNoClearkeySupport()) {
            return;
        }

        MediaDrm drm = null;
        mSessionId = null;
        mExpirationUpdateReceived = false;

        // provideKeyResponse calls sendExpirationUpdate method
        // for testing purpose, we therefore start a license request
        // which calls provideKeyResonpse
        byte[][] clearKeyIds = new byte[][] { CLEAR_KEY_CENC };
        int keyType = MediaDrm.KEY_TYPE_STREAMING;
        String initDataType = new String("cenc");

        drm = startDrm(clearKeyIds,  initDataType, CLEARKEY_SCHEME_UUID, keyType);
        mSessionId = openSession(drm);
        try {
            if (!preparePlayback(
                    MIME_VIDEO_AVC,
                    new String[0],
                    Uri.parse(Utils.getMediaPath() + CENC_AUDIO_PATH), false /* audioEncrypted */ ,
                    Uri.parse(Utils.getMediaPath() + CENC_VIDEO_PATH), true /* videoEncrypted */,
                    VIDEO_WIDTH_CENC, VIDEO_HEIGHT_CENC, false /* scrambled */,
                    mSessionId, getSurfaces())) {
                closeSession(drm, mSessionId);
                stopDrm(drm);
                return;
            }
        } catch (Exception e) {
            throw new Error("Unexpected exception ", e);
        }

        mDrmInitData = mMediaCodecPlayer.getDrmInitData();
        getKeys(drm, initDataType, mSessionId, mDrmInitData,
                    keyType, clearKeyIds);

        // wait for the event to arrive
        try {
            closeSession(drm, mSessionId);
            // wait up to 2 seconds for event
            for (int i = 0; i < 20 && !mExpirationUpdateReceived; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                }
            }
            if (!mExpirationUpdateReceived) {
                throw new Error("EXPIRATION_UPDATE event was not received by the listener");
            }
          } catch (MediaDrmStateException e) {
                throw new Error("Unexpected exception from closing session: ", e);
        } finally {
            stopDrm(drm);
        }
    }

    /**
     * Test that the onExpirationUpdateListener
     * listener is not called after
     * clearOnExpirationUpdateListener is called.
     */
    @Presubmit
    public void testClearOnExpirationUpdateListener() {

        if (watchHasNoClearkeySupport()) {
            return;
        }

        MediaDrm drm = null;
        mSessionId = null;
        mExpirationUpdateReceived = false;

        // provideKeyResponse calls sendExpirationUpdate method
        // for testing purpose, we therefore start a license request
        // which calls provideKeyResonpse
        byte[][] clearKeyIds = new byte[][] { CLEAR_KEY_CENC };
        int keyType = MediaDrm.KEY_TYPE_STREAMING;
        String initDataType = new String("cenc");

        drm = startDrm(clearKeyIds,  initDataType, CLEARKEY_SCHEME_UUID, keyType);
        mSessionId = openSession(drm);
        try {
            if (!preparePlayback(
                    MIME_VIDEO_AVC,
                    new String[0],
                    Uri.parse(Utils.getMediaPath() + CENC_AUDIO_PATH), false /* audioEncrypted */ ,
                    Uri.parse(Utils.getMediaPath() + CENC_VIDEO_PATH), true /* videoEncrypted */,
                    VIDEO_WIDTH_CENC, VIDEO_HEIGHT_CENC, false /* scrambled */,
                    mSessionId, getSurfaces())) {
                closeSession(drm, mSessionId);
                stopDrm(drm);
                return;
            }
        } catch (Exception e) {
            throw new Error("Unexpected exception ", e);
        }

        // clear the expiration update listener
        drm.clearOnExpirationUpdateListener();
        mDrmInitData = mMediaCodecPlayer.getDrmInitData();
        getKeys(drm, initDataType, mSessionId, mDrmInitData,
                    keyType, clearKeyIds);

        // wait for the event, it should not arrive
        // because the expiration update listener has been cleared
        try {
            closeSession(drm, mSessionId);
            // wait up to 2 seconds for event
            for (int i = 0; i < 20 && !mExpirationUpdateReceived; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                }
            }
            if (mExpirationUpdateReceived) {
                throw new Error("onExpirationUpdateListener should not be called");
            }
        } catch (MediaDrmStateException e) {
              throw new Error("Unexpected exception from closing session: ", e);
        } finally {
            stopDrm(drm);
        }
    }

    /**
     * Test that after onClearEventListener is called,
     * MediaDrm's event listener is not called.
     *
     * Clearkey plugin's provideKeyResponse method sends a
     * vendor defined event to the media drm event listener
     * for testing purpose. Check that after onClearEventListener
     * is called, the event listener is not called.
     */
    @Presubmit
    public void testClearOnEventListener() {

        if (watchHasNoClearkeySupport()) {
            return;
        }

        MediaDrm drm = null;
        mSessionId = null;
        mEventListenerCalled = false;

        // provideKeyResponse in clearkey plugin sends a
        // vendor defined event to test the event listener;
        // we therefore start a license request which will
        // call provideKeyResonpse
        byte[][] clearKeyIds = new byte[][] { CLEAR_KEY_CENC };
        int keyType = MediaDrm.KEY_TYPE_STREAMING;
        String initDataType = new String("cenc");

        drm = startDrm(clearKeyIds,  initDataType, CLEARKEY_SCHEME_UUID, keyType);
        mSessionId = openSession(drm);
        try {
            if (!preparePlayback(
                    MIME_VIDEO_AVC,
                    new String[0],
                    Uri.parse(Utils.getMediaPath() + CENC_AUDIO_PATH), false /* audioEncrypted */ ,
                    Uri.parse(Utils.getMediaPath() + CENC_VIDEO_PATH), true /* videoEncrypted */,
                    VIDEO_WIDTH_CENC, VIDEO_HEIGHT_CENC, false /* scrambled */,
                    mSessionId, getSurfaces())) {
                closeSession(drm, mSessionId);
                stopDrm(drm);
                return;
            }
        } catch (Exception e) {
            throw new Error("Unexpected exception ", e);
        }

        // test that the onEvent listener is called
        mDrmInitData = mMediaCodecPlayer.getDrmInitData();
        getKeys(drm, initDataType, mSessionId, mDrmInitData,
                    keyType, clearKeyIds);

        // wait for the vendor defined event, it should not arrive
        // because the event listener is cleared
        try {
            // wait up to 2 seconds for event
            for (int i = 0; i < 20 && !mEventListenerCalled; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                }
            }
            if (!mEventListenerCalled) {
                closeSession(drm, mSessionId);
                stopDrm(drm);
                throw new Error("onEventListener should be called");
            }
        } catch (MediaDrmStateException e) {
              closeSession(drm, mSessionId);
              stopDrm(drm);
              throw new Error("Unexpected exception from closing session: ", e);
        }

        // clear the drm event listener
        // and test that the onEvent listener is not called
        mEventListenerCalled = false;
        drm.clearOnEventListener();
        getKeys(drm, initDataType, mSessionId, mDrmInitData,
                    keyType, clearKeyIds);

        // wait for the vendor defined event, it should not arrive
        // because the event listener is cleared
        try {
            closeSession(drm, mSessionId);
            // wait up to 2 seconds for event
            for (int i = 0; i < 20 && !mEventListenerCalled; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                }
            }
            if (mEventListenerCalled) {
                throw new Error("onEventListener should not be called");
            }
        } catch (MediaDrmStateException e) {
              throw new Error("Unexpected exception from closing session: ", e);
        } finally {
            stopDrm(drm);
        }
    }

    /**
     * Test that the framework handles a device returning invoking
     * the ::android::hardware::drm@1.2::sendSessionLostState callback
     * Expected behavior: OnSessionLostState is called with
     * the sessionId
     */
    @Presubmit
    public void testSessionLostStateError() {

        if (watchHasNoClearkeySupport()) {
            return;
        }

        boolean gotException = false;
        mLostStateReceived = false;

        MediaDrm drm = startDrm(new byte[][] { CLEAR_KEY_CENC }, "cenc",
                CLEARKEY_SCHEME_UUID, MediaDrm.KEY_TYPE_STREAMING);

        mDrm.setPropertyString("drmErrorTest", "lostState");
        mSessionId = openSession(drm);

        // simulates session lost state here, detected by closeSession

        try {
            try {
                closeSession(drm, mSessionId);
            } catch (MediaDrmStateException e) {
                gotException = true; // expected for lost state
            }
            // wait up to 2 seconds for event
            for (int i = 0; i < 20 && !mLostStateReceived; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                }
            }
            if (!mLostStateReceived) {
                throw new Error("Callback for OnSessionLostStateListener not received");
            }
        } catch(Exception e) {
            throw new Error("Unexpected exception ", e);
        } finally {
            stopDrm(drm);
        }
        if (!gotException) {
            throw new Error("Didn't receive expected MediaDrmStateException");
        }
    }

    /**
     * Test that the framework handles a device ignoring
     * events for the onSessionLostStateListener after
     * clearOnSessionLostStateListener is called.
     *
     * Expected behavior: OnSessionLostState is not called with
     * the sessionId
     */
    @Presubmit
    public void testClearOnSessionLostStateListener() {

        if (watchHasNoClearkeySupport()) {
            return;
        }

        boolean gotException = false;
        mLostStateReceived = false;

        MediaDrm drm = startDrm(new byte[][] { CLEAR_KEY_CENC }, "cenc",
                CLEARKEY_SCHEME_UUID, MediaDrm.KEY_TYPE_STREAMING);

        mDrm.setPropertyString("drmErrorTest", "lostState");
        mSessionId = openSession(drm);

        // Simulates session lost state here, event is sent from closeSession.
        // The session lost state should not arrive in the listener
        // after clearOnSessionLostStateListener() is called.
        try {
            try {
                mDrm.clearOnSessionLostStateListener();
                Thread.sleep(2000);
                closeSession(drm, mSessionId);
            } catch (MediaDrmStateException e) {
                gotException = true; // expected for lost state
            }
            // wait up to 2 seconds for event
            for (int i = 0; i < 20 && !mLostStateReceived; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                }
            }
            if (mLostStateReceived) {
                throw new Error("Should not receive callback for OnSessionLostStateListener");
            }
        } catch(Exception e) {
            throw new Error("Unexpected exception ", e);
        } finally {
            stopDrm(drm);
        }
        if (!gotException) {
            throw new Error("Didn't receive expected MediaDrmStateException");
        }
    }

    @Presubmit
    public void testIsCryptoSchemeSupportedWithSecurityLevel() {
        if (watchHasNoClearkeySupport()) {
            return;
        }

        if (MediaDrm.isCryptoSchemeSupported(CLEARKEY_SCHEME_UUID, "cenc",
                                             MediaDrm.SECURITY_LEVEL_HW_SECURE_ALL)) {
            throw new Error("Clearkey claims to support SECURITY_LEVEL_HW_SECURE_ALL");
        }
        if (!MediaDrm.isCryptoSchemeSupported(CLEARKEY_SCHEME_UUID, "cenc",
                                              MediaDrm.SECURITY_LEVEL_SW_SECURE_CRYPTO)) {
            throw new Error("Clearkey claims not to support SECURITY_LEVEL_SW_SECURE_CRYPTO");
        }
    }

    @Presubmit
    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
    public void testMediaDrmStateExceptionErrorCode()
            throws ResourceBusyException, UnsupportedSchemeException, NotProvisionedException {
        if (watchHasNoClearkeySupport()) {
            return;
        }

        MediaDrm drm = null;
        try {
            drm = new MediaDrm(CLEARKEY_SCHEME_UUID);
            byte[] sessionId = drm.openSession();
            drm.closeSession(sessionId);

            byte[] ignoredInitData = new byte[]{1};
            drm.getKeyRequest(sessionId, ignoredInitData, "cenc",
                    MediaDrm.KEY_TYPE_STREAMING,
                    null);
        } catch(MediaDrmStateException e) {
            Log.i(TAG, "Verifying exception error code", e);
            assertFalse("ERROR_SESSION_NOT_OPENED requires new session", e.isTransient());
            assertEquals("Expected ERROR_SESSION_NOT_OPENED",
                    MediaDrm.ErrorCodes.ERROR_SESSION_NOT_OPENED, e.getErrorCode());
            assertTrue("Expected ERROR_SESSION_NOT_OPENED value in info",
                    e.getDiagnosticInfo().contains(
                            String.valueOf(MediaDrm.ErrorCodes.ERROR_SESSION_NOT_OPENED)));
        }  finally {
            if (drm != null) {
                drm.close();
            }
        }
    }

    private String getClearkeyVersion(MediaDrm drm) {
        try {
            return drm.getPropertyString("version");
        } catch (Exception e) {
            return "unavailable";
        }
    }

    private boolean cannotHandleGetPropertyByteArray(MediaDrm drm) {
        boolean apiNotSupported = false;
        byte[] bytes = new byte[0];
        try {
            bytes = drm.getPropertyByteArray(DEVICEID_PROPERTY_KEY);
        } catch (IllegalArgumentException e) {
            // Expected exception for invalid key or api not implemented
            apiNotSupported = true;
        }
        return apiNotSupported;
    }

    private boolean cannotHandleSetPropertyString(MediaDrm drm) {
        boolean apiNotSupported = false;
        final byte[] bytes = new byte[0];
        try {
            drm.setPropertyString(LISTENER_TEST_SUPPORT_PROPERTY_KEY, "testing");
        } catch (IllegalArgumentException e) {
            // Expected exception for invalid key or api not implemented
            apiNotSupported = true;
        }
        return apiNotSupported;
    }

    private boolean watchHasNoClearkeySupport() {
        if (!MediaDrm.isCryptoSchemeSupported(CLEARKEY_SCHEME_UUID)) {
            if (isWatchDevice()) {
                return true;
            } else {
                throw new Error(ERR_MSG_CRYPTO_SCHEME_NOT_SUPPORTED);
            }
        }
        return false;
    }

    private List<Surface> getSurfaces() {
        return Arrays.asList(getActivity().getSurfaceHolder().getSurface());
    }
}
