| /* |
| * Copyright (C) 2008 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 com.android.mediaframeworktest.unit; |
| |
| import android.util.Log; |
| import android.media.MediaRecorder; |
| import android.test.AndroidTestCase; |
| |
| /** |
| * A template class for running a method under test in all possible |
| * states of a MediaRecorder object. |
| * |
| * @see com.android.mediaframeworktest.unit.MediaRecorderStopStateUnitTest |
| * for an example of using this class. |
| * |
| * A typical concrete unit test class would implement the |
| * MediaRecorderMethodUnderTest interface and have a reference to an object of |
| * this class. Then it calls runTestOnMethod() to actually perform the unit |
| * tests. It is recommended that the toString() method of the concrete unit test |
| * class be overridden to use the actual method name under test for logging |
| * purpose. |
| * |
| */ |
| class MediaRecorderStateUnitTestTemplate extends AndroidTestCase { |
| public static final String RECORD_OUTPUT_PATH = "/sdcard/recording.3gp"; |
| public static final int OUTPUT_FORMAT= MediaRecorder.OutputFormat.THREE_GPP; |
| public static final int AUDIO_ENCODER = MediaRecorder.AudioEncoder.AMR_NB; |
| public static final int AUDIO_SOURCE = MediaRecorder.AudioSource.MIC; |
| private static final String TAG = "MediaRecorderStateUnitTest"; |
| private MediaRecorderStateErrors mStateErrors = new MediaRecorderStateErrors(); |
| private MediaRecorder mMediaRecorder = new MediaRecorder(); |
| private MediaRecorderStateErrors.MediaRecorderState mMediaRecorderState = null; |
| private MediaRecorderMethodUnderTest mMethodUnderTest = null; |
| |
| /** |
| * Runs the given method under test in all possible states of a MediaRecorder |
| * object. |
| * |
| * @param testMethod the method under test. |
| */ |
| public void runTestOnMethod(MediaRecorderMethodUnderTest testMethod) { |
| mMethodUnderTest = testMethod; |
| if (mMethodUnderTest != null) { // Method under test has been set? |
| checkMethodUnderTestInAllPossibleStates(); |
| mMethodUnderTest.checkStateErrors(mStateErrors); |
| cleanUp(); |
| } |
| } |
| |
| /* |
| * Calls method under test in the given state of the MediaRecorder object. |
| * |
| * @param state the MediaRecorder state in which the method under test is called. |
| */ |
| private void callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState state) { |
| Log.v(TAG, "call " + mMethodUnderTest + ": started in state " + state); |
| setMediaRecorderToState(state); |
| try { |
| mMethodUnderTest.invokeMethodUnderTest(mMediaRecorder); |
| } catch(Exception e) { |
| setStateError(mMediaRecorderState, true); |
| } |
| Log.v(TAG, "call " + mMethodUnderTest + ": ended in state " + state); |
| } |
| |
| /* |
| * The following setMediaRecorderToXXXStateXXX methods sets the MediaRecorder |
| * object to the corresponding state, given the assumption that reset() |
| * always resets the MediaRecorder object to Initial (after reset) state. |
| */ |
| private void setMediaRecorderToInitialStateAfterReset() { |
| try { |
| mMediaRecorder.reset(); |
| } catch(Exception e) { |
| fail("setMediaRecorderToInitialStateAfterReset: Exception " + e.getClass().getName() + " was thrown."); |
| } |
| } |
| |
| // FIXME: |
| // In the past, stop() == reset(). |
| // However, this is no longer true. The plan is to have a STOPPED state. |
| // and from STOPPED state, start can be called without the need to |
| // do the recording configuration again. |
| private void setMediaRecorderToInitialStateAfterStop() { |
| try { |
| mMediaRecorder.reset(); |
| /* |
| mMediaRecorder.setAudioSource(AUDIO_SOURCE); |
| mMediaRecorder.setOutputFormat(OUTPUT_FORMAT); |
| mMediaRecorder.setAudioEncoder(AUDIO_ENCODER); |
| mMediaRecorder.setOutputFile(RECORD_OUTPUT_PATH); |
| mMediaRecorder.prepare(); |
| mMediaRecorder.start(); |
| mMediaRecorder.stop(); |
| */ |
| } catch(Exception e) { |
| fail("setMediaRecorderToInitialStateAfterReset: Exception " + e.getClass().getName() + " was thrown."); |
| } |
| } |
| |
| private void setMediaRecorderToInitializedState() { |
| try { |
| mMediaRecorder.reset(); |
| if (mMethodUnderTest.toString() != "setAudioSource()") { |
| mMediaRecorder.setAudioSource(AUDIO_SOURCE); |
| } |
| } catch(Exception e) { |
| fail("setMediaRecorderToInitializedState: Exception " + e.getClass().getName() + " was thrown."); |
| } |
| } |
| |
| private void setMediaRecorderToPreparedState() { |
| try { |
| mMediaRecorder.reset(); |
| mMediaRecorder.setAudioSource(AUDIO_SOURCE); |
| mMediaRecorder.setOutputFormat(OUTPUT_FORMAT); |
| mMediaRecorder.setAudioEncoder(AUDIO_ENCODER); |
| mMediaRecorder.setOutputFile(RECORD_OUTPUT_PATH); |
| mMediaRecorder.prepare(); |
| } catch(Exception e) { |
| fail("setMediaRecorderToPreparedState: Exception " + e.getClass().getName() + " was thrown."); |
| } |
| } |
| |
| private void setMediaRecorderToRecordingState() { |
| try { |
| mMediaRecorder.reset(); |
| mMediaRecorder.setAudioSource(AUDIO_SOURCE); |
| mMediaRecorder.setOutputFormat(OUTPUT_FORMAT); |
| mMediaRecorder.setAudioEncoder(AUDIO_ENCODER); |
| mMediaRecorder.setOutputFile(RECORD_OUTPUT_PATH); |
| mMediaRecorder.prepare(); |
| mMediaRecorder.start(); |
| } catch(Exception e) { |
| fail("setMediaRecorderToRecordingState: Exception " + e.getClass().getName() + " was thrown."); |
| } |
| } |
| |
| private void setMediaRecorderToDataSourceConfiguredState() { |
| try { |
| mMediaRecorder.reset(); |
| mMediaRecorder.setAudioSource(AUDIO_SOURCE); |
| mMediaRecorder.setOutputFormat(OUTPUT_FORMAT); |
| |
| /* Skip setAudioEncoder() and setOutputFile() calls if |
| * the method under test is setAudioEncoder() since this |
| * method can only be called once even in the DATASOURCECONFIGURED state |
| */ |
| if (mMethodUnderTest.toString() != "setAudioEncoder()") { |
| mMediaRecorder.setAudioEncoder(AUDIO_ENCODER); |
| } |
| |
| if (mMethodUnderTest.toString() != "setOutputFile()") { |
| mMediaRecorder.setOutputFile(RECORD_OUTPUT_PATH); |
| } |
| } catch(Exception e) { |
| fail("setMediaRecorderToDataSourceConfiguredState: Exception " + e.getClass().getName() + " was thrown."); |
| } |
| } |
| |
| /* |
| * There are a lot of ways to force the MediaRecorder object to enter |
| * the Error state. We arbitrary choose one here. |
| */ |
| private void setMediaRecorderToErrorState() { |
| try { |
| mMediaRecorder.reset(); |
| |
| /* Skip setAudioSource() if the method under test is setAudioEncoder() |
| * Because, otherwise, it is valid to call setAudioEncoder() after |
| * start() since start() will fail, and then the mMediaRecorder |
| * won't be set to the Error state |
| */ |
| if (mMethodUnderTest.toString() != "setAudioEncoder()") { |
| mMediaRecorder.setAudioSource(AUDIO_SOURCE); |
| } |
| |
| /* Skip setOutputFormat if the method under test is setOutputFile() |
| * Because, otherwise, it is valid to call setOutputFile() after |
| * start() since start() will fail, and then the mMediaRecorder |
| * won't be set to the Error state |
| */ |
| if (mMethodUnderTest.toString() != "setOutputFile()") { |
| mMediaRecorder.setOutputFormat(OUTPUT_FORMAT); |
| } |
| |
| mMediaRecorder.start(); |
| } catch(Exception e) { |
| if (!(e instanceof IllegalStateException)) { |
| fail("setMediaRecorderToErrorState: Exception " + e.getClass().getName() + " was thrown."); |
| } |
| } |
| Log.v(TAG, "setMediaRecorderToErrorState: done."); |
| } |
| |
| /* |
| * Sets the state of the MediaRecorder object to the specified one. |
| * |
| * @param state the state of the MediaRecorder object. |
| */ |
| private void setMediaRecorderToState(MediaRecorderStateErrors.MediaRecorderState state) { |
| mMediaRecorderState = state; |
| switch(state) { |
| case INITIAL: |
| // Does nothing. |
| break; |
| case INITIAL_AFTER_RESET: |
| setMediaRecorderToInitialStateAfterReset(); |
| break; |
| case INITIAL_AFTER_STOP: |
| setMediaRecorderToInitialStateAfterStop(); |
| break; |
| case INITIALIZED: |
| setMediaRecorderToInitializedState(); |
| break; |
| case DATASOURCECONFIGURED: |
| setMediaRecorderToDataSourceConfiguredState(); |
| break; |
| case PREPARED: |
| setMediaRecorderToPreparedState(); |
| break; |
| case RECORDING: |
| setMediaRecorderToRecordingState(); |
| break; |
| case ERROR: |
| setMediaRecorderToErrorState(); |
| break; |
| } |
| } |
| |
| /* |
| * Sets the error value of the corresponding state to the given error. |
| * |
| * @param state the state of the MediaRecorder object. |
| * @param error the value of the state error to be set. |
| */ |
| private void setStateError(MediaRecorderStateErrors.MediaRecorderState state, boolean error) { |
| switch(state) { |
| case INITIAL: |
| mStateErrors.errorInInitialState = error; |
| break; |
| case INITIAL_AFTER_RESET: |
| mStateErrors.errorInInitialStateAfterReset = error; |
| break; |
| case INITIAL_AFTER_STOP: |
| mStateErrors.errorInInitialStateAfterStop = error; |
| break; |
| case INITIALIZED: |
| mStateErrors.errorInInitializedState = error; |
| break; |
| case DATASOURCECONFIGURED: |
| mStateErrors.errorInDataSourceConfiguredState = error; |
| break; |
| case PREPARED: |
| mStateErrors.errorInPreparedState = error; |
| break; |
| case RECORDING: |
| mStateErrors.errorInRecordingState = error; |
| break; |
| case ERROR: |
| mStateErrors.errorInErrorState = error; |
| break; |
| } |
| } |
| |
| private void checkInitialState() { |
| callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.INITIAL); |
| } |
| |
| private void checkInitialStateAfterReset() { |
| callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.INITIAL_AFTER_RESET); |
| } |
| |
| private void checkInitialStateAfterStop() { |
| callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.INITIAL_AFTER_STOP); |
| } |
| |
| private void checkInitializedState() { |
| callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.INITIALIZED); |
| } |
| |
| private void checkPreparedState() { |
| callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.PREPARED); |
| } |
| |
| private void checkRecordingState() { |
| callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.RECORDING); |
| } |
| |
| private void checkDataSourceConfiguredState() { |
| callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.DATASOURCECONFIGURED); |
| } |
| |
| private void checkErrorState() { |
| callMediaRecorderMethodUnderTestInState(MediaRecorderStateErrors.MediaRecorderState.ERROR); |
| } |
| |
| /* |
| * Checks the given method under test in all possible states of the MediaRecorder object. |
| */ |
| private void checkMethodUnderTestInAllPossibleStates() { |
| // Must be called first. |
| checkInitialState(); |
| |
| // The sequence of the following method calls should not |
| // affect the test results. |
| checkErrorState(); |
| checkInitialStateAfterReset(); |
| checkInitialStateAfterStop(); |
| checkInitializedState(); |
| checkRecordingState(); |
| checkDataSourceConfiguredState(); |
| checkPreparedState(); |
| } |
| |
| /* |
| * Cleans up all the internal object references. |
| */ |
| private void cleanUp() { |
| mMediaRecorder.release(); |
| mMediaRecorder = null; |
| mMediaRecorderState = null; |
| mStateErrors = null; |
| mMethodUnderTest = null; |
| } |
| } |