blob: f8e8f98a3549c5050f52f945f9b3f4b6e0e371a4 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 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.mediaframeworktest.unit;
18
19import android.util.Log;
20import android.os.Looper;
21import android.os.Handler;
22import android.os.Message;
23import android.media.MediaPlayer;
24import android.test.AndroidTestCase;
25import com.android.mediaframeworktest.MediaNames;
26
27/**
28 * A template class for running a method under test in all possible
29 * states of a MediaPlayer object.
30 *
31 * @see com.android.mediaframeworktest.unit.MediaPlayerSeekToStateUnitTest
32 * for an example of using this class.
33 *
34 * A typical concrete unit test class would implement the
35 * MediaPlayerMethodUnderTest interface and have a reference to an object of
36 * this class. Then it calls runTestOnMethod() to actually perform the unit
37 * tests.
38 *
39 */
40class MediaPlayerStateUnitTestTemplate extends AndroidTestCase {
41 private static final String TEST_PATH = MediaNames.TEST_PATH_1;
James Dong2fd4e592010-11-14 14:55:56 -080042 private static final String TAG = "MediaPlayerStateUnitTestTemplate";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043 private static final int SEEK_TO_END = 135110; // Milliseconds.
44 private static int WAIT_FOR_COMMAND_TO_COMPLETE = 1000; // Milliseconds.
45
46 private MediaPlayerStateErrors mStateErrors = new MediaPlayerStateErrors();
47 private MediaPlayer mMediaPlayer = null;
48 private boolean mInitialized = false;
49 private boolean mOnCompletionHasBeenCalled = false;
50 private MediaPlayerStateErrors.MediaPlayerState mMediaPlayerState = null;
51 private Looper mLooper = null;
52 private final Object lock = new Object();
53 private MediaPlayerMethodUnderTest mMethodUnderTest = null;
54
55 // An Handler object is absolutely necessary for receiving callback
56 // messages from MediaPlayer objects.
57 private Handler mHandler = new Handler() {
58 @Override
59 public void handleMessage(Message msg) {
60 /*
61 switch(msg.what) {
62 case MediaPlayerStateErrors.MEDIA_PLAYER_ERROR:
63 Log.v(TAG, "handleMessage: received MEDIA_PLAYER_ERROR message");
64 break;
65 default:
66 Log.v(TAG, "handleMessage: received unknown message");
67 break;
68 }
69 */
70 }
71 };
72
73 /**
74 * Runs the given method under test in all possible states of a MediaPlayer
75 * object.
76 *
77 * @param testMethod the method under test.
78 */
79 public void runTestOnMethod(MediaPlayerMethodUnderTest testMethod) {
80 mMethodUnderTest = testMethod;
81 if (mMethodUnderTest != null) { // Method under test has been set?
82 initializeMessageLooper();
83 synchronized(lock) {
84 try {
85 lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
86 } catch(Exception e) {
87 Log.v(TAG, "runTestOnMethod: wait was interrupted.");
88 }
89 }
90 assertTrue(mInitialized); // mMediaPlayer has been initialized?
91 checkMethodUnderTestInAllPossibleStates();
92 terminateMessageLooper(); // Release message looper thread.
93 assertTrue(mOnCompletionHasBeenCalled);
94 mMethodUnderTest.checkStateErrors(mStateErrors);
95 cleanUp();
96 }
97 }
98
99 /*
100 * Initializes the message looper so that the MediaPlayer object can
101 * receive the callback messages.
102 */
103 private void initializeMessageLooper() {
104 new Thread() {
105 @Override
106 public void run() {
107 // Set up a looper to be used by mMediaPlayer.
108 Looper.prepare();
109
110 // Save the looper so that we can terminate this thread
111 // after we are done with it.
112 mLooper = Looper.myLooper();
113
114 mMediaPlayer = new MediaPlayer();
115 mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
116 public boolean onError(MediaPlayer player, int what, int extra) {
117 Log.v(TAG, "onError has been called.");
118 synchronized(lock) {
119 Log.v(TAG, "notify lock.");
120 setStateError(mMediaPlayerState, true);
121 if (mMediaPlayerState != MediaPlayerStateErrors.MediaPlayerState.ERROR) {
122 notifyStateError();
123 }
124 lock.notify();
125 }
126 return true;
127 }
128 });
129 mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
130 public void onCompletion(MediaPlayer player) {
131 Log.v(TAG, "onCompletion has been called.");
132 synchronized(lock) {
133 if (mMediaPlayerState == MediaPlayerStateErrors.MediaPlayerState.PLAYBACK_COMPLETED) {
134 mOnCompletionHasBeenCalled = true;
135 }
136 lock.notify();
137 }
138 }
139 });
140 synchronized(lock) {
141 mInitialized = true;
142 lock.notify();
143 }
144 Looper.loop(); // Blocks forever until Looper.quit() is called.
145 Log.v(TAG, "initializeMessageLooper: quit.");
146 }
147 }.start();
148 }
149
150 /*
151 * Calls method under test in the given state of the MediaPlayer object.
152 *
153 * @param state the MediaPlayer state in which the method under test is called.
154 */
155 private void callMediaPlayerMethodUnderTestInState(MediaPlayerStateErrors.MediaPlayerState state) {
156 Log.v(TAG, "call " + mMethodUnderTest + ": started in state " + state);
157 setMediaPlayerToState(state);
158 mMethodUnderTest.invokeMethodUnderTest(mMediaPlayer);
159 synchronized(lock) {
160 try {
161 lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
162 } catch(Exception e) {
163 Log.v(TAG, "callMediaPlayerMethodUnderTestInState: wait is interrupted in state " + state);
164 }
165 }
166 Log.v(TAG, "call " + mMethodUnderTest + ": ended in state " + state);
167 }
168
169 /*
170 * The following setMediaPlayerToXXXStateXXX methods sets the MediaPlayer
171 * object to the corresponding state, given the assumption that reset()
172 * always resets the MediaPlayer object to Idle (after reset) state.
173 */
174 private void setMediaPlayerToIdleStateAfterReset() {
175 try {
176 mMediaPlayer.reset();
177 mMediaPlayer.setDataSource(TEST_PATH);
178 mMediaPlayer.prepare();
179 mMediaPlayer.reset();
180 } catch(Exception e) {
181 Log.v(TAG, "setMediaPlayerToIdleStateAfterReset: Exception " + e.getClass().getName() + " was thrown.");
182 assertTrue(false);
183 }
184 }
185
186 private void setMediaPlayerToInitializedState() {
187 try {
188 mMediaPlayer.reset();
189 mMediaPlayer.setDataSource(TEST_PATH);
190 } catch(Exception e) {
191 Log.v(TAG, "setMediaPlayerToInitializedState: Exception " + e.getClass().getName() + " was thrown.");
192 assertTrue(false);
193 }
194 }
195
196 private void setMediaPlayerToPreparedState() {
197 try {
198 mMediaPlayer.reset();
199 mMediaPlayer.setDataSource(TEST_PATH);
200 mMediaPlayer.prepare();
201 } catch(Exception e) {
202 Log.v(TAG, "setMediaPlayerToPreparedState: Exception " + e.getClass().getName() + " was thrown.");
203 assertTrue(false);
204 }
205 }
206
207 private void setMediaPlayerToPreparedStateAfterStop() {
208 try {
209 mMediaPlayer.reset();
210 mMediaPlayer.setDataSource(TEST_PATH);
211 mMediaPlayer.prepare();
212 mMediaPlayer.start();
213 mMediaPlayer.stop();
214 mMediaPlayer.prepare();
215 } catch(Exception e) {
216 Log.v(TAG, "setMediaPlayerToPreparedStateAfterStop: Exception " + e.getClass().getName() + " was thrown.");
217 assertTrue(false);
218 }
219 }
220
221 private void setMediaPlayerToStartedState() {
222 try {
223 mMediaPlayer.reset();
224 mMediaPlayer.setDataSource(TEST_PATH);
225 mMediaPlayer.prepare();
226 mMediaPlayer.start();
227 } catch(Exception e) {
228 Log.v(TAG, "setMediaPlayerToStartedState: Exception " + e.getClass().getName() + " was thrown.");
229 assertTrue(false);
230 }
231 }
232
233 private void setMediaPlayerToStartedStateAfterPause() {
234 try {
235 mMediaPlayer.reset();
236 mMediaPlayer.setDataSource(TEST_PATH);
237 mMediaPlayer.prepare();
238 mMediaPlayer.start();
239 mMediaPlayer.pause();
240
241 // pause() is an asynchronous call and returns immediately, but
242 // PV player engine may take quite a while to actually set the
243 // player state to Paused; if we call start() right after pause()
244 // without waiting, start() may fail.
245 try {
246 Thread.sleep(MediaNames.PAUSE_WAIT_TIME);
247 } catch(Exception ie) {
248 Log.v(TAG, "sleep was interrupted and terminated prematurely");
249 }
250
251 mMediaPlayer.start();
252 } catch(Exception e) {
253 Log.v(TAG, "setMediaPlayerToStartedStateAfterPause: Exception " + e.getClass().getName() + " was thrown.");
254 assertTrue(false);
255 }
256 }
257
258 private void setMediaPlayerToPausedState() {
259 try {
260 mMediaPlayer.reset();
261 mMediaPlayer.setDataSource(TEST_PATH);
262 mMediaPlayer.prepare();
263 mMediaPlayer.start();
264 mMediaPlayer.pause();
265 } catch(Exception e) {
266 Log.v(TAG, "setMediaPlayerToPausedState: Exception " + e.getClass().getName() + " was thrown.");
267 assertTrue(false);
268 }
269 }
270
271 private void setMediaPlayerToStoppedState() {
272 try {
273 mMediaPlayer.reset();
274 mMediaPlayer.setDataSource(TEST_PATH);
275 mMediaPlayer.prepare();
276 mMediaPlayer.start();
277 mMediaPlayer.stop();
278 } catch(Exception e) {
279 Log.v(TAG, "setMediaPlayerToStoppedState: Exception " + e.getClass().getName() + " was thrown.");
280 assertTrue(false);
281 }
282 }
283
284 private void setMediaPlayerToPlaybackCompletedState() {
285 try {
286 mMediaPlayer.reset();
287 mMediaPlayer.setDataSource(TEST_PATH);
288 mMediaPlayer.prepare();
289 mMediaPlayer.seekTo(SEEK_TO_END);
290 mMediaPlayer.start();
291 synchronized(lock) {
292 try {
293 lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
294 } catch(Exception e) {
295 Log.v(TAG, "setMediaPlayerToPlaybackCompletedState: wait was interrupted.");
296 }
297 }
298 } catch(Exception e) {
299 Log.v(TAG, "setMediaPlayerToPlaybackCompletedState: Exception " + e.getClass().getName() + " was thrown.");
300 assertTrue(false);
301 }
302 Log.v(TAG, "setMediaPlayerToPlaybackCompletedState: done.");
303 }
304
305 /*
306 * There are a lot of ways to force the MediaPlayer object to enter
307 * the Error state. The impact (such as onError is called or not) highly
308 * depends on how the Error state is entered.
309 */
310 private void setMediaPlayerToErrorState() {
311 try {
312 mMediaPlayer.reset();
313 mMediaPlayer.setDataSource(TEST_PATH);
314 mMediaPlayer.start();
315 synchronized(lock) {
316 try {
317 lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
318 } catch(Exception e) {
319 Log.v(TAG, "setMediaPlayerToErrorState: wait was interrupted.");
320 }
321 }
322 } catch(Exception e) {
323 Log.v(TAG, "setMediaPlayerToErrorState: Exception " + e.getClass().getName() + " was thrown.");
324 assertTrue(e instanceof IllegalStateException);
325 }
326 Log.v(TAG, "setMediaPlayerToErrorState: done.");
327 }
328
329 /*
330 * Sets the state of the MediaPlayer object to the specified one.
331 *
332 * @param state the state of the MediaPlayer object.
333 */
334 private void setMediaPlayerToState(MediaPlayerStateErrors.MediaPlayerState state) {
335 mMediaPlayerState = state;
336 switch(state) {
337 case IDLE:
338 // Does nothing.
339 break;
340 case IDLE_AFTER_RESET:
341 setMediaPlayerToIdleStateAfterReset();
342 break;
343 case INITIALIZED:
344 setMediaPlayerToInitializedState();
345 break;
346 case PREPARED:
347 setMediaPlayerToPreparedState();
348 break;
349 case PREPARED_AFTER_STOP:
350 setMediaPlayerToPreparedStateAfterStop();
351 break;
352 case STARTED:
353 setMediaPlayerToStartedState();
354 break;
355 case STARTED_AFTER_PAUSE:
356 setMediaPlayerToStartedStateAfterPause();
357 break;
358 case PAUSED:
359 setMediaPlayerToPausedState();
360 break;
361 case STOPPED:
362 setMediaPlayerToStoppedState();
363 break;
364 case PLAYBACK_COMPLETED:
365 setMediaPlayerToPlaybackCompletedState();
366 break;
367 case ERROR:
368 setMediaPlayerToErrorState();
369 break;
370 }
371 }
372
373 /*
374 * Sets the error value of the corresponding state to the given error.
375 *
376 * @param state the state of the MediaPlayer object.
377 * @param error the value of the state error to be set.
378 */
379 private void setStateError(MediaPlayerStateErrors.MediaPlayerState state, boolean error) {
380 switch(state) {
381 case IDLE:
382 mStateErrors.errorInIdleState = error;
383 break;
384 case IDLE_AFTER_RESET:
385 mStateErrors.errorInIdleStateAfterReset = error;
386 break;
387 case INITIALIZED:
388 mStateErrors.errorInInitializedState = error;
389 break;
390 case PREPARED:
391 mStateErrors.errorInPreparedState = error;
392 break;
393 case PREPARED_AFTER_STOP:
394 mStateErrors.errorInPreparedStateAfterStop = error;
395 break;
396 case STARTED:
397 mStateErrors.errorInStartedState = error;
398 break;
399 case STARTED_AFTER_PAUSE:
400 mStateErrors.errorInStartedStateAfterPause = error;
401 break;
402 case PAUSED:
403 mStateErrors.errorInPausedState = error;
404 break;
405 case STOPPED:
406 mStateErrors.errorInStoppedState = error;
407 break;
408 case PLAYBACK_COMPLETED:
409 mStateErrors.errorInPlaybackCompletedState = error;
410 break;
411 case ERROR:
412 mStateErrors.errorInErrorState = error;
413 break;
414 }
415 }
416
417 private void notifyStateError() {
418 mHandler.sendMessage(mHandler.obtainMessage(MediaPlayerStateErrors.MEDIA_PLAYER_ERROR));
419 }
420
421 private void checkIdleState() {
422 callMediaPlayerMethodUnderTestInState(MediaPlayerStateErrors.MediaPlayerState.IDLE);
423 }
424
425 private void checkIdleStateAfterReset() {
426 callMediaPlayerMethodUnderTestInState(MediaPlayerStateErrors.MediaPlayerState.IDLE_AFTER_RESET);
427 }
428
429 private void checkInitializedState() {
430 callMediaPlayerMethodUnderTestInState(MediaPlayerStateErrors.MediaPlayerState.INITIALIZED);
431 }
432
433 private void checkPreparedState() {
434 callMediaPlayerMethodUnderTestInState(MediaPlayerStateErrors.MediaPlayerState.PREPARED);
435 }
436
437 private void checkPreparedStateAfterStop() {
438 callMediaPlayerMethodUnderTestInState(MediaPlayerStateErrors.MediaPlayerState.PREPARED_AFTER_STOP);
439 }
440
441 private void checkStartedState() {
442 callMediaPlayerMethodUnderTestInState(MediaPlayerStateErrors.MediaPlayerState.STARTED);
443 }
444
445 private void checkPausedState() {
446 callMediaPlayerMethodUnderTestInState(MediaPlayerStateErrors.MediaPlayerState.PAUSED);
447 }
448
449 private void checkStartedStateAfterPause() {
450 callMediaPlayerMethodUnderTestInState(MediaPlayerStateErrors.MediaPlayerState.STARTED_AFTER_PAUSE);
451 }
452
453 private void checkStoppedState() {
454 callMediaPlayerMethodUnderTestInState(MediaPlayerStateErrors.MediaPlayerState.STOPPED);
455 }
456
457 private void checkPlaybackCompletedState() {
458 callMediaPlayerMethodUnderTestInState(MediaPlayerStateErrors.MediaPlayerState.PLAYBACK_COMPLETED);
459 }
460
461 private void checkErrorState() {
462 callMediaPlayerMethodUnderTestInState(MediaPlayerStateErrors.MediaPlayerState.ERROR);
463 }
464
465 /*
466 * Checks the given method under test in all possible states of the MediaPlayer object.
467 */
468 private void checkMethodUnderTestInAllPossibleStates() {
469 // Must be called first.
470 checkIdleState();
471
472 // The sequence of the following method calls should not
473 // affect the test results.
474 checkErrorState();
475 checkIdleStateAfterReset();
476 checkInitializedState();
477 checkStartedState();
478 checkStartedStateAfterPause();
479 checkPausedState();
480 checkPreparedState();
481
482 checkPreparedStateAfterStop();
483
484 checkPlaybackCompletedState();
485 checkStoppedState();
486 }
487
488 /*
489 * Terminates the message looper thread.
490 */
491 private void terminateMessageLooper() {
492 mLooper.quit();
493 mMediaPlayer.release();
494 }
495
496 /*
497 * Cleans up all the internal object references.
498 */
499 private void cleanUp() {
500 mMediaPlayer = null;
501 mMediaPlayerState = null;
502 mLooper = null;
503 mStateErrors = null;
504 mMethodUnderTest = null;
505 }
506}