1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.ex.variablespeed;
18
19import com.google.common.io.Closeables;
20
21import android.content.ContentResolver;
22import android.content.ContentValues;
23import android.content.res.AssetManager;
24import android.net.Uri;
25import android.provider.VoicemailContract;
26import android.test.InstrumentationTestCase;
27
28import java.io.IOException;
29import java.io.InputStream;
30import java.io.OutputStream;
31import java.lang.annotation.Retention;
32import java.lang.annotation.RetentionPolicy;
33import java.util.HashMap;
34import java.util.Map;
35import java.util.concurrent.TimeUnit;
36
37/**
38 * Base test for checking implementations of {@link MediaPlayerProxy}.
39 * <p>
40 * The purpose behind this class is to collect tests that implementations of
41 * MediaPlayerProxy should support.
42 * <p>
43 * This allows tests to show that the built-in {@link android.media.MediaPlayer} is performing
44 * correctly with respect to the contract it provides, i.e. test my understanding of that contract.
45 * <p>
46 * It allows us to test the current {@link VariableSpeed} implementation, and make sure that this
47 * too corresponds with the MediaPlayer implementation.
48 * <p>
49 * These tests cannot be run on their own - you must provide a concrete subclass of this test case -
50 * and in that subclass you will provide an implementation of the abstract
51 * {@link #createTestMediaPlayer()} method to construct the player you would like to test. Every
52 * test will construct the player in {@link #setUp()} and release it in {@link #tearDown()}.
53 */
54public abstract class MediaPlayerProxyTestCase extends InstrumentationTestCase {
55    private static final float ERROR_TOLERANCE_MILLIS = 1000f;
56
57    /** The phone number to use when inserting test data into the content provider. */
58    private static final String CONTACT_NUMBER = "01234567890";
59
60    /**
61     * A map from filename + mime type to the uri we can use to play from the content provider.
62     * <p>
63     * This is lazily filled in by the {@link #getTestContentUri(String, String)} method.
64     * <p>
65     * This map is keyed from the concatenation of filename and mime type with a "+" separator, it's
66     * not perfect but it doesn't matter in this test code.
67     */
68    private final Map<String, Uri> mContentUriMap = new HashMap<String, Uri>();
69
70    /** The system under test. */
71    private MediaPlayerProxy mPlayer;
72
73    private AwaitableCompletionListener mCompletionListener;
74    private AwaitableErrorListener mErrorListener;
75
76    @Override
77    protected void setUp() throws Exception {
78        super.setUp();
79        mPlayer = createTestMediaPlayer();
80        mCompletionListener = new AwaitableCompletionListener();
81        mErrorListener = new AwaitableErrorListener();
82    }
83
84    @Override
85    protected void tearDown() throws Exception {
86        mCompletionListener = null;
87        mErrorListener = null;
88        mPlayer.release();
89        mPlayer = null;
90        cleanupContentUriIfNecessary();
91        super.tearDown();
92    }
93
94    public abstract MediaPlayerProxy createTestMediaPlayer() throws Exception;
95
96    /** Annotation to indicate that test should throw an {@link IllegalStateException}. */
97    @Retention(RetentionPolicy.RUNTIME)
98    public @interface ShouldThrowIllegalStateException {
99    }
100
101    @Override
102    protected void runTest() throws Throwable {
103        // Tests annotated with ShouldThrowIllegalStateException will fail if they don't.
104        // Tests not annotated this way are run as normal.
105        if (getClass().getMethod(getName()).isAnnotationPresent(
106                ShouldThrowIllegalStateException.class)) {
107            try {
108                super.runTest();
109                fail("Expected this method to throw an IllegalStateException, but it didn't");
110            } catch (IllegalStateException e) {
111                // Expected.
112            }
113        } else {
114            super.runTest();
115        }
116    }
117
118    public void testReleaseMultipleTimesHasNoEffect() throws Exception {
119        mPlayer.release();
120        mPlayer.release();
121    }
122
123    public void testResetOnNewlyCreatedObject() throws Exception {
124        mPlayer.reset();
125    }
126
127    public void testSetDataSource() throws Exception {
128        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
129    }
130
131    @ShouldThrowIllegalStateException
132    public void testSetDataSourceTwice_ShouldFailWithIllegalState() throws Exception {
133        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
134        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
135    }
136
137    @ShouldThrowIllegalStateException
138    public void testSetDataSourceAfterRelease_ShouldFailWithIllegalState() throws Exception {
139        mPlayer.release();
140        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
141    }
142
143    public void testPrepare() throws Exception {
144        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
145        mPlayer.prepare();
146    }
147
148    @ShouldThrowIllegalStateException
149    public void testPrepareBeforeSetDataSource_ShouldFail() throws Exception {
150        mPlayer.prepare();
151    }
152
153    @ShouldThrowIllegalStateException
154    public void testPrepareTwice_ShouldFailWithIllegalState() throws Exception {
155        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
156        mPlayer.prepare();
157        mPlayer.prepare();
158    }
159
160    public void testStartThenImmediatelyRelease() throws Exception {
161        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
162        mPlayer.prepare();
163        mPlayer.start();
164    }
165
166    public void testPlayABitThenRelease() throws Exception {
167        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
168        mPlayer.prepare();
169        mPlayer.start();
170        Thread.sleep(2000);
171    }
172
173    public void testPlayFully() throws Exception {
174        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
175        mPlayer.prepare();
176        mPlayer.setOnCompletionListener(mCompletionListener);
177        mPlayer.start();
178        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
179    }
180
181    public void testGetDuration() throws Exception {
182        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
183        mPlayer.prepare();
184        int duration = mPlayer.getDuration();
185        assertTrue("duration was " + duration, duration > 0);
186        mPlayer.setOnCompletionListener(mCompletionListener);
187        mPlayer.start();
188        assertEquals(duration, mPlayer.getDuration());
189        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
190        assertEquals(duration, mPlayer.getDuration());
191    }
192
193    @ShouldThrowIllegalStateException
194    public void testGetDurationAfterRelease_ShouldFail() throws Exception {
195        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
196        mPlayer.release();
197        mPlayer.getDuration();
198    }
199
200    @ShouldThrowIllegalStateException
201    public void testGetPositionAfterRelease_ShouldFail() throws Exception {
202        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
203        mPlayer.release();
204        mPlayer.getCurrentPosition();
205    }
206
207    public void testGetCurrentPosition_ZeroBeforePlaybackBegins() throws Exception {
208        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
209        assertEquals(0, mPlayer.getCurrentPosition());
210        mPlayer.prepare();
211        assertEquals(0, mPlayer.getCurrentPosition());
212    }
213
214    public void testGetCurrentPosition_DuringPlayback() throws Exception {
215        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
216        mPlayer.prepare();
217        mPlayer.start();
218        Thread.sleep(2000);
219        assertEquals(2000, mPlayer.getCurrentPosition(), ERROR_TOLERANCE_MILLIS);
220    }
221
222    public void testGetCurrentPosition_FinishedPlaying() throws Exception {
223        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
224        mPlayer.prepare();
225        mPlayer.setOnCompletionListener(mCompletionListener);
226        mPlayer.start();
227        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
228        assertEquals(mPlayer.getDuration(), mPlayer.getCurrentPosition(), ERROR_TOLERANCE_MILLIS);
229    }
230
231    public void testGetCurrentPosition_DuringPlaybackWithSeek() throws Exception {
232        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
233        mPlayer.prepare();
234        mPlayer.seekTo(1500);
235        mPlayer.start();
236        Thread.sleep(1500);
237        assertEquals(3000, mPlayer.getCurrentPosition(), ERROR_TOLERANCE_MILLIS);
238    }
239
240    public void testSeekHalfWayBeforePlaying() throws Exception {
241        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
242        mPlayer.prepare();
243        assertTrue(mPlayer.getDuration() > 0);
244        mPlayer.seekTo(mPlayer.getDuration() / 2);
245        mPlayer.start();
246        mPlayer.setOnCompletionListener(mCompletionListener);
247        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
248    }
249
250    public void testHalfWaySeekWithStutteringAudio() throws Exception {
251        // The audio contained in this file has a stutter if we seek to half way and play.
252        // It shouldn't have.
253        setDataSourceFromContentProvider(mPlayer, "fake_voicemail2.mp3", "audio/mp3");
254        mPlayer.prepare();
255        assertTrue(mPlayer.getDuration() > 0);
256        mPlayer.seekTo(mPlayer.getDuration() / 2);
257        mPlayer.start();
258        mPlayer.setOnCompletionListener(mCompletionListener);
259        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
260    }
261
262    public void testResetWithoutReleaseAndThenReUse() throws Exception {
263        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
264        mPlayer.reset();
265        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
266        mPlayer.prepare();
267        mPlayer.seekTo(mPlayer.getDuration() / 2);
268        mPlayer.start();
269        Thread.sleep(1000);
270    }
271
272    public void testResetAfterPlaybackThenReUse() throws Exception {
273        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
274        mPlayer.setOnCompletionListener(mCompletionListener);
275        mPlayer.prepare();
276        mPlayer.start();
277        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
278        mPlayer.reset();
279        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
280        mPlayer.prepare();
281        mPlayer.start();
282        Thread.sleep(2000);
283    }
284
285    public void testResetDuringPlaybackThenReUse() throws Exception {
286        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
287        mPlayer.prepare();
288        mPlayer.start();
289        Thread.sleep(2000);
290        mPlayer.reset();
291        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
292        mPlayer.prepare();
293        mPlayer.start();
294        Thread.sleep(2000);
295    }
296
297    public void testFinishPlayingThenSeekToHalfWayThenPlayAgain() throws Exception {
298        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
299        mPlayer.prepare();
300        mPlayer.setOnCompletionListener(mCompletionListener);
301        mPlayer.start();
302        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
303        mPlayer.seekTo(mPlayer.getDuration() / 2);
304        mPlayer.start();
305        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
306    }
307
308    public void testPause_DuringPlayback() throws Exception {
309        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
310        mPlayer.prepare();
311        mPlayer.start();
312        assertTrue(mPlayer.isPlaying());
313        Thread.sleep(2000);
314        assertTrue(mPlayer.isPlaying());
315        mPlayer.pause();
316        assertFalse(mPlayer.isPlaying());
317    }
318
319    public void testPause_DoesNotInvokeCallback() throws Exception {
320        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
321        mPlayer.prepare();
322        mPlayer.setOnCompletionListener(mCompletionListener);
323        mPlayer.start();
324        mPlayer.pause();
325        Thread.sleep(200);
326        mCompletionListener.assertNoMoreCallbacks();
327    }
328
329    public void testReset_DoesNotInvokeCallback() throws Exception {
330        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
331        mPlayer.prepare();
332        mPlayer.setOnCompletionListener(mCompletionListener);
333        mPlayer.start();
334        mPlayer.reset();
335        Thread.sleep(200);
336        mCompletionListener.assertNoMoreCallbacks();
337    }
338
339    public void testPause_MultipleTimes() throws Exception {
340        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
341        mPlayer.prepare();
342        mPlayer.start();
343        Thread.sleep(2000);
344        mPlayer.pause();
345        mPlayer.pause();
346    }
347
348    public void testDoubleStartWaitingForFinish() throws Exception {
349        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
350        mPlayer.prepare();
351        mPlayer.setOnCompletionListener(mCompletionListener);
352        mPlayer.start();
353        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
354        mPlayer.start();
355        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
356    }
357
358    public void testTwoFastConsecutiveStarts() throws Exception {
359        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
360        mPlayer.prepare();
361        mPlayer.setOnCompletionListener(mCompletionListener);
362        mPlayer.start();
363        mPlayer.start();
364        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
365        Thread.sleep(200);
366        mCompletionListener.assertNoMoreCallbacks();
367    }
368
369    public void testThreeFastConsecutiveStarts() throws Exception {
370        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
371        mPlayer.prepare();
372        mPlayer.setOnCompletionListener(mCompletionListener);
373        mPlayer.start();
374        mPlayer.start();
375        mPlayer.start();
376        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
377        Thread.sleep(4000);
378        mCompletionListener.assertNoMoreCallbacks();
379    }
380
381    public void testSeekDuringPlayback() throws Exception {
382        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
383        mPlayer.prepare();
384        mPlayer.setOnCompletionListener(mCompletionListener);
385        mPlayer.start();
386        Thread.sleep(2000);
387        mPlayer.seekTo(0);
388        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
389        Thread.sleep(200);
390        mCompletionListener.assertNoMoreCallbacks();
391    }
392
393    public void testPlaySingleChannelLowSampleRate3gppFile() throws Exception {
394        setDataSourceFromContentProvider(mPlayer, "count_and_test.3gpp", "audio/3gpp");
395        mPlayer.prepare();
396        mPlayer.setOnCompletionListener(mCompletionListener);
397        mPlayer.start();
398        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
399    }
400
401    public void testPlayTwoDifferentTypesWithSameMediaPlayer() throws Exception {
402        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
403        mPlayer.prepare();
404        mPlayer.setOnCompletionListener(mCompletionListener);
405        mPlayer.start();
406        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
407        mPlayer.reset();
408        setDataSourceFromContentProvider(mPlayer, "count_and_test.3gpp", "audio/3gpp");
409        mPlayer.prepare();
410        mPlayer.start();
411        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
412    }
413
414    public void testIllegalPreparingDoesntFireErrorListener() throws Exception {
415        mPlayer.setOnErrorListener(mErrorListener);
416        try {
417            mPlayer.prepare();
418            fail("This should have thrown an IllegalStateException");
419        } catch (IllegalStateException e) {
420            // Good, expected.
421        }
422        mErrorListener.assertNoMoreCallbacks();
423    }
424
425    public void testSetDataSourceForMissingFile_ThrowsIOExceptionInPrepare() throws Exception {
426        mPlayer.setOnErrorListener(mErrorListener);
427        mPlayer.setDataSource("/this/file/does/not/exist/");
428        try {
429            mPlayer.prepare();
430            fail("Should have thrown IOException");
431        } catch (IOException e) {
432            // Good, expected.
433        }
434        // Synchronous prepare does not report errors to the error listener.
435        mErrorListener.assertNoMoreCallbacks();
436    }
437
438    public void testRepeatedlySeekingDuringPlayback() throws Exception {
439        // Start playback then seek repeatedly during playback to the same point.
440        // The real media player should play a stuttering audio, hopefully my player does too.
441        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
442        mPlayer.prepare();
443        mPlayer.setOnCompletionListener(mCompletionListener);
444        mPlayer.start();
445        Thread.sleep(500);
446        for (int i = 0; i < 40; ++i) {
447            Thread.sleep(200);
448            mPlayer.seekTo(2000);
449        }
450        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
451    }
452
453    public void testRepeatedlySeekingDuringPlaybackRandomAndVeryFast() throws Exception {
454        setDataSourceFromContentProvider(mPlayer, "quick_test_recording.mp3", "audio/mp3");
455        mPlayer.prepare();
456        mPlayer.setOnCompletionListener(mCompletionListener);
457        mPlayer.start();
458        Thread.sleep(500);
459        for (int i = 0; i < 40; ++i) {
460            Thread.sleep(250);
461            mPlayer.seekTo(1500 + (int) (Math.random() * 1000));
462        }
463        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
464    }
465
466    public void testSeekToEndThenPlayThenRateChangeCrash() throws Exception {
467        // Unit test for this bug: http://b/5140693
468        // This test proves that the bug is fixed.
469        setDataSourceFromContentProvider(mPlayer, "fake_voicemail.mp3", "audio/mp3");
470        mPlayer.prepare();
471        mPlayer.seekTo(mPlayer.getDuration() - 1);
472        mPlayer.setOnCompletionListener(mCompletionListener);
473        mPlayer.start();
474        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
475        // Prior to the fix, this next line was causing a crash.
476        // The reason behind this was due to our having seeked so close to the end of the file
477        // that insufficient data was being read, and thus we weren't able to yet determine the
478        // sample rate and number of channels, which was causing an assertion failure when trying
479        // to create the time scaler.
480        setVariableSpeedRateIfSupported(1.0f);
481    }
482
483    public void testVariableSpeedRateChangeAtDifferentTimes() throws Exception {
484        // Just check that we can set the rate at any point during playback.
485        setVariableSpeedRateIfSupported(1.05f);
486        setDataSourceFromContentProvider(mPlayer, "fake_voicemail.mp3", "audio/mp3");
487        setVariableSpeedRateIfSupported(1.10f);
488        mPlayer.prepare();
489        setVariableSpeedRateIfSupported(1.15f);
490        mPlayer.seekTo(mPlayer.getDuration() / 2);
491        setVariableSpeedRateIfSupported(1.20f);
492        mPlayer.setOnCompletionListener(mCompletionListener);
493        setVariableSpeedRateIfSupported(1.25f);
494        mPlayer.start();
495        setVariableSpeedRateIfSupported(1.30f);
496        mCompletionListener.awaitOneCallback(10, TimeUnit.SECONDS);
497        setVariableSpeedRateIfSupported(1.35f);
498    }
499
500    /**
501     * If we have a variable speed media player proxy, set the variable speed rate.
502     * <p>
503     * If we don't have a variable speed media player proxy, this method will be a no-op.
504     */
505    private void setVariableSpeedRateIfSupported(float rate) {
506        if (mPlayer instanceof SingleThreadedMediaPlayerProxy) {
507            ((SingleThreadedMediaPlayerProxy) mPlayer).setVariableSpeed(rate);
508        } else if (mPlayer instanceof VariableSpeed) {
509            ((VariableSpeed) mPlayer).setVariableSpeed(rate);
510        }
511    }
512
513    /**
514     * Gets the {@link Uri} for the test audio content we should play.
515     * <p>
516     * If this is the first time we've called this method, for a given file type and mime type, then
517     * we'll have to insert some data into the content provider so that we can play it.
518     * <p>
519     * This is not thread safe, but doesn't need to be because all unit tests are executed from a
520     * single thread, sequentially.
521     */
522    private Uri getTestContentUri(String assetFilename, String assetMimeType) throws IOException {
523        String key = keyFor(assetFilename, assetMimeType);
524        if (mContentUriMap.containsKey(key)) {
525            return mContentUriMap.get(key);
526        }
527        ContentValues values = new ContentValues();
528        values.put(VoicemailContract.Voicemails.DATE, String.valueOf(System.currentTimeMillis()));
529        values.put(VoicemailContract.Voicemails.NUMBER, CONTACT_NUMBER);
530        values.put(VoicemailContract.Voicemails.MIME_TYPE, assetMimeType);
531        String packageName = getInstrumentation().getTargetContext().getPackageName();
532        Uri uri = getContentResolver().insert(
533                VoicemailContract.Voicemails.buildSourceUri(packageName), values);
534        AssetManager assets = getAssets();
535        OutputStream outputStream = null;
536        InputStream inputStream = null;
537        try {
538            inputStream = assets.open(assetFilename);
539            outputStream = getContentResolver().openOutputStream(uri);
540            copyBetweenStreams(inputStream, outputStream);
541            mContentUriMap.put(key, uri);
542            return uri;
543        } finally {
544            Closeables.closeQuietly(outputStream);
545            Closeables.closeQuietly(inputStream);
546        }
547    }
548
549    private String keyFor(String assetFilename, String assetMimeType) {
550        return assetFilename + "+" + assetMimeType;
551    }
552
553    public void copyBetweenStreams(InputStream in, OutputStream out) throws IOException {
554        byte[] buffer = new byte[1024];
555        int bytesRead;
556        while ((bytesRead = in.read(buffer)) != -1) {
557            out.write(buffer, 0, bytesRead);
558        }
559    }
560
561    private void cleanupContentUriIfNecessary() {
562        for (Uri uri : mContentUriMap.values()) {
563            getContentResolver().delete(uri, null, null);
564        }
565        mContentUriMap.clear();
566    }
567
568    private void setDataSourceFromContentProvider(MediaPlayerProxy player, String assetFilename,
569            String assetMimeType) throws IOException {
570        player.setDataSource(getInstrumentation().getTargetContext(),
571                getTestContentUri(assetFilename, assetMimeType));
572    }
573
574    private ContentResolver getContentResolver() {
575        return getInstrumentation().getContext().getContentResolver();
576    }
577
578    private AssetManager getAssets() {
579        return getInstrumentation().getContext().getAssets();
580    }
581}
582