Added tests for audio effects.

AudioEffectTest.java: tests for base AudioEffect class.
BassBoostTest.java: tests for bass boost effect
EnvReverbTest.java: tests for environmental reverb
PresetReverbTest.java: tests for preset reverb
VirtualizerTest.java: tests for virtualizer
VisualizerTest.java: test for visualizer

There is no requirement on the quality of audio effects or the supported parameter ranges.
The tests just ensure that the platform exposes and responds to all methods in effect APIs.

Change-Id: Ibdd0bf937c30ce000184e0bdf2323655ebf1d839
diff --git a/tests/tests/media/src/android/media/cts/AudioEffectTest.java b/tests/tests/media/src/android/media/cts/AudioEffectTest.java
new file mode 100644
index 0000000..3d458c4
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/AudioEffectTest.java
@@ -0,0 +1,1379 @@
+/*
+ * Copyright (C) 2010 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.cts;
+
+import com.android.cts.stub.R;
+
+import android.content.res.AssetFileDescriptor;
+import android.media.AudioEffect;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.media.PresetReverb;
+import android.media.EnvironmentalReverb;
+import android.media.Equalizer;
+import android.media.MediaPlayer;
+
+import android.os.Looper;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+import java.util.UUID;
+
+@TestTargetClass(AudioEffect.class)
+public class AudioEffectTest extends AndroidTestCase {
+
+    private String TAG = "AudioEffectTest";
+    private final static int MIN_NUMBER_EFFECTS = 5;
+    // allow +/- 5% tolerance between set and get delays
+    private final static float DELAY_TOLERANCE = 1.05f;
+    // allow +/- 5% tolerance between set and get ratios
+    private final static float RATIO_TOLERANCE = 1.05f;
+
+    private AudioEffect mEffect = null;
+    private AudioEffect mEffect2 = null;
+    private int mSession = -1;
+    private boolean mHasControl = false;
+    private boolean mIsEnabled = false;
+    private int mChangedParameter = -1;
+    private boolean mInitialized = false;
+    private Looper mLooper = null;
+    private MediaPlayer mMediaPlayer = null;
+    private int mError = 0;
+
+    private final Object mLock = new Object();
+
+
+    //-----------------------------------------------------------------
+    // AUDIOEFFECT TESTS:
+    //----------------------------------
+
+    //-----------------------------------------------------------------
+    // 0 - static methods
+    //----------------------------------
+
+    //Test case 0.0: test queryEffects() and platfrom at least provides Equalizer, Bass Boost,
+    // Virtualizer, Environmental reverb and Preset reverb effects
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "queryEffects",
+            args = {}
+        )
+    })
+    public void test0_0QueryEffects() throws Exception {
+
+        AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();
+
+        assertTrue("test0_0QueryEffects: number of effects < MIN_NUMBER_EFFECTS: "+desc.length,
+                (desc.length >= MIN_NUMBER_EFFECTS));
+
+        boolean hasEQ = false;
+        boolean hasBassBoost = false;
+        boolean hasVirtualizer = false;
+        boolean hasEnvReverb = false;
+        boolean hasPresetReverb = false;
+
+        for (int i = 0; i < desc.length; i++) {
+            if (desc[i].mType.equals(AudioEffect.EFFECT_TYPE_EQUALIZER)) {
+                hasEQ = true;
+            } else if (desc[i].mType.equals(AudioEffect.EFFECT_TYPE_BASS_BOOST)) {
+                hasBassBoost = true;
+            } else if (desc[i].mType.equals(AudioEffect.EFFECT_TYPE_VIRTUALIZER)) {
+                hasVirtualizer = true;
+            } else if (desc[i].mType.equals(AudioEffect.EFFECT_TYPE_ENV_REVERB)) {
+                hasEnvReverb = true;
+            } else if (desc[i].mType.equals(AudioEffect.EFFECT_TYPE_PRESET_REVERB)) {
+                hasPresetReverb = true;
+            }
+        }
+        assertTrue("test0_0QueryEffects: equalizer not found", hasEQ);
+        assertTrue("test0_0QueryEffects: bass boost not found", hasBassBoost);
+        assertTrue("test0_0QueryEffects: virtualizer not found", hasVirtualizer);
+        assertTrue("test0_0QueryEffects: environmental reverb not found", hasEnvReverb);
+        assertTrue("test0_0QueryEffects: preset reverb not found", hasPresetReverb);
+    }
+
+    //-----------------------------------------------------------------
+    // 1 - constructor
+    //----------------------------------
+
+    //Test case 1.0: test constructor from effect type and get effect ID
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "AudioEffect",
+            args = {UUID.class, UUID.class, int.class, int.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getId",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "release",
+            args = {}
+        )
+    })
+    public void test1_0ConstructorFromType() throws Exception {
+        AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();
+        assertTrue("no effects found", (desc.length != 0));
+        for (int i = 0; i < desc.length; i++) {
+            try {
+                AudioEffect effect = new AudioEffect(desc[i].mType,
+                        AudioEffect.EFFECT_TYPE_NULL,
+                        0,
+                        0);
+                assertNotNull("could not create AudioEffect", effect);
+                try {
+                    assertTrue("invalid effect ID", (effect.getId() != 0));
+                } catch (IllegalStateException e) {
+                    fail("AudioEffect not initialized");
+                } finally {
+                    effect.release();
+                }
+            } catch (IllegalArgumentException e) {
+                fail("Effect not found: "+desc[i].mName);
+            } catch (UnsupportedOperationException e) {
+                fail("Effect library not loaded");
+            }
+        }
+    }
+
+    //Test case 1.1: test constructor from effect uuid
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "AudioEffect",
+            args = {UUID.class, UUID.class, int.class, int.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getId",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "release",
+            args = {}
+        )
+    })
+    public void test1_1ConstructorFromUuid() throws Exception {
+        AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();
+        assertTrue("no effects found", (desc.length != 0));
+        for (int i = 0; i < desc.length; i++) {
+            try {
+                AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_NULL,
+                        desc[i].mUuid,
+                        0,
+                        0);
+                assertNotNull("could not create AudioEffect", effect);
+                try {
+                    assertTrue("invalid effect ID", (effect.getId() != 0));
+                } catch (IllegalStateException e) {
+                    fail("AudioEffect not initialized");
+                } finally {
+                    effect.release();
+                }
+            } catch (IllegalArgumentException e) {
+                fail("Effect not found: "+desc[i].mName);
+            } catch (UnsupportedOperationException e) {
+                fail("Effect library not loaded");
+            }
+        }
+    }
+
+    //Test case 1.2: test constructor failure from unknown type
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "AudioEffect",
+            args = {UUID.class, UUID.class, int.class, int.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "release",
+            args = {}
+        )
+    })
+    public void test1_2ConstructorUnknownType() throws Exception {
+
+        try {
+            AudioEffect effect = new AudioEffect(UUID.randomUUID(),
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    0,
+                    0);
+            fail("could create random AudioEffect");
+            if (effect != null) {
+                effect.release();
+            }
+        } catch (IllegalArgumentException e) {
+
+        } catch (UnsupportedOperationException e) {
+            fail("Effect library not loaded");
+        }
+    }
+
+    //Test case 1.3: test getEnabled() failure when called on released effect
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "AudioEffect",
+            args = {UUID.class, UUID.class, int.class, int.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getEnabled",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "release",
+            args = {}
+        )
+    })
+    public void test1_3GetEnabledAfterRelease() throws Exception {
+
+        try {
+            AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    0,
+                    0);
+            assertNotNull("could not create AudioEffect", effect);
+            effect.release();
+            try {
+                effect.getEnabled();
+                fail("getEnabled() processed after release()");
+            } catch (IllegalStateException e) {
+
+            }
+        } catch (IllegalArgumentException e) {
+            fail("AudioEffect not found");
+        } catch (UnsupportedOperationException e) {
+            fail("Effect library not loaded");
+        }
+    }
+
+    //Test case 1.4: test contructor on mediaPlayer audio session
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnabled",
+            args = {boolean.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "MediaPlayer.getAudioSessionId",
+            args = {}
+        )
+    })
+    public void test1_4InsertOnMediaPlayer() throws Exception {
+        MediaPlayer mp = new MediaPlayer();
+        assertNotNull("could not create mediaplayer", mp);
+        AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(R.raw.testmp3);
+        mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+        afd.close();
+        getEffect(AudioEffect.EFFECT_TYPE_EQUALIZER, mp.getAudioSessionId());
+        try {
+            mEffect.setEnabled(true);
+
+        } catch (IllegalStateException e) {
+            fail("AudioEffect not initialized");
+        } finally {
+            mp.release();
+            releaseEffect();
+        }
+    }
+
+    //Test case 1.5: test auxiliary effect attachement on MediaPlayer
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getId",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "MediaPlayer.attachAuxEffect",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "MediaPlayer.setAuxEffectSendLevel",
+            args = {}
+        )
+    })
+    public void test1_5AuxiliaryOnMediaPlayer() throws Exception {
+        createMediaPlayerLooper();
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch(Exception e) {
+                fail("Looper creation: wait was interrupted.");
+            }
+        }
+        assertTrue(mInitialized);  // mMediaPlayer has been initialized?
+        mError = 0;
+
+        AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(R.raw.testmp3);
+        mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+        afd.close();
+        getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+        try {
+            synchronized(mLock) {
+                try {
+                    mMediaPlayer.attachAuxEffect(mEffect.getId());
+                    mMediaPlayer.setAuxEffectSendLevel(1.0f);
+                    mLock.wait(200);
+                } catch(Exception e) {
+                    fail("Attach effect: wait was interrupted.");
+                }
+            }
+            assertTrue("error on attachAuxEffect", mError == 0);
+
+        } catch (IllegalStateException e) {
+            fail("attach aux effect failed");
+        } finally {
+            terminateMediaPlayerLooper();
+            releaseEffect();
+        }
+    }
+
+    //Test case 1.6: test auxiliary effect attachement failure before setDatasource
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getId",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "MediaPlayer.attachAuxEffect",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "MediaPlayer.setAuxEffectSendLevel",
+            args = {}
+        )
+    })
+    public void test1_6AuxiliaryOnMediaPlayerFailure() throws Exception {
+        createMediaPlayerLooper();
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch(Exception e) {
+                fail("Looper creation: wait was interrupted.");
+            }
+        }
+        assertTrue(mInitialized);  // mMediaPlayer has been initialized?
+        mError = 0;
+
+        getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+        try {
+            synchronized(mLock) {
+                try {
+                    mMediaPlayer.attachAuxEffect(mEffect.getId());
+                    mLock.wait(1000);
+                } catch(Exception e) {
+                    fail("Attach effect: wait was interrupted.");
+                }
+            }
+            assertTrue("no error on attachAuxEffect", mError != 0);
+
+        } catch (IllegalStateException e) {
+            fail("attach aux effect failed");
+        } finally {
+            terminateMediaPlayerLooper();
+            releaseEffect();
+        }
+    }
+
+
+    //Test case 1.7: test auxiliary effect attachement on AudioTrack
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getId",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "AudioTrack.attachAuxEffect",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "AudioTrack.setAuxEffectSendLevel",
+            args = {}
+        )
+    })
+    public void test1_7AuxiliaryOnAudioTrack() throws Exception {
+        AudioTrack track = null;
+        getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+        try {
+            track = new AudioTrack(
+                                AudioManager.STREAM_MUSIC,
+                                44100,
+                                AudioFormat.CHANNEL_OUT_MONO,
+                                AudioFormat.ENCODING_PCM_16BIT,
+                                AudioTrack.getMinBufferSize(44100,
+                                                            AudioFormat.CHANNEL_OUT_MONO,
+                                                            AudioFormat.ENCODING_PCM_16BIT),
+                                                            AudioTrack.MODE_STREAM);
+            assertNotNull("could not create AudioTrack", track);
+
+            int status = track.attachAuxEffect(mEffect.getId());
+            if (status != AudioTrack.SUCCESS) {
+                fail("could not attach aux effect");
+            }
+            status = track.setAuxEffectSendLevel(1.0f);
+            if (status != AudioTrack.SUCCESS) {
+                fail("could not set send level");
+            }
+        } catch (IllegalStateException e) {
+            fail("could not attach aux effect");
+        } catch (IllegalArgumentException e) {
+            fail("could not create AudioTrack");
+        } finally {
+            if (track != null) {
+                track.release();
+            }
+            releaseEffect();
+        }
+    }
+
+    //-----------------------------------------------------------------
+    // 2 - enable/ disable
+    //----------------------------------
+
+
+    //Test case 2.0: test setEnabled() and getEnabled() in valid state
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnabled",
+            args = {boolean.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getEnabled",
+            args = {}
+        )
+    })
+    public void test2_0SetEnabledGetEnabled() throws Exception {
+
+        try {
+            AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    0,
+                    0);
+            assertNotNull("could not create AudioEffect", effect);
+            try {
+                effect.setEnabled(true);
+                assertTrue("invalid state from getEnabled", effect.getEnabled());
+                effect.setEnabled(false);
+                assertFalse("invalid state to getEnabled", effect.getEnabled());
+
+            } catch (IllegalStateException e) {
+                fail("setEnabled() in wrong state");
+            } finally {
+                effect.release();
+            }
+        } catch (IllegalArgumentException e) {
+            fail("AudioEffect not found");
+
+        } catch (UnsupportedOperationException e) {
+            fail("Effect library not loaded");
+        }
+    }
+
+    //Test case 2.1: test setEnabled() throws exception after release
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnabled",
+            args = {boolean.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getEnabled",
+            args = {}
+        )
+    })
+    public void test2_1SetEnabledAfterRelease() throws Exception {
+
+        try {
+            AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    0,
+                    0);
+            assertNotNull("could not create AudioEffect", effect);
+            effect.release();
+            try {
+                effect.setEnabled(true);
+                fail("setEnabled() processed after release");
+            } catch (IllegalStateException e) {
+                // test passed
+            }
+        } catch (IllegalArgumentException e) {
+            fail("AudioEffect not found");
+        } catch (UnsupportedOperationException e) {
+            fail("Effect library not loaded");
+        }
+    }
+
+    //-----------------------------------------------------------------
+    // 3 - set/get parameters
+    //----------------------------------
+
+    //Test case 3.0: test setParameter(byte[], byte[]) / getParameter(byte[], byte[])
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setParameter",
+            args = {byte[].class, byte[].class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getParameter",
+            args = {byte[].class, byte[].class}
+        )
+    })
+    public void test3_0SetParameterByteArrayByteArray() throws Exception {
+        getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+        try {
+            byte[] param = mEffect.intToByteArray(PresetReverb.PARAM_PRESET);
+            byte[] value = new byte[2];
+            int status = mEffect.getParameter(param, value);
+            assertEquals("getParameter 1 failed", AudioEffect.SUCCESS, status);
+            short preset = PresetReverb.PRESET_SMALLROOM;
+            if (mEffect.byteArrayToShort(value) == preset) {
+                preset = PresetReverb.PRESET_MEDIUMROOM;
+            }
+            value = mEffect.shortToByteArray(preset);
+            status = mEffect.setParameter(param, value);
+            assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
+            status = mEffect.getParameter(param, value);
+            assertEquals("getParameter 2 failed", AudioEffect.SUCCESS, status);
+            assertEquals("get/set Parameter failed", preset,
+                    mEffect.byteArrayToShort(value));
+
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("setParameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("setParameter() called in wrong state");
+        } finally {
+            releaseEffect();
+        }
+    }
+
+    //Test case 3.1: test setParameter(int, int) / getParameter(int, int[])
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setParameter",
+            args = {int.class, int.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getParameter",
+            args = {int.class, int[].class}
+        )
+    })
+    public void test3_1SetParameterIntInt() throws Exception {
+        getEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB, 0);
+        try {
+            int param = EnvironmentalReverb.PARAM_DECAY_TIME;
+            int[] value = new int[1];
+            int status = mEffect.getParameter(param, value);
+            assertEquals("getParameter 1 failed", AudioEffect.SUCCESS, status);
+            int time = 500;
+            if (value[0] == time) {
+                time = 1000;
+            }
+            status = mEffect.setParameter(param, time);
+            assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
+            status = mEffect.getParameter(param, value);
+            assertEquals("getParameter 2 failed", AudioEffect.SUCCESS, status);
+            assertTrue("got incorrect decay time",
+                    ((float)value[0] > (float)(time / DELAY_TOLERANCE)) &&
+                    ((float)value[0] < (float)(time * DELAY_TOLERANCE)));
+
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("setParameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("setParameter() called in wrong state");
+        } finally {
+            releaseEffect();
+        }
+    }
+
+    //Test case 3.2: test setParameter(int, short) / getParameter(int, short[])
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setParameter",
+            args = {int.class, short.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getParameter",
+            args = {int.class, short[].class}
+        )
+    })
+    public void test3_2SetParameterIntShort() throws Exception {
+        getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+        try {
+            int param = PresetReverb.PARAM_PRESET;
+            short[] value = new short[1];
+            int status = mEffect.getParameter(param, value);
+            assertEquals("getParameter 1 failed", AudioEffect.SUCCESS, status);
+            short preset = PresetReverb.PRESET_SMALLROOM;
+            if (value[0] == preset) {
+                preset = PresetReverb.PRESET_MEDIUMROOM;
+            }
+            status = mEffect.setParameter(param, preset);
+            assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
+            status = mEffect.getParameter(param, value);
+            assertEquals("getParameter 2 failed", AudioEffect.SUCCESS, status);
+            assertEquals("get/set Parameter failed", preset, value[0]);
+
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("setParameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("setParameter() called in wrong state");
+        } finally {
+            releaseEffect();
+        }
+    }
+
+    //Test case 3.3: test setParameter(int, byte[]) / getParameter(int, byte[])
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setParameter",
+            args = {int.class, byte[].class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getParameter",
+            args = {int.class, byte[].class}
+        )
+    })
+    public void test3_3SetParameterIntByteArray() throws Exception {
+        getEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB, 0);
+        try {
+            int param = EnvironmentalReverb.PARAM_DECAY_TIME;
+            byte[] value = new byte[4];
+            int status = mEffect.getParameter(param, value);
+            assertEquals("getParameter 1 failed", AudioEffect.SUCCESS, status);
+            int time = 500;
+            if (mEffect.byteArrayToInt(value) == time) {
+                time = 1000;
+            }
+            value = mEffect.intToByteArray(time);
+            status = mEffect.setParameter(param, value);
+            assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
+            status = mEffect.getParameter(param, value);
+            assertEquals("getParameter 2 failed", AudioEffect.SUCCESS, status);
+            int time2 = mEffect.byteArrayToInt(value);
+            assertTrue("got incorrect decay time",
+                    ((float)time2 > (float)(time / DELAY_TOLERANCE)) &&
+                    ((float)time2 < (float)(time * DELAY_TOLERANCE)));
+
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("setParameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("setParameter() called in wrong state");
+        } finally {
+            releaseEffect();
+        }
+    }
+
+    //Test case 3.4: test setParameter(int[], int[]) / getParameter(int[], int[])
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setParameter",
+            args = {int[].class, int[].class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getParameter",
+            args = {int[].class, int[].class}
+        )
+    })
+    public void test3_4SetParameterIntArrayIntArray() throws Exception {
+        getEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB, 0);
+        try {
+            int[] param = new int[1];
+            int[] value = new int[1];
+            param[0] = EnvironmentalReverb.PARAM_DECAY_TIME;
+            int status = mEffect.getParameter(param, value);
+            assertEquals("getParameter 1 failed", AudioEffect.SUCCESS, status);
+            int[] time = new int[1];
+            time[0] = 500;
+            if (value[0] == time[0]) {
+                time[0] = 1000;
+            }
+            status = mEffect.setParameter(param, time);
+            assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
+            status = mEffect.getParameter(param, value);
+            assertEquals("getParameter 2 failed", AudioEffect.SUCCESS, status);
+            assertTrue("got incorrect decay time",
+                    ((float)value[0] > (float)(time[0] / DELAY_TOLERANCE)) &&
+                    ((float)value[0] < (float)(time[0] * DELAY_TOLERANCE)));
+
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("setParameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("setParameter() called in wrong state");
+        } finally {
+            releaseEffect();
+        }
+    }
+
+    //Test case 3.5: test setParameter(int[], short[]) / getParameter(int[], short[])
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setParameter",
+            args = {int[].class, short[].class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getParameter",
+            args = {int[].class, short[].class}
+        )
+    })
+
+    public void test3_5SetParameterIntArrayShortArray() throws Exception {
+        getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+        try {
+            int[] param = new int[1];
+            param[0] = PresetReverb.PARAM_PRESET;
+            short[] value = new short[1];
+            int status = mEffect.getParameter(param, value);
+            assertEquals("getParameter 1 failed", AudioEffect.SUCCESS, status);
+            short[] preset = new short[1];
+            preset[0] = PresetReverb.PRESET_SMALLROOM;
+            if (value[0] == preset[0]) {
+                preset[0] = PresetReverb.PRESET_MEDIUMROOM;
+            }
+            status = mEffect.setParameter(param, preset);
+            assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
+            status = mEffect.getParameter(param, value);
+            assertEquals("getParameter 2 failed", AudioEffect.SUCCESS, status);
+            assertEquals("get/set Parameter failed", preset[0], value[0]);
+
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("setParameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("setParameter() called in wrong state");
+        } finally {
+            releaseEffect();
+        }
+    }
+
+    //Test case 3.6: test setParameter(int[], byte[]) / getParameter(int[], byte[])
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setParameter",
+            args = {int[].class, byte[].class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getParameter",
+            args = {int[].class, byte[].class}
+        )
+    })
+    public void test3_6SetParameterIntArrayByteArray() throws Exception {
+        getEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB, 0);
+        try {
+            int[] param = new int[1];
+            param[0] = EnvironmentalReverb.PARAM_DECAY_TIME;
+            byte[] value = new byte[4];
+            int status = mEffect.getParameter(param, value);
+            assertEquals("getParameter 1 failed", AudioEffect.SUCCESS, status);
+            int time = 500;
+            if (mEffect.byteArrayToInt(value) == time) {
+                time = 1000;
+            }
+
+            status = mEffect.setParameter(param, mEffect.intToByteArray(time));
+            assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
+            status = mEffect.getParameter(param, value);
+            assertEquals("getParameter 2 failed", AudioEffect.SUCCESS, status);
+            int time2 = mEffect.byteArrayToInt(value);
+            assertTrue("got incorrect decay time",
+                    ((float)time2 > (float)(time / DELAY_TOLERANCE)) &&
+                    ((float)time2 < (float)(time * DELAY_TOLERANCE)));
+
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("setParameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("setParameter() called in wrong state");
+        } finally {
+            releaseEffect();
+        }
+    }
+
+    //Test case 3.7: test setParameter() throws exception after release()
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setParameter",
+            args = {int.class, short.class}
+        )
+    })
+    public void test3_7SetParameterAfterRelease() throws Exception {
+        AudioEffect effect = null;
+        try {
+            effect = new AudioEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            assertNotNull("could not create AudioEffect", effect);
+            effect.release();
+            effect.setParameter(PresetReverb.PARAM_PRESET, PresetReverb.PRESET_SMALLROOM);
+            fail("setParameter() processed after release");
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("setParameter() rejected");
+        } catch (IllegalStateException e) {
+            // test passed
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+    }
+
+    //Test case 3.8: test getParameter() throws exception after release()
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setParameter",
+            args = {int.class, short[].class}
+        )
+    })
+    public void test3_8GetParameterAfterRelease() throws Exception {
+        AudioEffect effect = null;
+        try {
+            effect = new AudioEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            assertNotNull("could not create AudioEffect", effect);
+            effect.release();
+            short[] value = new short[1];
+            effect.getParameter(PresetReverb.PARAM_PRESET, value);
+            fail("getParameter() processed after release");
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("getParameter() rejected");
+        } catch (IllegalStateException e) {
+            // test passed
+        } finally {
+            if (effect != null) {
+                effect.release();
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------
+    // 4 priority and listeners
+    //----------------------------------
+
+    //Test case 4.0: test control passed to higher priority client
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "hasControl",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnabled",
+            args = {boolean.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getEnabled",
+            args = {}
+        )
+    })
+    public void test4_0setEnabledLowerPriority() throws Exception {
+        AudioEffect effect1 = null;
+        AudioEffect effect2 = null;
+        try {
+            effect1 = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            effect2 = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    1,
+                    0);
+
+            assertNotNull("could not create AudioEffect", effect1);
+            assertNotNull("could not create AudioEffect", effect2);
+
+            assertTrue("Effect2 does not have control", effect2.hasControl());
+            assertFalse("Effect1 has control", effect1.hasControl());
+            assertTrue("Effect1 can enable",
+                    effect1.setEnabled(true) == AudioEffect.ERROR_INVALID_OPERATION);
+            assertFalse("Effect1 has enabled", effect2.getEnabled());
+
+        } catch (IllegalArgumentException e) {
+            fail("Effect not found");
+        } catch (UnsupportedOperationException e) {
+            fail("Effect library not loaded");
+        } finally {
+            if (effect1 != null) {
+                effect1.release();
+            }
+            if (effect2 != null) {
+                effect2.release();
+            }
+        }
+    }
+
+    //Test case 4.1: test control passed to higher priority client
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setParameter",
+            args = {int.class, short.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getParameter",
+            args = {int.class, short[].class}
+        )
+    })
+    public void test4_1setParameterLowerPriority() throws Exception {
+        AudioEffect effect1 = null;
+        AudioEffect effect2 = null;
+        try {
+            effect1 = new AudioEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB,
+                                    AudioEffect.EFFECT_TYPE_NULL,
+                                    0,
+                                    0);
+            effect2 = new AudioEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB,
+                    AudioEffect.EFFECT_TYPE_NULL,
+                    1,
+                    0);
+
+            assertNotNull("could not create AudioEffect", effect1);
+            assertNotNull("could not create AudioEffect", effect2);
+
+            int status = effect2.setParameter(PresetReverb.PARAM_PRESET,
+                    PresetReverb.PRESET_SMALLROOM);
+            assertEquals("Effect2 setParameter failed",
+                    AudioEffect.SUCCESS, status);
+
+            status = effect1.setParameter(PresetReverb.PARAM_PRESET,
+                    PresetReverb.PRESET_MEDIUMROOM);
+            assertEquals("Effect1 setParameter did not fail",
+                    AudioEffect.ERROR_INVALID_OPERATION, status);
+
+            short[] value = new short[1];
+            status = effect2.getParameter(PresetReverb.PARAM_PRESET, value);
+            assertEquals("Effect2 getParameter failed",
+                    AudioEffect.SUCCESS, status);
+            assertEquals("Effect1 changed parameter", PresetReverb.PRESET_SMALLROOM
+                    , value[0]);
+
+
+        } catch (IllegalArgumentException e) {
+            fail("Effect not found");
+        } catch (UnsupportedOperationException e) {
+            fail("Effect library not loaded");
+        } finally {
+            if (effect1 != null) {
+                effect1.release();
+            }
+            if (effect2 != null) {
+                effect2.release();
+            }
+        }
+    }
+
+    //Test case 4.2: test control status listener
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setControlStatusListener",
+            args = {AudioEffect.OnControlStatusChangeListener.class}
+        )
+    })
+    public void test4_2ControlStatusListener() throws Exception {
+
+        mHasControl = true;
+        createListenerLooper(true, false, false);
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch(Exception e) {
+                fail("Looper creation: wait was interrupted.");
+            }
+        }
+        assertTrue(mInitialized);
+        synchronized(mLock) {
+            try {
+                getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+                mLock.wait(1000);
+            } catch(Exception e) {
+                fail("Create second effect: wait was interrupted.");
+            } finally {
+                releaseEffect();
+                terminateListenerLooper();
+            }
+        }
+        assertFalse("effect control not lost by effect1", mHasControl);
+    }
+
+    //Test case 4.3: test enable status listener
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnableStatusListener",
+            args = {AudioEffect.OnEnableStatusChangeListener.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnabled",
+            args = {boolean.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getEnabled",
+            args = {}
+        )
+    })
+    public void test4_3EnableStatusListener() throws Exception {
+
+        createListenerLooper(false, true, false);
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch(Exception e) {
+                fail("Looper creation: wait was interrupted.");
+            }
+        }
+        assertTrue(mInitialized);
+        mEffect2.setEnabled(true);
+        mIsEnabled = true;
+
+        getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+        assertTrue("effect not enabled", mEffect.getEnabled());
+        synchronized(mLock) {
+            try {
+                mEffect.setEnabled(false);
+                mLock.wait(1000);
+            } catch(Exception e) {
+                fail("Second effect setEnabled: wait was interrupted.");
+            } finally {
+                releaseEffect();
+                terminateListenerLooper();
+            }
+        }
+        assertFalse("enable status not updated", mIsEnabled);
+    }
+
+    //Test case 4.4: test parameter changed listener
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setParameterListener",
+            args = {AudioEffect.OnParameterChangeListener.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setParameter",
+            args = {int.class, short.class}
+        )
+    })
+    public void test4_4ParameterChangedListener() throws Exception {
+
+        createListenerLooper(false, false, true);
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch(Exception e) {
+                fail("Looper creation: wait was interrupted.");
+            }
+        }
+        assertTrue(mInitialized);
+        int status = mEffect2.setParameter(PresetReverb.PARAM_PRESET,
+                PresetReverb.PRESET_SMALLROOM);
+        assertEquals("mEffect2 setParameter failed",
+                AudioEffect.SUCCESS, status);
+        getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+        synchronized(mLock) {
+            try {
+                mChangedParameter = -1;
+                mEffect.setParameter(PresetReverb.PARAM_PRESET,
+                        PresetReverb.PRESET_MEDIUMROOM);
+                mLock.wait(1000);
+            } catch(Exception e) {
+                fail("set Parameter: wait was interrupted.");
+            } finally {
+                releaseEffect();
+                terminateListenerLooper();
+            }
+        }
+        assertEquals("parameter change not received",
+                PresetReverb.PARAM_PRESET, mChangedParameter);
+    }
+
+    //-----------------------------------------------------------------
+    // 5 command method
+    //----------------------------------
+
+
+    //Test case 5.0: test command method
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "command",
+            args = {int.class, byte[].class, byte[].class}
+        )
+    })
+    public void test5_0Command() throws Exception {
+        getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+        try {
+            byte[] cmd = new byte[0];
+            byte[] reply = new byte[4];
+            // command 3 is ENABLE
+            int status = mEffect.command(3, cmd, reply);
+            assertEquals("command failed", AudioEffect.SUCCESS, status);
+            assertTrue("effect not enabled", mEffect.getEnabled());
+
+        } catch (IllegalStateException e) {
+            fail("command in illegal state");
+        } finally {
+            releaseEffect();
+        }
+    }
+
+
+    //-----------------------------------------------------------------
+    // private methods
+    //----------------------------------
+
+    private void getEffect(UUID type, int session) {
+         if (mEffect == null || session != mSession) {
+             if (session != mSession && mEffect != null) {
+                 mEffect.release();
+                 mEffect = null;
+             }
+             try {
+                 mEffect = new AudioEffect(type,
+                                             AudioEffect.EFFECT_TYPE_NULL,
+                                             0,
+                                             session);
+                 mSession = session;
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "getEffect() AudioEffect not found exception: "+e);
+            } catch (UnsupportedOperationException e) {
+                Log.e(TAG, "getEffect() Effect library not loaded exception: "+e);
+            }
+         }
+         assertNotNull("could not create mEffect", mEffect);
+    }
+
+    private void releaseEffect() {
+        if (mEffect != null) {
+            mEffect.release();
+            mEffect = null;
+        }
+    }
+
+    // Initializes the equalizer listener looper
+    class ListenerThread extends Thread {
+        boolean mControl;
+        boolean mEnable;
+        boolean mParameter;
+
+        public ListenerThread(boolean control, boolean enable, boolean parameter) {
+            super();
+            mControl = control;
+            mEnable = enable;
+            mParameter = parameter;
+        }
+    }
+
+    private void createListenerLooper(boolean control, boolean enable, boolean parameter) {
+        mInitialized = false;
+        new ListenerThread(control, enable, parameter) {
+            @Override
+            public void run() {
+                // Set up a looper
+                Looper.prepare();
+
+                // Save the looper so that we can terminate this thread
+                // after we are done with it.
+                mLooper = Looper.myLooper();
+
+                mEffect2 = new AudioEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB,
+                        AudioEffect.EFFECT_TYPE_NULL,
+                        0,
+                        0);
+                assertNotNull("could not create Equalizer2", mEffect2);
+
+                if (mControl) {
+                    mEffect2.setControlStatusListener(
+                            new AudioEffect.OnControlStatusChangeListener() {
+                        public void onControlStatusChange(
+                                AudioEffect effect, boolean controlGranted) {
+                            synchronized(mLock) {
+                                if (effect == mEffect2) {
+                                    mHasControl = controlGranted;
+                                    mLock.notify();
+                                }
+                            }
+                        }
+                    });
+                }
+                if (mEnable) {
+                    mEffect2.setEnableStatusListener(
+                            new AudioEffect.OnEnableStatusChangeListener() {
+                        public void onEnableStatusChange(AudioEffect effect, boolean enabled) {
+                            synchronized(mLock) {
+                                if (effect == mEffect2) {
+                                    mIsEnabled = enabled;
+                                    mLock.notify();
+                                }
+                            }
+                        }
+                    });
+                }
+                if (mParameter) {
+                    mEffect2.setParameterListener(new AudioEffect.OnParameterChangeListener() {
+                        public void onParameterChange(AudioEffect effect, int status, byte[] param,
+                                byte[] value)
+                        {
+                            synchronized(mLock) {
+                                if (effect == mEffect2) {
+                                    mChangedParameter = mEffect2.byteArrayToInt(param);
+                                    mLock.notify();
+                                }
+                            }
+                        }
+                    });
+                }
+
+                synchronized(mLock) {
+                    mInitialized = true;
+                    mLock.notify();
+                }
+                Looper.loop();  // Blocks forever until Looper.quit() is called.
+            }
+        }.start();
+    }
+
+    // Terminates the listener looper thread.
+    private void terminateListenerLooper() {
+        if (mEffect2 != null) {
+            mEffect2.release();
+            mEffect2 = null;
+        }
+        if (mLooper != null) {
+            mLooper.quit();
+            mLooper = null;
+        }
+    }
+
+    /*
+     * Initializes the message looper so that the MediaPlayer object can
+     * receive the callback messages.
+     */
+    private void createMediaPlayerLooper() {
+        mInitialized = false;
+        new Thread() {
+            @Override
+            public void run() {
+                // Set up a looper to be used by mMediaPlayer.
+                Looper.prepare();
+
+                // Save the looper so that we can terminate this thread
+                // after we are done with it.
+                mLooper = Looper.myLooper();
+
+                mMediaPlayer = new MediaPlayer();
+                mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+                    public boolean onError(MediaPlayer player, int what, int extra) {
+                        synchronized(mLock) {
+                            mError = what;
+                            mLock.notify();
+                        }
+                        return true;
+                    }
+                });
+                mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+                    public void onCompletion(MediaPlayer player) {
+                        synchronized(mLock) {
+                            mLock.notify();
+                        }
+                    }
+                });
+                synchronized(mLock) {
+                    mInitialized = true;
+                    mLock.notify();
+                }
+                Looper.loop();  // Blocks forever until Looper.quit() is called.
+            }
+        }.start();
+    }
+    /*
+     * Terminates the message looper thread.
+     */
+    private void terminateMediaPlayerLooper() {
+        if (mLooper != null) {
+            mLooper.quit();
+            mLooper = null;
+        }
+        if (mMediaPlayer != null) {
+            mMediaPlayer.release();
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/tests/tests/media/src/android/media/cts/BassBoostTest.java b/tests/tests/media/src/android/media/cts/BassBoostTest.java
new file mode 100644
index 0000000..d0b16e4
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/BassBoostTest.java
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2010 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.cts;
+
+import android.media.AudioEffect;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.BassBoost;
+import android.os.Looper;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+
+@TestTargetClass(BassBoost.class)
+public class BassBoostTest extends AndroidTestCase {
+
+    private String TAG = "BassBoostTest";
+    private final static short TEST_STRENGTH = 500;
+    private final static short TEST_STRENGTH2 = 1000;
+    private final static float STRENGTH_TOLERANCE = 1.1f;  // 10%
+
+    private BassBoost mBassBoost = null;
+    private BassBoost mBassBoost2 = null;
+    private int mSession = -1;
+    private boolean mHasControl = false;
+    private boolean mIsEnabled = false;
+    private int mChangedParameter = -1;
+    private boolean mInitialized = false;
+    private Looper mLooper = null;
+    private final Object mLock = new Object();
+
+    //-----------------------------------------------------------------
+    // BASS BOOST TESTS:
+    //----------------------------------
+
+    //-----------------------------------------------------------------
+    // 0 - constructor
+    //----------------------------------
+
+    //Test case 0.0: test constructor and release
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "BassBoost",
+            args = {int.class, int.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getId",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "release",
+            args = {}
+        )
+    })
+    public void test0_0ConstructorAndRelease() throws Exception {
+        BassBoost eq = null;
+        try {
+            eq = new BassBoost(0, 0);
+            assertNotNull("could not create BassBoost", eq);
+            try {
+                assertTrue("invalid effect ID", (eq.getId() != 0));
+            } catch (IllegalStateException e) {
+                fail("BassBoost not initialized");
+            }
+            // test passed
+        } catch (IllegalArgumentException e) {
+            fail("BassBoost not found");
+        } catch (UnsupportedOperationException e) {
+            fail("Effect library not loaded");
+        } finally {
+            if (eq != null) {
+                eq.release();
+            }
+        }
+    }
+
+
+    //-----------------------------------------------------------------
+    // 1 - get/set parameters
+    //----------------------------------
+
+    //Test case 1.0: test strength
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getStrengthSupported",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setStrength",
+            args = {short.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getRoundedStrength",
+            args = {}
+        )
+    })
+    public void test1_0Strength() throws Exception {
+        getBassBoost(0);
+        try {
+            if (mBassBoost.getStrengthSupported()) {
+                short strength = mBassBoost.getRoundedStrength();
+                strength = (strength == TEST_STRENGTH) ? TEST_STRENGTH2 : TEST_STRENGTH;
+                mBassBoost.setStrength((short)strength);
+                short strength2 = mBassBoost.getRoundedStrength();
+                // allow STRENGTH_TOLERANCE difference between set strength and rounded strength
+                assertTrue("got incorrect strength",
+                        ((float)strength2 > (float)strength / STRENGTH_TOLERANCE) &&
+                        ((float)strength2 < (float)strength * STRENGTH_TOLERANCE));
+            } else {
+                short strength = mBassBoost.getRoundedStrength();
+                assertTrue("got incorrect strength", strength >= 0 && strength <= 1000);
+            }
+            // test passed
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("get parameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("get parameter() called in wrong state");
+        } finally {
+            releaseBassBoost();
+        }
+    }
+
+    //Test case 1.1: test properties
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getProperties",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setProperties",
+            args = {BassBoost.Settings.class}
+        )
+    })
+    public void test1_1Properties() throws Exception {
+        getBassBoost(0);
+        try {
+            BassBoost.Settings settings = mBassBoost.getProperties();
+            String str = settings.toString();
+            settings = new BassBoost.Settings(str);
+
+            short strength = settings.strength;
+            if (mBassBoost.getStrengthSupported()) {
+                strength = (strength == TEST_STRENGTH) ? TEST_STRENGTH2 : TEST_STRENGTH;
+            }
+            settings.strength = strength;
+            mBassBoost.setProperties(settings);
+            settings = mBassBoost.getProperties();
+
+            if (mBassBoost.getStrengthSupported()) {
+                // allow STRENGTH_TOLERANCE difference between set strength and rounded strength
+                assertTrue("got incorrect strength",
+                        ((float)settings.strength > (float)strength / STRENGTH_TOLERANCE) &&
+                        ((float)settings.strength < (float)strength * STRENGTH_TOLERANCE));
+            }
+            // test passed
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("get parameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("get parameter() called in wrong state");
+        } finally {
+            releaseBassBoost();
+        }
+    }
+
+    //Test case 1.2: test setStrength() throws exception after release
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "release",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setStrength",
+            args = {short.class}
+        )
+    })
+    public void test1_2SetStrengthAfterRelease() throws Exception {
+        getBassBoost(0);
+        mBassBoost.release();
+        try {
+            mBassBoost.setStrength(TEST_STRENGTH);
+            fail("setStrength() processed after release()");
+        } catch (IllegalStateException e) {
+            // test passed
+        } finally {
+            releaseBassBoost();
+        }
+    }
+
+    //-----------------------------------------------------------------
+    // 2 - Effect enable/disable
+    //----------------------------------
+
+    //Test case 2.0: test setEnabled() and getEnabled() in valid state
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnabled",
+            args = {boolean.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getEnabled",
+            args = {}
+        )
+    })
+    public void test2_0SetEnabledGetEnabled() throws Exception {
+        getBassBoost(0);
+        try {
+            mBassBoost.setEnabled(true);
+            assertTrue("invalid state from getEnabled", mBassBoost.getEnabled());
+            mBassBoost.setEnabled(false);
+            assertFalse("invalid state to getEnabled", mBassBoost.getEnabled());
+            // test passed
+        } catch (IllegalStateException e) {
+            fail("setEnabled() in wrong state");
+        } finally {
+            releaseBassBoost();
+        }
+    }
+
+    //Test case 2.1: test setEnabled() throws exception after release
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "release",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnabled",
+            args = {boolean.class}
+        )
+    })
+    public void test2_1SetEnabledAfterRelease() throws Exception {
+        getBassBoost(0);
+        mBassBoost.release();
+        try {
+            mBassBoost.setEnabled(true);
+            fail("setEnabled() processed after release()");
+        } catch (IllegalStateException e) {
+            // test passed
+        } finally {
+            releaseBassBoost();
+        }
+    }
+
+    //-----------------------------------------------------------------
+    // 3 priority and listeners
+    //----------------------------------
+
+    //Test case 3.0: test control status listener
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setControlStatusListener",
+            args = {AudioEffect.OnControlStatusChangeListener.class}
+        )
+    })
+    public void test3_0ControlStatusListener() throws Exception {
+        mHasControl = true;
+        createListenerLooper(true, false, false);
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Looper creation: wait was interrupted.");
+            }
+        }
+        assertTrue(mInitialized);
+        synchronized(mLock) {
+            try {
+                getBassBoost(0);
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Create second effect: wait was interrupted.");
+            } finally {
+                releaseBassBoost();
+                terminateListenerLooper();
+            }
+        }
+        assertFalse("effect control not lost by effect1", mHasControl);
+    }
+
+    //Test case 3.1: test enable status listener
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnableStatusListener",
+            args = {AudioEffect.OnEnableStatusChangeListener.class}
+        )
+    })
+    public void test3_1EnableStatusListener() throws Exception {
+        createListenerLooper(false, true, false);
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Looper creation: wait was interrupted.");
+            }
+        }
+        assertTrue(mInitialized);
+        mBassBoost2.setEnabled(true);
+        mIsEnabled = true;
+        getBassBoost(0);
+        synchronized(mLock) {
+            try {
+                mBassBoost.setEnabled(false);
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Create second effect: wait was interrupted.");
+            } finally {
+                releaseBassBoost();
+                terminateListenerLooper();
+            }
+        }
+        assertFalse("enable status not updated", mIsEnabled);
+    }
+
+    //Test case 3.2: test parameter changed listener
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setParameterListener",
+            args = {BassBoost.OnParameterChangeListener.class}
+        )
+    })
+    public void test3_2ParameterChangedListener() throws Exception {
+        createListenerLooper(false, false, true);
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Looper creation: wait was interrupted.");
+            }
+        }
+        assertTrue(mInitialized);
+        getBassBoost(0);
+        synchronized(mLock) {
+            try {
+                mChangedParameter = -1;
+                mBassBoost.setStrength(TEST_STRENGTH);
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Create second effect: wait was interrupted.");
+            } finally {
+                releaseBassBoost();
+                terminateListenerLooper();
+            }
+        }
+        assertEquals("parameter change not received",
+                BassBoost.PARAM_STRENGTH, mChangedParameter);
+    }
+
+    //-----------------------------------------------------------------
+    // private methods
+    //----------------------------------
+
+    private void getBassBoost(int session) {
+         if (mBassBoost == null || session != mSession) {
+             if (session != mSession && mBassBoost != null) {
+                 mBassBoost.release();
+                 mBassBoost = null;
+             }
+             try {
+                mBassBoost = new BassBoost(0, session);
+                mSession = session;
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "getBassBoost() BassBoost not found exception: "+e);
+            } catch (UnsupportedOperationException e) {
+                Log.e(TAG, "getBassBoost() Effect library not loaded exception: "+e);
+            }
+         }
+         assertNotNull("could not create mBassBoost", mBassBoost);
+    }
+
+    private void releaseBassBoost() {
+        if (mBassBoost != null) {
+            mBassBoost.release();
+            mBassBoost = null;
+        }
+    }
+
+    // Initializes the bassboot listener looper
+    class ListenerThread extends Thread {
+        boolean mControl;
+        boolean mEnable;
+        boolean mParameter;
+
+        public ListenerThread(boolean control, boolean enable, boolean parameter) {
+            super();
+            mControl = control;
+            mEnable = enable;
+            mParameter = parameter;
+        }
+    }
+
+    private void createListenerLooper(boolean control, boolean enable, boolean parameter) {
+        mInitialized = false;
+        new ListenerThread(control, enable, parameter) {
+            @Override
+            public void run() {
+                // Set up a looper
+                Looper.prepare();
+
+                // Save the looper so that we can terminate this thread
+                // after we are done with it.
+                mLooper = Looper.myLooper();
+
+                mBassBoost2 = new BassBoost(0, 0);
+                assertNotNull("could not create bassboot2", mBassBoost2);
+
+                if (mControl) {
+                    mBassBoost2.setControlStatusListener(
+                            new AudioEffect.OnControlStatusChangeListener() {
+                        public void onControlStatusChange(
+                                AudioEffect effect, boolean controlGranted) {
+                            synchronized(mLock) {
+                                if (effect == mBassBoost2) {
+                                    mHasControl = controlGranted;
+                                    mLock.notify();
+                                }
+                            }
+                        }
+                    });
+                }
+                if (mEnable) {
+                    mBassBoost2.setEnableStatusListener(
+                            new AudioEffect.OnEnableStatusChangeListener() {
+                        public void onEnableStatusChange(AudioEffect effect, boolean enabled) {
+                            synchronized(mLock) {
+                                if (effect == mBassBoost2) {
+                                    mIsEnabled = enabled;
+                                    mLock.notify();
+                                }
+                            }
+                        }
+                    });
+                }
+                if (mParameter) {
+                    mBassBoost2.setParameterListener(new BassBoost.OnParameterChangeListener() {
+                        public void onParameterChange(BassBoost effect, int status,
+                                int param, short value)
+                        {
+                            synchronized(mLock) {
+                                if (effect == mBassBoost2) {
+                                    mChangedParameter = param;
+                                    mLock.notify();
+                                }
+                            }
+                        }
+                    });
+                }
+
+                synchronized(mLock) {
+                    mInitialized = true;
+                    mLock.notify();
+                }
+                Looper.loop();  // Blocks forever until Looper.quit() is called.
+            }
+        }.start();
+    }
+
+    // Terminates the listener looper thread.
+    private void terminateListenerLooper() {
+        if (mBassBoost2 != null) {
+            mBassBoost2.release();
+            mBassBoost2 = null;
+        }
+        if (mLooper != null) {
+            mLooper.quit();
+            mLooper = null;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/tests/tests/media/src/android/media/cts/EnvReverbTest.java b/tests/tests/media/src/android/media/cts/EnvReverbTest.java
new file mode 100644
index 0000000..3854048
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/EnvReverbTest.java
@@ -0,0 +1,698 @@
+/*
+ * Copyright (C) 2010 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.cts;
+
+import android.media.AudioEffect;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.EnvironmentalReverb;
+import android.os.Looper;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+
+@TestTargetClass(EnvironmentalReverb.class)
+public class EnvReverbTest extends AndroidTestCase {
+
+    private String TAG = "EnvReverbTest";
+    private final static int MILLIBEL_TOLERANCE = 100;            // +/-1dB
+    private final static float DELAY_TOLERANCE = 1.05f;           // 5%
+    private final static float RATIO_TOLERANCE = 1.05f;           // 5%
+
+    private EnvironmentalReverb mReverb = null;
+    private EnvironmentalReverb mReverb2 = null;
+    private int mSession = -1;
+    private boolean mHasControl = false;
+    private boolean mIsEnabled = false;
+    private int mChangedParameter = -1;
+    private boolean mInitialized = false;
+    private Looper mLooper = null;
+    private final Object mLock = new Object();
+
+
+    //-----------------------------------------------------------------
+    // ENVIRONMENTAL REVERB TESTS:
+    //----------------------------------
+
+    //-----------------------------------------------------------------
+    // 0 - constructor
+    //----------------------------------
+
+    //Test case 0.0: test constructor and release
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "EnvironmentalReverb",
+            args = {int.class, int.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getId",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "release",
+            args = {}
+        )
+    })
+    public void test0_0ConstructorAndRelease() throws Exception {
+        EnvironmentalReverb envReverb = null;
+         try {
+            envReverb = new EnvironmentalReverb(0, 0);
+            assertNotNull("could not create EnvironmentalReverb", envReverb);
+            try {
+                assertTrue("invalid effect ID", (envReverb.getId() != 0));
+            } catch (IllegalStateException e) {
+                fail("EnvironmentalReverb not initialized");
+            }
+        } catch (IllegalArgumentException e) {
+            fail("EnvironmentalReverb not found");
+        } catch (UnsupportedOperationException e) {
+            fail("Effect library not loaded");
+        } finally {
+            if (envReverb != null) {
+                envReverb.release();
+            }
+        }
+    }
+
+
+    //-----------------------------------------------------------------
+    // 1 - get/set parameters
+    //----------------------------------
+
+    //Test case 1.0: test room level and room HF level
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setRoomLevel",
+            args = {short.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getRoomLevel",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setRoomHFLevel",
+            args = {short.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getRoomHFLevel",
+            args = {}
+        )
+    })
+    public void test1_0Room() throws Exception {
+        getReverb(0);
+        try {
+            short level = mReverb.getRoomLevel();
+            level = (short)((level == 0) ? -1000 : 0);
+            mReverb.setRoomLevel(level);
+            short level2 = mReverb.getRoomLevel();
+            assertTrue("got incorrect room level",
+                    (level2 > (level - MILLIBEL_TOLERANCE)) &&
+                    (level2 < (level + MILLIBEL_TOLERANCE)));
+
+            level = mReverb.getRoomHFLevel();
+            level = (short)((level == 0) ? -1000 : 0);
+            mReverb.setRoomHFLevel(level);
+            level2 = mReverb.getRoomHFLevel();
+            assertTrue("got incorrect room HF level",
+                    (level2 > (level - MILLIBEL_TOLERANCE)) &&
+                    (level2 < (level + MILLIBEL_TOLERANCE)));
+
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("get parameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("get parameter() called in wrong state");
+        } finally {
+            releaseReverb();
+        }
+    }
+
+    //Test case 1.1: test decay time and ratio
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setDecayTime",
+            args = {int.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getDecayTime",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setDecayHFRatio",
+            args = {short.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getDecayHFRatio",
+            args = {}
+        )
+    })
+    public void test1_1Decay() throws Exception {
+        getReverb(0);
+        try {
+            int time = mReverb.getDecayTime();
+            time = (time == 500) ? 1000 : 500;
+            mReverb.setDecayTime(time);
+            int time2 = mReverb.getDecayTime();
+            assertTrue("got incorrect decay time",
+                    ((float)time2 > (float)(time / DELAY_TOLERANCE)) &&
+                    ((float)time2 < (float)(time * DELAY_TOLERANCE)));
+            short ratio = mReverb.getDecayHFRatio();
+            ratio = (short)((ratio == 500) ? 1000 : 500);
+            mReverb.setDecayHFRatio(ratio);
+            short ratio2 = mReverb.getDecayHFRatio();
+            assertTrue("got incorrect decay HF ratio",
+                    ((float)ratio2 > (float)(ratio / RATIO_TOLERANCE)) &&
+                    ((float)ratio2 < (float)(ratio * RATIO_TOLERANCE)));
+
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("get parameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("get parameter() called in wrong state");
+        } finally {
+            releaseReverb();
+        }
+    }
+
+
+    //Test case 1.2: test reverb level and delay
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setReverbLevel",
+            args = {short.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getReverbLevel",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setReverbDelay",
+            args = {int.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getReverbDelay",
+            args = {}
+        )
+    })
+    public void test1_2Reverb() throws Exception {
+        getReverb(0);
+        try {
+            short level = mReverb.getReverbLevel();
+            level = (short)((level == 0) ? -1000 : 0);
+            mReverb.setReverbLevel(level);
+            short level2 = mReverb.getReverbLevel();
+            assertTrue("got incorrect reverb level",
+                    (level2 > (level - MILLIBEL_TOLERANCE)) &&
+                    (level2 < (level + MILLIBEL_TOLERANCE)));
+
+// FIXME:uncomment actual test when early reflections are implemented in the reverb
+//            int time = mReverb.getReverbDelay();
+//             mReverb.setReverbDelay(time);
+//            int time2 = mReverb.getReverbDelay();
+//            assertTrue("got incorrect reverb delay",
+//                    ((float)time2 > (float)(time / DELAY_TOLERANCE)) &&
+//                    ((float)time2 < (float)(time * DELAY_TOLERANCE)));
+            mReverb.setReverbDelay(0);
+            int time2 = mReverb.getReverbDelay();
+            assertEquals("got incorrect reverb delay", mReverb.getReverbDelay(), 0);
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("get parameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("get parameter() called in wrong state");
+        } finally {
+            releaseReverb();
+        }
+    }
+
+    //Test case 1.3: test early reflections level and delay
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setReflectionsLevel",
+            args = {short.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getReflectionsLevel",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setReflectionsDelay",
+            args = {int.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getReflectionsDelay",
+            args = {}
+        )
+    })
+    public void test1_3Reflections() throws Exception {
+        getReverb(0);
+        try {
+// FIXME:uncomment actual test when early reflections are implemented in the reverb
+//            short level = mReverb.getReflectionsLevel();
+//            level = (short)((level == 0) ? -1000 : 0);
+//            mReverb.setReflectionsLevel(level);
+//            short level2 = mReverb.getReflectionsLevel();
+//            assertTrue("got incorrect reflections level",
+//                    (level2 > (level - MILLIBEL_TOLERANCE)) &&
+//                    (level2 < (level + MILLIBEL_TOLERANCE)));
+//
+//            int time = mReverb.getReflectionsDelay();
+//            time = (time == 20) ? 0 : 20;
+//            mReverb.setReflectionsDelay(time);
+//            int time2 = mReverb.getReflectionsDelay();
+//            assertTrue("got incorrect reflections delay",
+//                    ((float)time2 > (float)(time / DELAY_TOLERANCE)) &&
+//                    ((float)time2 < (float)(time * DELAY_TOLERANCE)));
+            mReverb.setReflectionsLevel((short) 0);
+            assertEquals("got incorrect reverb delay",
+                    mReverb.getReflectionsLevel(), (short) 0);
+            mReverb.setReflectionsDelay(0);
+            assertEquals("got incorrect reverb delay",
+                    mReverb.getReflectionsDelay(), 0);
+
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("get parameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("get parameter() called in wrong state");
+        } finally {
+            releaseReverb();
+        }
+    }
+
+    //Test case 1.4: test diffusion and density
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setDiffusion",
+            args = {short.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getDiffusion",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setDensity",
+            args = {short.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getDensity",
+            args = {}
+        )
+    })
+    public void test1_4DiffusionAndDensity() throws Exception {
+        getReverb(0);
+        try {
+            short ratio = mReverb.getDiffusion();
+            ratio = (short)((ratio == 500) ? 1000 : 500);
+            mReverb.setDiffusion(ratio);
+            short ratio2 = mReverb.getDiffusion();
+            assertTrue("got incorrect diffusion",
+                    ((float)ratio2 > (float)(ratio / RATIO_TOLERANCE)) &&
+                    ((float)ratio2 < (float)(ratio * RATIO_TOLERANCE)));
+
+            ratio = mReverb.getDensity();
+            ratio = (short)((ratio == 500) ? 1000 : 500);
+            mReverb.setDensity(ratio);
+            ratio2 = mReverb.getDensity();
+            assertTrue("got incorrect density",
+                    ((float)ratio2 > (float)(ratio / RATIO_TOLERANCE)) &&
+                    ((float)ratio2 < (float)(ratio * RATIO_TOLERANCE)));
+
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("get parameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("get parameter() called in wrong state");
+        } finally {
+            releaseReverb();
+        }
+    }
+
+    //Test case 1.5: test properties
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getProperties",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setProperties",
+            args = {EnvironmentalReverb.Settings.class}
+        )
+    })
+    public void test1_5Properties() throws Exception {
+        getReverb(0);
+        try {
+            EnvironmentalReverb.Settings settings = mReverb.getProperties();
+            String str = settings.toString();
+            settings = new EnvironmentalReverb.Settings(str);
+            short level = (short)((settings.roomLevel == 0) ? -1000 : 0);
+            settings.roomLevel = level;
+            mReverb.setProperties(settings);
+            settings = mReverb.getProperties();
+            assertTrue("setProperties failed",
+                    (settings.roomLevel >= (level - MILLIBEL_TOLERANCE)) &&
+                    (settings.roomLevel <= (level + MILLIBEL_TOLERANCE)));
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("get parameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("get parameter() called in wrong state");
+        } finally {
+            releaseReverb();
+        }
+    }
+
+    //-----------------------------------------------------------------
+    // 2 - Effect enable/disable
+    //----------------------------------
+
+    //Test case 2.0: test setEnabled() and getEnabled() in valid state
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnabled",
+            args = {boolean.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getEnabled",
+            args = {}
+        )
+    })
+    public void test2_0SetEnabledGetEnabled() throws Exception {
+        getReverb(0);
+        try {
+            mReverb.setEnabled(true);
+            assertTrue("invalid state from getEnabled", mReverb.getEnabled());
+            mReverb.setEnabled(false);
+            assertFalse("invalid state to getEnabled", mReverb.getEnabled());
+        } catch (IllegalStateException e) {
+            fail("setEnabled() in wrong state");
+        } finally {
+            releaseReverb();
+        }
+    }
+
+    //Test case 2.1: test setEnabled() throws exception after release
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "release",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnabled",
+            args = {boolean.class}
+        )
+    })
+    public void test2_1SetEnabledAfterRelease() throws Exception {
+        getReverb(0);
+        mReverb.release();
+        try {
+            mReverb.setEnabled(true);
+            fail("setEnabled() processed after release()");
+        } catch (IllegalStateException e) {
+            // test passed
+        } finally {
+            releaseReverb();
+        }
+    }
+
+    //-----------------------------------------------------------------
+    // 3 priority and listeners
+    //----------------------------------
+
+    //Test case 3.0: test control status listener
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setControlStatusListener",
+            args = {AudioEffect.OnControlStatusChangeListener.class}
+        )
+    })
+    public void test3_0ControlStatusListener() throws Exception {
+        mHasControl = true;
+        createListenerLooper(true, false, false);
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Looper creation: wait was interrupted.");
+            }
+        }
+        assertTrue(mInitialized);
+        synchronized(mLock) {
+            try {
+                getReverb(0);
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Create second effect: wait was interrupted.");
+            } finally {
+                releaseReverb();
+                terminateListenerLooper();
+            }
+        }
+        assertFalse("effect control not lost by effect1", mHasControl);
+    }
+
+    //Test case 3.1: test enable status listener
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnableStatusListener",
+            args = {AudioEffect.OnEnableStatusChangeListener.class}
+        )
+    })
+    public void test3_1EnableStatusListener() throws Exception {
+        createListenerLooper(false, true, false);
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Looper creation: wait was interrupted.");
+            }
+        }
+        assertTrue(mInitialized);
+        mReverb2.setEnabled(true);
+        mIsEnabled = true;
+        getReverb(0);
+        synchronized(mLock) {
+            try {
+                mReverb.setEnabled(false);
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Create second effect: wait was interrupted.");
+            } finally {
+                releaseReverb();
+                terminateListenerLooper();
+            }
+        }
+        assertFalse("enable status not updated", mIsEnabled);
+    }
+
+    //Test case 3.2: test parameter changed listener
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setParameterListener",
+            args = {EnvironmentalReverb.OnParameterChangeListener.class}
+        )
+    })
+    public void test3_2ParameterChangedListener() throws Exception {
+        createListenerLooper(false, false, true);
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Looper creation: wait was interrupted.");
+            }
+        }
+        assertTrue(mInitialized);
+        getReverb(0);
+        synchronized(mLock) {
+            try {
+                mChangedParameter = -1;
+                mReverb.setRoomLevel((short)0);
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Create second effect: wait was interrupted.");
+            } finally {
+                releaseReverb();
+                terminateListenerLooper();
+            }
+        }
+        assertEquals("parameter change not received",
+                EnvironmentalReverb.PARAM_ROOM_LEVEL, mChangedParameter);
+    }
+
+    //-----------------------------------------------------------------
+    // private methods
+    //----------------------------------
+
+    private void getReverb(int session) {
+         if (mReverb == null || session != mSession) {
+             if (session != mSession && mReverb != null) {
+                 mReverb.release();
+                 mReverb = null;
+             }
+             try {
+                mReverb = new EnvironmentalReverb(0, session);
+                mSession = session;
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "getReverb() EnvironmentalReverb not found exception: "+e);
+            } catch (UnsupportedOperationException e) {
+                Log.e(TAG, "getReverb() Effect library not loaded exception: "+e);
+            }
+         }
+         assertNotNull("could not create mReverb", mReverb);
+    }
+
+    private void releaseReverb() {
+        if (mReverb != null) {
+            mReverb.release();
+            mReverb = null;
+        }
+    }
+
+    // Initializes the reverb listener looper
+    class ListenerThread extends Thread {
+        boolean mControl;
+        boolean mEnable;
+        boolean mParameter;
+
+        public ListenerThread(boolean control, boolean enable, boolean parameter) {
+            super();
+            mControl = control;
+            mEnable = enable;
+            mParameter = parameter;
+        }
+    }
+
+    private void createListenerLooper(boolean control, boolean enable, boolean parameter) {
+        mInitialized = false;
+        new ListenerThread(control, enable, parameter) {
+            @Override
+            public void run() {
+                // Set up a looper
+                Looper.prepare();
+
+                // Save the looper so that we can terminate this thread
+                // after we are done with it.
+                mLooper = Looper.myLooper();
+
+                mReverb2 = new EnvironmentalReverb(0, 0);
+                assertNotNull("could not create reverb2", mReverb2);
+
+                if (mControl) {
+                    mReverb2.setControlStatusListener(
+                            new AudioEffect.OnControlStatusChangeListener() {
+                        public void onControlStatusChange(
+                                AudioEffect effect, boolean controlGranted) {
+                            synchronized(mLock) {
+                                if (effect == mReverb2) {
+                                    mHasControl = controlGranted;
+                                    mLock.notify();
+                                }
+                            }
+                        }
+                    });
+                }
+                if (mEnable) {
+                    mReverb2.setEnableStatusListener(
+                            new AudioEffect.OnEnableStatusChangeListener() {
+                        public void onEnableStatusChange(AudioEffect effect, boolean enabled) {
+                            synchronized(mLock) {
+                                if (effect == mReverb2) {
+                                    mIsEnabled = enabled;
+                                    mLock.notify();
+                                }
+                            }
+                        }
+                    });
+                }
+                if (mParameter) {
+                    mReverb2.setParameterListener(new EnvironmentalReverb.OnParameterChangeListener() {
+                        public void onParameterChange(EnvironmentalReverb effect,
+                                int status, int param, int value)
+                        {
+                            synchronized(mLock) {
+                                if (effect == mReverb2) {
+                                    mChangedParameter = param;
+                                    mLock.notify();
+                                }
+                            }
+                        }
+                    });
+                }
+
+                synchronized(mLock) {
+                    mInitialized = true;
+                    mLock.notify();
+                }
+                Looper.loop();  // Blocks forever until Looper.quit() is called.
+            }
+        }.start();
+    }
+
+    // Terminates the listener looper thread.
+    private void terminateListenerLooper() {
+        if (mReverb2 != null) {
+            mReverb2.release();
+            mReverb2 = null;
+        }
+        if (mLooper != null) {
+            mLooper.quit();
+            mLooper = null;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/tests/tests/media/src/android/media/cts/EqualizerTest.java b/tests/tests/media/src/android/media/cts/EqualizerTest.java
index cb21d47..967a281 100644
--- a/tests/tests/media/src/android/media/cts/EqualizerTest.java
+++ b/tests/tests/media/src/android/media/cts/EqualizerTest.java
@@ -49,13 +49,6 @@
     private Looper mLooper = null;
     private final Object mLock = new Object();
 
-    private void log(String testName, String message) {
-        Log.v(TAG, "[" + testName + "] " + message);
-    }
-
-    private void loge(String testName, String message) {
-        Log.e(TAG, "[" + testName + "] " + message);
-    }
 
     //-----------------------------------------------------------------
     // EQUALIZER TESTS:
@@ -73,39 +66,35 @@
             args = {int.class, int.class}
         ),
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "getId",
-                args = {}
+            level = TestLevel.COMPLETE,
+            method = "getId",
+            args = {}
         ),
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "release",
-                args = {}
+            level = TestLevel.COMPLETE,
+            method = "release",
+            args = {}
         )
     })
     public void test0_0ConstructorAndRelease() throws Exception {
-        boolean result = false;
-        String msg = "test1_0ConstructorAndRelease()";
         Equalizer eq = null;
-         try {
+        try {
             eq = new Equalizer(0, 0);
-            assertNotNull(msg + ": could not create Equalizer", eq);
+            assertNotNull("could not create Equalizer", eq);
             try {
-                assertTrue(msg +": invalid effect ID", (eq.getId() != 0));
+                assertTrue("invalid effect ID", (eq.getId() != 0));
             } catch (IllegalStateException e) {
-                msg = msg.concat(": Equalizer not initialized");
+                fail("Equalizer not initialized");
             }
-            result = true;
         } catch (IllegalArgumentException e) {
-            msg = msg.concat(": Equalizer not found");
+            fail("Equalizer not found");
         } catch (UnsupportedOperationException e) {
-            msg = msg.concat(": Effect library not loaded");
+            fail("Effect library not loaded");
         } finally {
             if (eq != null) {
                 eq.release();
             }
         }
-        assertTrue(msg, result);
     }
 
 
@@ -116,181 +105,161 @@
     //Test case 1.0: test setBandLevel() and getBandLevel()
     @TestTargets({
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "getNumberOfBands",
-                args = {}
+            level = TestLevel.COMPLETE,
+            method = "getNumberOfBands",
+            args = {}
         ),
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "getBandLevelRange",
-                args = {}
+            level = TestLevel.COMPLETE,
+            method = "getBandLevelRange",
+            args = {}
         ),
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "setBandLevel",
-                args = {short.class, short.class}
+            level = TestLevel.COMPLETE,
+            method = "setBandLevel",
+            args = {short.class, short.class}
         ),
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "getBandLevel",
-                args = {short.class}
+            level = TestLevel.COMPLETE,
+            method = "getBandLevel",
+            args = {short.class}
         )
     })
     public void test1_0BandLevel() throws Exception {
-        boolean result = false;
-        String msg = "test1_0BandLevel()";
         getEqualizer(0);
         try {
             short numBands = mEqualizer.getNumberOfBands();
-            assertTrue(msg + ": not enough bands", numBands >= MIN_NUMBER_OF_BANDS);
+            assertTrue("not enough bands", numBands >= MIN_NUMBER_OF_BANDS);
 
             short[] levelRange = mEqualizer.getBandLevelRange();
-            assertTrue(msg + ": min level too high", levelRange[0] <= MAX_LEVEL_RANGE_LOW);
-            assertTrue(msg + ": max level too low", levelRange[1] >= MIN_LEVEL_RANGE_HIGH);
+            assertTrue("min level too high", levelRange[0] <= MAX_LEVEL_RANGE_LOW);
+            assertTrue("max level too low", levelRange[1] >= MIN_LEVEL_RANGE_HIGH);
 
             mEqualizer.setBandLevel((short)0, levelRange[1]);
             short level = mEqualizer.getBandLevel((short)0);
             // allow +/- TOLERANCE margin on actual level compared to requested level
-            assertTrue(msg + ": setBandLevel failed",
+            assertTrue("setBandLevel failed",
                     (level >= (levelRange[1] - TOLERANCE)) &&
                     (level <= (levelRange[1] + TOLERANCE)));
-            result = true;
+
         } catch (IllegalArgumentException e) {
-            msg = msg.concat(": Bad parameter value");
-            loge(msg, "Bad parameter value");
+            fail("Bad parameter value");
         } catch (UnsupportedOperationException e) {
-            msg = msg.concat(": get parameter() rejected");
-            loge(msg, "get parameter() rejected");
+            fail("get parameter() rejected");
         } catch (IllegalStateException e) {
-            msg = msg.concat("get parameter() called in wrong state");
-            loge(msg, "get parameter() called in wrong state");
+            fail("get parameter() called in wrong state");
         } finally {
             releaseEqualizer();
         }
-        assertTrue(msg, result);
     }
 
     //Test case 1.1: test band frequency
     @TestTargets({
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "getBand",
-                args = {int.class}
+            level = TestLevel.COMPLETE,
+            method = "getBand",
+            args = {int.class}
         ),
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "getBandFreqRange",
-                args = {short.class}
+            level = TestLevel.COMPLETE,
+            method = "getBandFreqRange",
+            args = {short.class}
         ),
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "getCenterFreq",
-                args = {short.class}
+            level = TestLevel.COMPLETE,
+            method = "getCenterFreq",
+            args = {short.class}
         )
     })
     public void test1_1BandFrequency() throws Exception {
-        boolean result = false;
-        String msg = "test1_1BandFrequency()";
         getEqualizer(0);
         try {
             short band = mEqualizer.getBand(TEST_FREQUENCY_MILLIHERTZ);
-            assertTrue(msg + ": getBand failed", band >= 0);
+            assertTrue("getBand failed", band >= 0);
             int[] freqRange = mEqualizer.getBandFreqRange(band);
-            assertTrue(msg + ": getBandFreqRange failed",
+            assertTrue("getBandFreqRange failed",
                     (freqRange[0] <= TEST_FREQUENCY_MILLIHERTZ) &&
                     (freqRange[1] >= TEST_FREQUENCY_MILLIHERTZ));
             int freq = mEqualizer.getCenterFreq(band);
-            assertTrue(msg + ": getCenterFreq failed",
+            assertTrue("getCenterFreq failed",
                     (freqRange[0] <= freq) && (freqRange[1] >= freq));
-            result = true;
+
         } catch (IllegalArgumentException e) {
-            msg = msg.concat(": Bad parameter value");
-            loge(msg, "Bad parameter value");
+            fail("Bad parameter value");
         } catch (UnsupportedOperationException e) {
-            msg = msg.concat(": get parameter() rejected");
-            loge(msg, "get parameter() rejected");
+            fail("get parameter() rejected");
         } catch (IllegalStateException e) {
-            msg = msg.concat("get parameter() called in wrong state");
-            loge(msg, "get parameter() called in wrong state");
+            fail("get parameter() called in wrong state");
         } finally {
             releaseEqualizer();
         }
-        assertTrue(msg, result);
     }
 
     //Test case 1.2: test presets
     @TestTargets({
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "getNumberOfPresets",
-                args = {}
+            level = TestLevel.COMPLETE,
+            method = "getNumberOfPresets",
+            args = {}
         ),
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "usePreset",
-                args = {short.class}
+            level = TestLevel.COMPLETE,
+            method = "usePreset",
+            args = {short.class}
         ),
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "getCurrentPreset",
-                args = {}
+            level = TestLevel.COMPLETE,
+            method = "getCurrentPreset",
+            args = {}
         ),
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "getPresetName",
-                args = {short.class}
+            level = TestLevel.COMPLETE,
+            method = "getPresetName",
+            args = {short.class}
         )
     })
     public void test1_2Presets() throws Exception {
-        boolean result = false;
-        String msg = "test1_2Presets()";
         getEqualizer(0);
         try {
             short numPresets = mEqualizer.getNumberOfPresets();
-            assertTrue(msg + ": getNumberOfPresets failed", numPresets >= MIN_NUMBER_OF_PRESETS);
+            assertTrue("getNumberOfPresets failed", numPresets >= MIN_NUMBER_OF_PRESETS);
             if (numPresets > 0) {
                 mEqualizer.usePreset((short)(numPresets - 1));
                 short preset = mEqualizer.getCurrentPreset();
-                assertEquals(msg + ": usePreset failed", preset, (short)(numPresets - 1));
+                assertEquals("usePreset failed", preset, (short)(numPresets - 1));
                 String name = mEqualizer.getPresetName(preset);
-                assertNotNull(msg + ": getPresetName failed", name);
+                assertNotNull("getPresetName failed", name);
             }
-            result = true;
+
         } catch (IllegalArgumentException e) {
-            msg = msg.concat(": Bad parameter value");
-            loge(msg, "Bad parameter value");
+            fail("Bad parameter value");
         } catch (UnsupportedOperationException e) {
-            msg = msg.concat(": get parameter() rejected");
-            loge(msg, "get parameter() rejected");
+            fail("get parameter() rejected");
         } catch (IllegalStateException e) {
-            msg = msg.concat("get parameter() called in wrong state");
-            loge(msg, "get parameter() called in wrong state");
+            fail("get parameter() called in wrong state");
         } finally {
             releaseEqualizer();
         }
-        assertTrue(msg, result);
     }
 
     //Test case 1.3: test properties
     @TestTargets({
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "getProperties",
-                args = {}
+            level = TestLevel.COMPLETE,
+            method = "getProperties",
+            args = {}
         ),
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "setProperties",
-                args = {Equalizer.Settings.class}
+            level = TestLevel.COMPLETE,
+            method = "setProperties",
+            args = {Equalizer.Settings.class}
         )
     })
     public void test1_3Properties() throws Exception {
-        boolean result = false;
-        String msg = "test1_3Properties()";
         getEqualizer(0);
         try {
             Equalizer.Settings settings = mEqualizer.getProperties();
-            assertTrue(msg + ": no enough bands", settings.numBands >= MIN_NUMBER_OF_BANDS);
+            assertTrue("no enough bands", settings.numBands >= MIN_NUMBER_OF_BANDS);
             short newLevel = 0;
             if (settings.bandLevels[0] == 0) {
                 newLevel = -600;
@@ -301,54 +270,45 @@
             settings.bandLevels[0] = newLevel;
             mEqualizer.setProperties(settings);
             settings = mEqualizer.getProperties();
-            Log.e(TAG, "settings.bandLevels[0]: "+settings.bandLevels[0]+" newLevel: "+newLevel);
-            assertTrue(msg + ": setProperties failed",
+            assertTrue("setProperties failed",
                     (settings.bandLevels[0] >= (newLevel - TOLERANCE)) &&
                     (settings.bandLevels[0] <= (newLevel + TOLERANCE)));
 
-            result = true;
         } catch (IllegalArgumentException e) {
-            msg = msg.concat(": Bad parameter value");
-            loge(msg, "Bad parameter value");
+            fail("Bad parameter value");
         } catch (UnsupportedOperationException e) {
-            msg = msg.concat(": get parameter() rejected");
-            loge(msg, "get parameter() rejected");
+            fail("get parameter() rejected");
         } catch (IllegalStateException e) {
-            msg = msg.concat("get parameter() called in wrong state");
-            loge(msg, "get parameter() called in wrong state");
+            fail("get parameter() called in wrong state");
         } finally {
             releaseEqualizer();
         }
-        assertTrue(msg, result);
     }
 
     //Test case 1.4: test setBandLevel() throws exception after release
     @TestTargets({
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "release",
-                args = {}
+            level = TestLevel.COMPLETE,
+            method = "release",
+            args = {}
         ),
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "setBandLevel",
-                args = {short.class, short.class}
+            level = TestLevel.COMPLETE,
+            method = "setBandLevel",
+            args = {short.class, short.class}
         )
     })
     public void test1_4SetBandLevelAfterRelease() throws Exception {
-        boolean result = false;
-        String msg = "test1_4SetBandLevelAfterRelease()";
 
         getEqualizer(0);
         mEqualizer.release();
         try {
             mEqualizer.setBandLevel((short)0, (short)0);
         } catch (IllegalStateException e) {
-            result = true;
+            // test passed
         } finally {
             releaseEqualizer();
         }
-        assertTrue(msg+ ": no exception for setBandLevel() after release()", result);
     }
 
     //-----------------------------------------------------------------
@@ -358,62 +318,55 @@
     //Test case 2.0: test setEnabled() and getEnabled() in valid state
     @TestTargets({
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "setEnabled",
-                args = {boolean.class}
+            level = TestLevel.COMPLETE,
+            method = "setEnabled",
+            args = {boolean.class}
         ),
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "getEnabled",
-                args = {}
+            level = TestLevel.COMPLETE,
+            method = "getEnabled",
+            args = {}
         )
     })
     public void test2_0SetEnabledGetEnabled() throws Exception {
-        boolean result = false;
-        String msg = "test2_0SetEnabledGetEnabled()";
-
         getEqualizer(0);
         try {
             mEqualizer.setEnabled(true);
-            assertTrue(msg + ": invalid state from getEnabled", mEqualizer.getEnabled());
+            assertTrue("invalid state from getEnabled", mEqualizer.getEnabled());
             mEqualizer.setEnabled(false);
-            assertFalse(msg + ": invalid state to getEnabled", mEqualizer.getEnabled());
-            result = true;
+            assertFalse("invalid state to getEnabled", mEqualizer.getEnabled());
+
         } catch (IllegalStateException e) {
-            msg = msg.concat(": setEnabled() in wrong state");
+            fail("setEnabled() in wrong state");
         } finally {
             releaseEqualizer();
         }
-        assertTrue(msg, result);
     }
 
     //Test case 2.1: test setEnabled() throws exception after release
     @TestTargets({
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "release",
-                args = {}
+            level = TestLevel.COMPLETE,
+            method = "release",
+            args = {}
         ),
         @TestTargetNew(
-                level = TestLevel.COMPLETE,
-                method = "setEnabled",
-                args = {boolean.class}
+            level = TestLevel.COMPLETE,
+            method = "setEnabled",
+            args = {boolean.class}
         )
     })
     public void test2_1SetEnabledAfterRelease() throws Exception {
-        boolean result = false;
-        String msg = "test2_1SetEnabledAfterRelease()";
 
         getEqualizer(0);
         mEqualizer.release();
         try {
             mEqualizer.setEnabled(true);
         } catch (IllegalStateException e) {
-            result = true;
+            // test passed
         } finally {
             releaseEqualizer();
         }
-        assertTrue(msg+ ": no exception for setEnabled() after release()", result);
     }
 
     //-----------------------------------------------------------------
@@ -429,8 +382,6 @@
         )
     })
     public void test3_0ControlStatusListener() throws Exception {
-        boolean result = false;
-        String msg = "test3_0ControlStatusListener()";
         mHasControl = true;
         createListenerLooper(true, false, false);
         synchronized(mLock) {
@@ -452,9 +403,7 @@
                 terminateListenerLooper();
             }
         }
-        assertFalse(msg + ": effect control not lost by effect1", mHasControl);
-        result = true;
-        assertTrue(msg, result);
+        assertFalse("effect control not lost by effect1", mHasControl);
     }
 
     //Test case 3.1: test enable status listener
@@ -466,8 +415,6 @@
         )
     })
     public void test3_1EnableStatusListener() throws Exception {
-        boolean result = false;
-        String msg = "test3_1EnableStatusListener()";
         createListenerLooper(false, true, false);
         synchronized(mLock) {
             try {
@@ -491,9 +438,7 @@
                 terminateListenerLooper();
             }
         }
-        assertFalse(msg + ": enable status not updated", mIsEnabled);
-        result = true;
-        assertTrue(msg, result);
+        assertFalse("enable status not updated", mIsEnabled);
     }
 
     //Test case 3.2: test parameter changed listener
@@ -505,8 +450,6 @@
         )
     })
     public void test3_2ParameterChangedListener() throws Exception {
-        boolean result = false;
-        String msg = "test3_2ParameterChangedListener()";
         createListenerLooper(false, false, true);
         synchronized(mLock) {
             try {
@@ -529,10 +472,8 @@
                 terminateListenerLooper();
             }
         }
-        assertEquals(msg + ": parameter change not received",
+        assertEquals("parameter change not received",
                 Equalizer.PARAM_BAND_LEVEL, mChangedParameter);
-        result = true;
-        assertTrue(msg, result);
     }
 
     //-----------------------------------------------------------------
@@ -579,7 +520,7 @@
     }
 
     private void createListenerLooper(boolean control, boolean enable, boolean parameter) {
-
+        mInitialized = false;
         new ListenerThread(control, enable, parameter) {
             @Override
             public void run() {
diff --git a/tests/tests/media/src/android/media/cts/PresetReverbTest.java b/tests/tests/media/src/android/media/cts/PresetReverbTest.java
new file mode 100644
index 0000000..e29192b
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/PresetReverbTest.java
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2010 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.cts;
+
+import android.media.AudioEffect;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.PresetReverb;
+import android.os.Looper;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+
+@TestTargetClass(PresetReverb.class)
+public class PresetReverbTest extends AndroidTestCase {
+
+    private String TAG = "PresetReverbTest";
+    private final static short FIRST_PRESET = PresetReverb.PRESET_NONE;
+    private final static short LAST_PRESET = PresetReverb.PRESET_PLATE;
+    private PresetReverb mReverb = null;
+    private PresetReverb mReverb2 = null;
+    private int mSession = -1;
+    private boolean mHasControl = false;
+    private boolean mIsEnabled = false;
+    private int mChangedParameter = -1;
+    private boolean mInitialized = false;
+    private Looper mLooper = null;
+    private final Object mLock = new Object();
+
+
+    //-----------------------------------------------------------------
+    // PRESET REVERB TESTS:
+    //----------------------------------
+
+    //-----------------------------------------------------------------
+    // 0 - constructor
+    //----------------------------------
+
+    //Test case 0.0: test constructor and release
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "PresetReverb",
+            args = {int.class, int.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getId",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "release",
+            args = {}
+        )
+    })
+    public void test0_0ConstructorAndRelease() throws Exception {
+        PresetReverb reverb = null;
+        try {
+            reverb = new PresetReverb(0, 0);
+            assertNotNull("could not create PresetReverb", reverb);
+            try {
+                assertTrue("invalid effect ID", (reverb.getId() != 0));
+            } catch (IllegalStateException e) {
+                fail("PresetReverb not initialized");
+            }
+        } catch (IllegalArgumentException e) {
+            fail("PresetReverb not found");
+        } catch (UnsupportedOperationException e) {
+            fail("Effect library not loaded");
+        } finally {
+            if (reverb != null) {
+                reverb.release();
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------
+    // 1 - get/set parameters
+    //----------------------------------
+
+    //Test case 1.0: test presets
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setPreset",
+            args = {short.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getPreset",
+            args = {}
+        )
+    })
+    public void test1_0Presets() throws Exception {
+        getReverb(0);
+        try {
+            for (short preset = FIRST_PRESET;
+                 preset <= LAST_PRESET;
+                 preset++) {
+                mReverb.setPreset(preset);
+                assertEquals("got incorrect preset", preset, mReverb.getPreset());
+            }
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("get parameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("get parameter() called in wrong state");
+        } finally {
+            releaseReverb();
+        }
+    }
+
+    //Test case 1.1: test properties
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getProperties",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setProperties",
+            args = {PresetReverb.Settings.class}
+        )
+    })
+    public void test1_1Properties() throws Exception {
+        getReverb(0);
+        try {
+            PresetReverb.Settings settings = mReverb.getProperties();
+            String str = settings.toString();
+            settings = new PresetReverb.Settings(str);
+            short preset = (settings.preset == PresetReverb.PRESET_SMALLROOM) ?
+                            PresetReverb.PRESET_MEDIUMROOM : PresetReverb.PRESET_SMALLROOM;
+            settings.preset = preset;
+            mReverb.setProperties(settings);
+            settings = mReverb.getProperties();
+            assertEquals("setProperties failed", settings.preset, preset);
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("get parameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("get parameter() called in wrong state");
+        } finally {
+            releaseReverb();
+        }
+    }
+
+    //-----------------------------------------------------------------
+    // 2 - Effect enable/disable
+    //----------------------------------
+
+    //Test case 2.0: test setEnabled() and getEnabled() in valid state
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnabled",
+            args = {boolean.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getEnabled",
+            args = {}
+        )
+    })
+    public void test2_0SetEnabledGetEnabled() throws Exception {
+        getReverb(0);
+        try {
+            mReverb.setEnabled(true);
+            assertTrue("invalid state from getEnabled", mReverb.getEnabled());
+            mReverb.setEnabled(false);
+            assertFalse("invalid state to getEnabled", mReverb.getEnabled());
+        } catch (IllegalStateException e) {
+            fail("setEnabled() in wrong state");
+        } finally {
+            releaseReverb();
+        }
+    }
+
+    //Test case 2.1: test setEnabled() throws exception after release
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "release",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnabled",
+            args = {boolean.class}
+        )
+    })
+    public void test2_1SetEnabledAfterRelease() throws Exception {
+        getReverb(0);
+        mReverb.release();
+        try {
+            mReverb.setEnabled(true);
+        } catch (IllegalStateException e) {
+            // test passed
+        } finally {
+            releaseReverb();
+        }
+    }
+
+    //-----------------------------------------------------------------
+    // 3 priority and listeners
+    //----------------------------------
+
+    //Test case 3.0: test control status listener
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setControlStatusListener",
+            args = {AudioEffect.OnControlStatusChangeListener.class}
+        )
+    })
+    public void test3_0ControlStatusListener() throws Exception {
+        mHasControl = true;
+        createListenerLooper(true, false, false);
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Looper creation: wait was interrupted.");
+            }
+        }
+        assertTrue(mInitialized);
+        synchronized(mLock) {
+            try {
+                getReverb(0);
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Create second effect: wait was interrupted.");
+            } finally {
+                releaseReverb();
+                terminateListenerLooper();
+            }
+        }
+        assertFalse("effect control not lost by effect1", mHasControl);
+    }
+
+    //Test case 3.1: test enable status listener
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnableStatusListener",
+            args = {AudioEffect.OnEnableStatusChangeListener.class}
+        )
+    })
+    public void test3_1EnableStatusListener() throws Exception {
+        createListenerLooper(false, true, false);
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Looper creation: wait was interrupted.");
+            }
+        }
+        assertTrue(mInitialized);
+        mReverb2.setEnabled(true);
+        mIsEnabled = true;
+        getReverb(0);
+        synchronized(mLock) {
+            try {
+                mReverb.setEnabled(false);
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Create second effect: wait was interrupted.");
+            } finally {
+                releaseReverb();
+                terminateListenerLooper();
+            }
+        }
+        assertFalse("enable status not updated", mIsEnabled);
+    }
+
+    //Test case 3.2: test parameter changed listener
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setParameterListener",
+            args = {PresetReverb.OnParameterChangeListener.class}
+        )
+    })
+    public void test3_2ParameterChangedListener() throws Exception {
+        createListenerLooper(false, false, true);
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Looper creation: wait was interrupted.");
+            }
+        }
+        assertTrue(mInitialized);
+        getReverb(0);
+        synchronized(mLock) {
+            try {
+                mChangedParameter = -1;
+                mReverb.setPreset(PresetReverb.PRESET_SMALLROOM);
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Create second effect: wait was interrupted.");
+            } finally {
+                releaseReverb();
+                terminateListenerLooper();
+            }
+        }
+        assertEquals("parameter change not received",
+                PresetReverb.PARAM_PRESET, mChangedParameter);
+    }
+
+    //-----------------------------------------------------------------
+    // private methods
+    //----------------------------------
+
+    private void getReverb(int session) {
+         if (mReverb == null || session != mSession) {
+             if (session != mSession && mReverb != null) {
+                 mReverb.release();
+                 mReverb = null;
+             }
+             try {
+                mReverb = new PresetReverb(0, session);
+                mSession = session;
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "getReverb() PresetReverb not found exception: "+e);
+            } catch (UnsupportedOperationException e) {
+                Log.e(TAG, "getReverb() Effect library not loaded exception: "+e);
+            }
+         }
+         assertNotNull("could not create mReverb", mReverb);
+    }
+
+    private void releaseReverb() {
+        if (mReverb != null) {
+            mReverb.release();
+            mReverb = null;
+        }
+    }
+
+    // Initializes the reverb listener looper
+    class ListenerThread extends Thread {
+        boolean mControl;
+        boolean mEnable;
+        boolean mParameter;
+
+        public ListenerThread(boolean control, boolean enable, boolean parameter) {
+            super();
+            mControl = control;
+            mEnable = enable;
+            mParameter = parameter;
+        }
+    }
+
+    private void createListenerLooper(boolean control, boolean enable, boolean parameter) {
+        mInitialized = false;
+        new ListenerThread(control, enable, parameter) {
+            @Override
+            public void run() {
+                // Set up a looper
+                Looper.prepare();
+
+                // Save the looper so that we can terminate this thread
+                // after we are done with it.
+                mLooper = Looper.myLooper();
+
+                mReverb2 = new PresetReverb(0, 0);
+                assertNotNull("could not create Reverb2", mReverb2);
+
+                if (mControl) {
+                    mReverb2.setControlStatusListener(
+                            new AudioEffect.OnControlStatusChangeListener() {
+                        public void onControlStatusChange(
+                                AudioEffect effect, boolean controlGranted) {
+                            synchronized(mLock) {
+                                if (effect == mReverb2) {
+                                    mHasControl = controlGranted;
+                                    mLock.notify();
+                                }
+                            }
+                        }
+                    });
+                }
+                if (mEnable) {
+                    mReverb2.setEnableStatusListener(
+                            new AudioEffect.OnEnableStatusChangeListener() {
+                        public void onEnableStatusChange(AudioEffect effect, boolean enabled) {
+                            synchronized(mLock) {
+                                if (effect == mReverb2) {
+                                    mIsEnabled = enabled;
+                                    mLock.notify();
+                                }
+                            }
+                        }
+                    });
+                }
+                if (mParameter) {
+                    mReverb2.setParameterListener(new PresetReverb.OnParameterChangeListener() {
+                        public void onParameterChange(PresetReverb effect,
+                                int status, int param, short value)
+                        {
+                            synchronized(mLock) {
+                                if (effect == mReverb2) {
+                                    mChangedParameter = param;
+                                    mLock.notify();
+                                }
+                            }
+                        }
+                    });
+                }
+
+                synchronized(mLock) {
+                    mInitialized = true;
+                    mLock.notify();
+                }
+                Looper.loop();  // Blocks forever until Looper.quit() is called.
+            }
+        }.start();
+    }
+
+    // Terminates the listener looper thread.
+    private void terminateListenerLooper() {
+        if (mReverb2 != null) {
+            mReverb2.release();
+            mReverb2 = null;
+        }
+        if (mLooper != null) {
+            mLooper.quit();
+            mLooper = null;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/tests/tests/media/src/android/media/cts/VirtualizerTest.java b/tests/tests/media/src/android/media/cts/VirtualizerTest.java
new file mode 100644
index 0000000..07f8894
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/VirtualizerTest.java
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2010 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.cts;
+
+import android.media.AudioEffect;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.Virtualizer;
+import android.os.Looper;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+
+@TestTargetClass(Virtualizer.class)
+public class VirtualizerTest extends AndroidTestCase {
+
+    private String TAG = "VirtualizerTest";
+    private final static short TEST_STRENGTH = 500;
+    private final static short TEST_STRENGTH2 = 1000;
+    private final static float STRENGTH_TOLERANCE = 1.1f;  // 10%
+
+    private Virtualizer mVirtualizer = null;
+    private Virtualizer mVirtualizer2 = null;
+    private int mSession = -1;
+    private boolean mHasControl = false;
+    private boolean mIsEnabled = false;
+    private int mChangedParameter = -1;
+    private boolean mInitialized = false;
+    private Looper mLooper = null;
+    private final Object mLock = new Object();
+
+    //-----------------------------------------------------------------
+    // VIRTUALIZER TESTS:
+    //----------------------------------
+
+    //-----------------------------------------------------------------
+    // 0 - constructor
+    //----------------------------------
+
+    //Test case 0.0: test constructor and release
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "Virtualizer",
+            args = {int.class, int.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getId",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "release",
+            args = {}
+        )
+    })
+    public void test0_0ConstructorAndRelease() throws Exception {
+        Virtualizer eq = null;
+        try {
+            eq = new Virtualizer(0, 0);
+            assertNotNull(" could not create Virtualizer", eq);
+            try {
+                assertTrue(" invalid effect ID", (eq.getId() != 0));
+            } catch (IllegalStateException e) {
+                fail("Virtualizer not initialized");
+            }
+        } catch (IllegalArgumentException e) {
+            fail("Virtualizer not found");
+        } catch (UnsupportedOperationException e) {
+            fail("Effect library not loaded");
+        } finally {
+            if (eq != null) {
+                eq.release();
+            }
+        }
+    }
+
+
+    //-----------------------------------------------------------------
+    // 1 - get/set parameters
+    //----------------------------------
+
+    //Test case 1.0: test strength
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getStrengthSupported",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setStrength",
+            args = {short.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getRoundedStrength",
+            args = {}
+        )
+    })
+    public void test1_0Strength() throws Exception {
+        getVirtualizer(0);
+        try {
+            if (mVirtualizer.getStrengthSupported()) {
+                short strength = mVirtualizer.getRoundedStrength();
+                strength = (strength == TEST_STRENGTH) ? TEST_STRENGTH2 : TEST_STRENGTH;
+                mVirtualizer.setStrength((short)strength);
+                short strength2 = mVirtualizer.getRoundedStrength();
+                // allow STRENGTH_TOLERANCE difference between set strength and rounded strength
+                assertTrue("got incorrect strength",
+                        ((float)strength2 > (float)strength / STRENGTH_TOLERANCE) &&
+                        ((float)strength2 < (float)strength * STRENGTH_TOLERANCE));
+            } else {
+                short strength = mVirtualizer.getRoundedStrength();
+                assertTrue("got incorrect strength", strength >= 0 && strength <= 1000);
+            }
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("get parameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("get parameter() called in wrong state");
+        } finally {
+            releaseVirtualizer();
+        }
+    }
+
+    //Test case 1.1: test properties
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getProperties",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setProperties",
+            args = {Virtualizer.Settings.class}
+        )
+    })
+    public void test1_1Properties() throws Exception {
+        getVirtualizer(0);
+        try {
+            Virtualizer.Settings settings = mVirtualizer.getProperties();
+            String str = settings.toString();
+            settings = new Virtualizer.Settings(str);
+
+            short strength = settings.strength;
+            if (mVirtualizer.getStrengthSupported()) {
+                strength = (strength == TEST_STRENGTH) ? TEST_STRENGTH2 : TEST_STRENGTH;
+            }
+            settings.strength = strength;
+            mVirtualizer.setProperties(settings);
+            settings = mVirtualizer.getProperties();
+
+            if (mVirtualizer.getStrengthSupported()) {
+                // allow STRENGTH_TOLERANCE difference between set strength and rounded strength
+                assertTrue("got incorrect strength",
+                        ((float)settings.strength > (float)strength / STRENGTH_TOLERANCE) &&
+                        ((float)settings.strength < (float)strength * STRENGTH_TOLERANCE));
+            }
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("get parameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("get parameter() called in wrong state");
+        } finally {
+            releaseVirtualizer();
+        }
+    }
+
+    //Test case 1.2: test setStrength() throws exception after release
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "release",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setStrength",
+            args = {short.class}
+        )
+    })
+    public void test1_2SetStrengthAfterRelease() throws Exception {
+        getVirtualizer(0);
+        mVirtualizer.release();
+        try {
+            mVirtualizer.setStrength(TEST_STRENGTH);
+        } catch (IllegalStateException e) {
+            // test passed
+        } finally {
+            releaseVirtualizer();
+        }
+    }
+
+    //-----------------------------------------------------------------
+    // 2 - Effect enable/disable
+    //----------------------------------
+
+    //Test case 2.0: test setEnabled() and getEnabled() in valid state
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnabled",
+            args = {boolean.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getEnabled",
+            args = {}
+        )
+    })
+    public void test2_0SetEnabledGetEnabled() throws Exception {
+        getVirtualizer(0);
+        try {
+            mVirtualizer.setEnabled(true);
+            assertTrue(" invalid state from getEnabled", mVirtualizer.getEnabled());
+            mVirtualizer.setEnabled(false);
+            assertFalse(" invalid state to getEnabled", mVirtualizer.getEnabled());
+        } catch (IllegalStateException e) {
+            fail("setEnabled() in wrong state");
+        } finally {
+            releaseVirtualizer();
+        }
+    }
+
+    //Test case 2.1: test setEnabled() throws exception after release
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "release",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnabled",
+            args = {boolean.class}
+        )
+    })
+    public void test2_1SetEnabledAfterRelease() throws Exception {
+        getVirtualizer(0);
+        mVirtualizer.release();
+        try {
+            mVirtualizer.setEnabled(true);
+        } catch (IllegalStateException e) {
+            // test passed
+        } finally {
+            releaseVirtualizer();
+        }
+    }
+
+    //-----------------------------------------------------------------
+    // 3 priority and listeners
+    //----------------------------------
+
+    //Test case 3.0: test control status listener
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setControlStatusListener",
+            args = {AudioEffect.OnControlStatusChangeListener.class}
+        )
+    })
+    public void test3_0ControlStatusListener() throws Exception {
+        mHasControl = true;
+        createListenerLooper(true, false, false);
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Looper creation: wait was interrupted.");
+            }
+        }
+        assertTrue(mInitialized);
+        synchronized(mLock) {
+            try {
+                getVirtualizer(0);
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Create second effect: wait was interrupted.");
+            } finally {
+                releaseVirtualizer();
+                terminateListenerLooper();
+            }
+        }
+        assertFalse("effect control not lost by effect1", mHasControl);
+    }
+
+    //Test case 3.1: test enable status listener
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnableStatusListener",
+            args = {AudioEffect.OnEnableStatusChangeListener.class}
+        )
+    })
+    public void test3_1EnableStatusListener() throws Exception {
+        createListenerLooper(false, true, false);
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Looper creation: wait was interrupted.");
+            }
+        }
+        assertTrue(mInitialized);
+        mVirtualizer2.setEnabled(true);
+        mIsEnabled = true;
+        getVirtualizer(0);
+        synchronized(mLock) {
+            try {
+                mVirtualizer.setEnabled(false);
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Create second effect: wait was interrupted.");
+            } finally {
+                releaseVirtualizer();
+                terminateListenerLooper();
+            }
+        }
+        assertFalse("enable status not updated", mIsEnabled);
+    }
+
+    //Test case 3.2: test parameter changed listener
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setParameterListener",
+            args = {Virtualizer.OnParameterChangeListener.class}
+        )
+    })
+    public void test3_2ParameterChangedListener() throws Exception {
+        createListenerLooper(false, false, true);
+        synchronized(mLock) {
+            try {
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Looper creation: wait was interrupted.");
+            }
+        }
+        assertTrue(mInitialized);
+        getVirtualizer(0);
+        synchronized(mLock) {
+            try {
+                mChangedParameter = -1;
+                mVirtualizer.setStrength(TEST_STRENGTH);
+                mLock.wait(1000);
+            } catch(Exception e) {
+                Log.e(TAG, "Create second effect: wait was interrupted.");
+            } finally {
+                releaseVirtualizer();
+                terminateListenerLooper();
+            }
+        }
+        assertEquals("parameter change not received",
+                Virtualizer.PARAM_STRENGTH, mChangedParameter);
+    }
+
+    //-----------------------------------------------------------------
+    // private methods
+    //----------------------------------
+
+    private void getVirtualizer(int session) {
+         if (mVirtualizer == null || session != mSession) {
+             if (session != mSession && mVirtualizer != null) {
+                 mVirtualizer.release();
+                 mVirtualizer = null;
+             }
+             try {
+                mVirtualizer = new Virtualizer(0, session);
+                mSession = session;
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "getVirtualizer() Virtualizer not found exception: "+e);
+            } catch (UnsupportedOperationException e) {
+                Log.e(TAG, "getVirtualizer() Effect library not loaded exception: "+e);
+            }
+         }
+         assertNotNull("could not create mVirtualizer", mVirtualizer);
+    }
+
+    private void releaseVirtualizer() {
+        if (mVirtualizer != null) {
+            mVirtualizer.release();
+            mVirtualizer = null;
+        }
+    }
+
+    // Initializes the virtualizer listener looper
+    class ListenerThread extends Thread {
+        boolean mControl;
+        boolean mEnable;
+        boolean mParameter;
+
+        public ListenerThread(boolean control, boolean enable, boolean parameter) {
+            super();
+            mControl = control;
+            mEnable = enable;
+            mParameter = parameter;
+        }
+    }
+
+    private void createListenerLooper(boolean control, boolean enable, boolean parameter) {
+        mInitialized = false;
+        new ListenerThread(control, enable, parameter) {
+            @Override
+            public void run() {
+                // Set up a looper
+                Looper.prepare();
+
+                // Save the looper so that we can terminate this thread
+                // after we are done with it.
+                mLooper = Looper.myLooper();
+
+                mVirtualizer2 = new Virtualizer(0, 0);
+                assertNotNull("could not create virtualizer2", mVirtualizer2);
+
+                if (mControl) {
+                    mVirtualizer2.setControlStatusListener(
+                            new AudioEffect.OnControlStatusChangeListener() {
+                        public void onControlStatusChange(
+                                AudioEffect effect, boolean controlGranted) {
+                            synchronized(mLock) {
+                                if (effect == mVirtualizer2) {
+                                    mHasControl = controlGranted;
+                                    mLock.notify();
+                                }
+                            }
+                        }
+                    });
+                }
+                if (mEnable) {
+                    mVirtualizer2.setEnableStatusListener(
+                            new AudioEffect.OnEnableStatusChangeListener() {
+                        public void onEnableStatusChange(AudioEffect effect, boolean enabled) {
+                            synchronized(mLock) {
+                                if (effect == mVirtualizer2) {
+                                    mIsEnabled = enabled;
+                                    mLock.notify();
+                                }
+                            }
+                        }
+                    });
+                }
+                if (mParameter) {
+                    mVirtualizer2.setParameterListener(new Virtualizer.OnParameterChangeListener() {
+                        public void onParameterChange(Virtualizer effect, int status,
+                                int param, short value)
+                        {
+                            synchronized(mLock) {
+                                if (effect == mVirtualizer2) {
+                                    mChangedParameter = param;
+                                    mLock.notify();
+                                }
+                            }
+                        }
+                    });
+                }
+
+                synchronized(mLock) {
+                    mInitialized = true;
+                    mLock.notify();
+                }
+                Looper.loop();  // Blocks forever until Looper.quit() is called.
+            }
+        }.start();
+    }
+
+    // Terminates the listener looper thread.
+    private void terminateListenerLooper() {
+        if (mVirtualizer2 != null) {
+            mVirtualizer2.release();
+            mVirtualizer2 = null;
+        }
+        if (mLooper != null) {
+            mLooper.quit();
+            mLooper = null;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/tests/tests/media/src/android/media/cts/VisualizerTest.java b/tests/tests/media/src/android/media/cts/VisualizerTest.java
new file mode 100644
index 0000000..d23be3f
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/VisualizerTest.java
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2010 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.cts;
+
+import android.media.AudioEffect;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.Visualizer;
+import android.os.Looper;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+
+@TestTargetClass(Visualizer.class)
+public class VisualizerTest extends AndroidTestCase {
+
+    private String TAG = "VisualizerTest";
+    private final static int MIN_CAPTURE_RATE_MAX = 10000; // 10Hz
+    private final static int MIN_CAPTURE_SIZE_MAX = 1024;
+    private final static int MAX_CAPTURE_SIZE_MIN = 512;
+
+    private Visualizer mVisualizer = null;
+    private int mSession = -1;
+    private boolean mInitialized = false;
+    private Looper mLooper = null;
+    private final Object mLock = new Object();
+    private byte[] mWaveform = null;
+    private byte[] mFft = null;
+    private boolean mCaptureWaveform = false;
+    private boolean mCaptureFft = false;
+
+    //-----------------------------------------------------------------
+    // VISUALIZER TESTS:
+    //----------------------------------
+
+    //-----------------------------------------------------------------
+    // 0 - constructor
+    //----------------------------------
+
+    //Test case 0.0: test constructor and release
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "Visualizer",
+            args = {int.class, int.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "release",
+            args = {}
+        )
+    })
+    public void test0_0ConstructorAndRelease() throws Exception {
+        Visualizer visualizer = null;
+         try {
+            visualizer = new Visualizer(0);
+            assertNotNull("could not create Visualizer", visualizer);
+        } catch (IllegalArgumentException e) {
+            fail("Visualizer not found");
+        } catch (UnsupportedOperationException e) {
+            fail("Effect library not loaded");
+        } finally {
+            if (visualizer != null) {
+                visualizer.release();
+            }
+        }
+    }
+
+
+    //-----------------------------------------------------------------
+    // 1 - get/set parameters
+    //----------------------------------
+
+    //Test case 1.0: capture rates
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getMaxCaptureRate",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getSamplingRate",
+            args = {}
+        )
+    })
+    public void test1_0CaptureRates() throws Exception {
+        getVisualizer(0);
+        try {
+            int captureRate = mVisualizer.getMaxCaptureRate();
+            assertTrue("insufficient max capture rate",
+                    captureRate >= MIN_CAPTURE_RATE_MAX);
+            int samplingRate = mVisualizer.getSamplingRate();
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("get parameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("get parameter() called in wrong state");
+        } finally {
+            releaseVisualizer();
+        }
+    }
+
+    //Test case 1.1: test capture size
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getCaptureSizeRange",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setCaptureSize",
+            args = {int.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getCaptureSize",
+            args = {}
+        )
+    })
+    public void test1_1CaptureSize() throws Exception {
+        getVisualizer(0);
+        try {
+            int[] range = mVisualizer.getCaptureSizeRange();
+            assertTrue("insufficient min capture size",
+                    range[0] <= MAX_CAPTURE_SIZE_MIN);
+            assertTrue("insufficient min capture size",
+                    range[1] >= MIN_CAPTURE_SIZE_MAX);
+            mVisualizer.setCaptureSize(range[0]);
+            assertEquals("insufficient min capture size",
+                    range[0], mVisualizer.getCaptureSize());
+            mVisualizer.setCaptureSize(range[1]);
+            assertEquals("insufficient min capture size",
+                    range[1], mVisualizer.getCaptureSize());
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("get parameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("get parameter() called in wrong state");
+        } finally {
+            releaseVisualizer();
+        }
+    }
+
+    //-----------------------------------------------------------------
+    // 2 - check capture
+    //----------------------------------
+
+    //Test case 2.0: test cature in polling mode
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnabled",
+            args = {boolean.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getEnabled",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getWaveForm",
+            args = {byte[].class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getFft",
+            args = {byte[].class}
+        )
+    })
+    public void test2_0PollingCapture() throws Exception {
+        try {
+            getVisualizer(0);
+            mVisualizer.setEnabled(true);
+            assertTrue("visualizer not enabled", mVisualizer.getEnabled());
+            Thread.sleep(100);
+            // check capture on silence
+            byte[] data = new byte[mVisualizer.getCaptureSize()];
+            mVisualizer.getWaveForm(data);
+            int energy = computeEnergy(data, true);
+            assertEquals("getWaveForm reports energy for silence",
+                    0, energy);
+            mVisualizer.getFft(data);
+            energy = computeEnergy(data, false);
+            assertEquals("getFft reports energy for silence",
+                    0, energy);
+
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("get parameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("get parameter() called in wrong state");
+        } catch (InterruptedException e) {
+            fail("sleep() interrupted");
+        }
+        finally {
+            releaseVisualizer();
+        }
+    }
+
+    //Test case 2.1: test capture with listener
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setEnabled",
+            args = {boolean.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "getEnabled",
+            args = {}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "setDataCaptureListener",
+            args = {Visualizer.OnDataCaptureListener.class,
+                    int.class, boolean.class, boolean.class}
+        )
+    })
+    public void test2_1ListenerCapture() throws Exception {
+        try {
+            getVisualizer(0);
+            createListenerLooper();
+            synchronized(mLock) {
+                try {
+                    mLock.wait(1000);
+                } catch(Exception e) {
+                    Log.e(TAG, "Looper creation: wait was interrupted.");
+                }
+            }
+            assertTrue(mInitialized);
+
+            mVisualizer.setEnabled(true);
+            assertTrue("visualizer not enabled", mVisualizer.getEnabled());
+
+            Thread.sleep(100);
+            // check capture on silence
+            synchronized(mLock) {
+                try {
+                    mCaptureWaveform = true;
+                    mLock.wait(1000);
+                    mCaptureWaveform = false;
+                } catch(Exception e) {
+                    Log.e(TAG, "Capture waveform: wait was interrupted.");
+                }
+            }
+            assertNotNull("waveform capture failed", mWaveform);
+            int energy = computeEnergy(mWaveform, true);
+            assertEquals("getWaveForm reports energy for silence",
+                    0, energy);
+
+            synchronized(mLock) {
+                try {
+                    mCaptureFft = true;
+                    mLock.wait(1000);
+                    mCaptureFft = false;
+                } catch(Exception e) {
+                    Log.e(TAG, "Capture FFT: wait was interrupted.");
+                }
+            }
+            assertNotNull("FFT capture failed", mFft);
+            energy = computeEnergy(mFft, false);
+            assertEquals("getFft reports energy for silence",
+                    0, energy);
+
+        } catch (IllegalArgumentException e) {
+            fail("Bad parameter value");
+        } catch (UnsupportedOperationException e) {
+            fail("get parameter() rejected");
+        } catch (IllegalStateException e) {
+            fail("get parameter() called in wrong state");
+        } catch (InterruptedException e) {
+            fail("sleep() interrupted");
+        } finally {
+            terminateListenerLooper();
+            releaseVisualizer();
+        }
+    }
+
+    //-----------------------------------------------------------------
+    // private methods
+    //----------------------------------
+
+    private int computeEnergy(byte[] data, boolean pcm) {
+        int energy = 0;
+        if (data.length != 0) {
+            if (pcm) {
+                for (int i = 0; i < data.length; i++) {
+                    int tmp = ((int)data[i] & 0xFF) - 128;
+                    energy += tmp*tmp;
+                }
+            } else {
+                energy = (int)data[0] * (int)data[0];
+                for (int i = 2; i < data.length; i += 2) {
+                    int real = (int)data[i];
+                    int img = (int)data[i + 1];
+                    energy += real * real + img * img;
+                }
+            }
+        }
+        return energy;
+    }
+
+    private void getVisualizer(int session) {
+         if (mVisualizer == null || session != mSession) {
+             if (session != mSession && mVisualizer != null) {
+                 mVisualizer.release();
+                 mVisualizer = null;
+             }
+             try {
+                mVisualizer = new Visualizer(session);
+                mSession = session;
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "getVisualizer() Visualizer not found exception: "+e);
+            } catch (UnsupportedOperationException e) {
+                Log.e(TAG, "getVisualizer() Effect library not loaded exception: "+e);
+            }
+         }
+         assertNotNull("could not create mVisualizer", mVisualizer);
+    }
+
+    private void releaseVisualizer() {
+        if (mVisualizer != null) {
+            mVisualizer.release();
+            mVisualizer = null;
+        }
+   }
+
+    private void createListenerLooper() {
+
+        new Thread() {
+            @Override
+            public void run() {
+                // Set up a looper to be used by mEffect.
+                Looper.prepare();
+
+                // Save the looper so that we can terminate this thread
+                // after we are done with it.
+                mLooper = Looper.myLooper();
+
+                if (mVisualizer != null) {
+                    mVisualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener() {
+                        public void onWaveFormDataCapture(
+                                Visualizer visualizer, byte[] waveform, int samplingRate) {
+                            synchronized(mLock) {
+                                if (visualizer == mVisualizer) {
+                                    if (mCaptureWaveform) {
+                                        mWaveform = waveform;
+                                        mLock.notify();
+                                    }
+                                }
+                            }
+                        }
+
+                        public void onFftDataCapture(
+                                Visualizer visualizer, byte[] fft, int samplingRate) {
+                            synchronized(mLock) {
+                                if (visualizer == mVisualizer) {
+                                    if (mCaptureFft) {
+                                        mFft = fft;
+                                        mLock.notify();
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    10000,
+                    true,
+                    true);
+                }
+
+                synchronized(mLock) {
+                    mInitialized = true;
+                    mLock.notify();
+                }
+                Looper.loop();  // Blocks forever until Looper.quit() is called.
+            }
+        }.start();
+    }
+    /*
+     * Terminates the listener looper thread.
+     */
+    private void terminateListenerLooper() {
+        if (mLooper != null) {
+            mLooper.quit();
+            mLooper = null;
+        }
+    }
+}