auto import from //branches/cupcake_rel/...@140373
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 077d016..f509fb5 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -160,7 +160,7 @@
         16, // STREAM_MUSIC
         8,  // STREAM_ALARM
         8,  // STREAM_NOTIFICATION
-        15, // STREAM_BLUETOOTH_SCO
+        16, // STREAM_BLUETOOTH_SCO
     };
 
     /**  @hide Default volume index values for audio streams */
@@ -220,7 +220,7 @@
      * By default this is on for the ring stream. If this flag is included,
      * this behavior will be present regardless of the stream type being
      * affected by the ringer mode.
-     * 
+     *
      * @see #adjustVolume(int, int)
      * @see #adjustStreamVolume(int, int, int)
      */
@@ -954,25 +954,21 @@
     /**
      * IME standard keypress sound
      * @see #playSoundEffect(int)
-     * @hide FIXME: Unhide before release
      */
     public static final int FX_KEYPRESS_STANDARD = 5;
     /**
      * IME spacebar keypress sound
      * @see #playSoundEffect(int)
-     * @hide FIXME: Unhide before release
      */
     public static final int FX_KEYPRESS_SPACEBAR = 6;
     /**
      * IME delete keypress sound
      * @see #playSoundEffect(int)
-     * @hide FIXME: Unhide before release
      */
     public static final int FX_KEYPRESS_DELETE = 7;
     /**
      * IME return_keypress sound
      * @see #playSoundEffect(int)
-     * @hide FIXME: Unhide before release
      */
     public static final int FX_KEYPRESS_RETURN = 8;
     /**
@@ -988,11 +984,10 @@
      *            {@link #FX_FOCUS_NAVIGATION_DOWN},
      *            {@link #FX_FOCUS_NAVIGATION_LEFT},
      *            {@link #FX_FOCUS_NAVIGATION_RIGHT},
-     *            FIXME: include links before release
-     *            {link #FX_KEYPRESS_STANDARD},
-     *            {link #FX_KEYPRESS_SPACEBAR},
-     *            {link #FX_KEYPRESS_DELETE},
-     *            {link #FX_KEYPRESS_RETURN},
+     *            {@link #FX_KEYPRESS_STANDARD},
+     *            {@link #FX_KEYPRESS_SPACEBAR},
+     *            {@link #FX_KEYPRESS_DELETE},
+     *            {@link #FX_KEYPRESS_RETURN},
      * NOTE: This version uses the UI settings to determine
      * whether sounds are heard or not.
      */
@@ -1021,15 +1016,13 @@
      *            {@link #FX_FOCUS_NAVIGATION_DOWN},
      *            {@link #FX_FOCUS_NAVIGATION_LEFT},
      *            {@link #FX_FOCUS_NAVIGATION_RIGHT},
-     *            FIXME: include links before release
-     *            {link #FX_KEYPRESS_STANDARD},
-     *            {link #FX_KEYPRESS_SPACEBAR},
-     *            {link #FX_KEYPRESS_DELETE},
-     *            {link #FX_KEYPRESS_RETURN},
+     *            {@link #FX_KEYPRESS_STANDARD},
+     *            {@link #FX_KEYPRESS_SPACEBAR},
+     *            {@link #FX_KEYPRESS_DELETE},
+     *            {@link #FX_KEYPRESS_RETURN},
      * @param volume Sound effect volume
      * NOTE: This version is for applications that have their own
      * settings panel for enabling and controlling volume.
-     *  @hide FIXME: Unhide before release
      */
     public void  playSoundEffect(int effectType, float volume) {
         if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 316fa7a..d2bad93 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -171,6 +171,10 @@
      */
     private NativeEventHandlerDelegate mEventHandlerDelegate = null;
     /**
+     * Looper associated with the thread that creates the AudioTrack instance
+     */
+    private Looper mInitializationLooper = null;
+    /**
      * The audio data sampling rate in Hz.
      */
     private int mSampleRate = 22050;
@@ -248,6 +252,11 @@
             int bufferSizeInBytes, int mode)
     throws IllegalArgumentException {
         mState = STATE_UNINITIALIZED;
+        
+        // remember which looper is associated with the AudioTrack instanciation
+        if ((mInitializationLooper = Looper.myLooper()) == null) {
+            mInitializationLooper = Looper.getMainLooper();
+        }
 
         audioParamCheck(streamType, sampleRateInHz, channelConfig, audioFormat, mode);
 
@@ -902,11 +911,10 @@
             if (handler != null) {
                 looper = handler.getLooper();
             } else {
-                // no given handler, look for main looper
-                if ((looper = Looper.myLooper()) == null) {
-                    looper = Looper.getMainLooper();
-                }
+                // no given handler, use the looper the AudioTrack was created in
+                looper = mInitializationLooper;
             }
+            
             // construct the event handler with this looper
             if (looper != null) {
                 // implement the event handler delegate
diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java
index 9de0eec..6539d84 100644
--- a/media/java/android/media/JetPlayer.java
+++ b/media/java/android/media/JetPlayer.java
@@ -68,21 +68,22 @@
     //--------------------------------------------
     // Member variables
     //------------------------
-    private EventHandler            mNativeEventHandler = null;
+    /**
+     * Handler for jet events and status updates coming from the native code
+     */
+    private NativeEventHandler mEventHandler = null;
     
     /**
-     * Lock to protect status listener updates against status change notifications
+     * Looper associated with the thread that creates the AudioTrack instance
      */
-    private final Object mStatusListenerLock = new Object();
+    private Looper mInitializationLooper = null;
     
     /**
      * Lock to protect the event listener updates against event notifications
      */
     private final Object mEventListenerLock = new Object();
     
-    private JetStatusUpdateListener mJetStatusUpdateListener = null;
-    
-    private JetEventListener mJetEventListener = null;
+    private OnJetEventListener mJetEventListener = null;
     
     private static JetPlayer singletonRef;
     
@@ -115,6 +116,11 @@
     
 
     private JetPlayer() {
+
+        // remember which looper is associated with the JetPlayer instanciation
+        if ((mInitializationLooper = Looper.myLooper()) == null) {
+            mInitializationLooper = Looper.getMainLooper();
+        }
                 
         native_setup(new WeakReference<JetPlayer>(this),
                 JetPlayer.getMaxTracks(), 
@@ -132,18 +138,6 @@
     }
     
     
-    private void createNativeEventHandler() {
-        Looper looper;
-        if ((looper = Looper.myLooper()) != null) {
-            mNativeEventHandler = new EventHandler(this, looper);
-        } else if ((looper = Looper.getMainLooper()) != null) {
-            mNativeEventHandler = new EventHandler(this, looper);
-        } else {
-            mNativeEventHandler = null;
-        }
-    }
-    
-    
     //--------------------------------------------
     // Getters
     //------------------------
@@ -235,24 +229,27 @@
     //---------------------------------------------------------
     // Internal class to handle events posted from native code
     //------------------------
-    private class EventHandler extends Handler
+    private class NativeEventHandler extends Handler
     {
         private JetPlayer mJet;
 
-        public EventHandler(JetPlayer jet, Looper looper) {
+        public NativeEventHandler(JetPlayer jet, Looper looper) {
             super(looper);
             mJet = jet;
         }
 
         @Override
         public void handleMessage(Message msg) {
+            OnJetEventListener listener = null;
+            synchronized (mEventListenerLock) {
+                listener = mJet.mJetEventListener;
+            }
             switch(msg.what) {
             case JET_EVENT:
-                synchronized (mEventListenerLock) {
-                    if (mJetEventListener != null) {
-                        // call the appropriate listener after decoding the event parameters
-                        // encoded in msg.arg1
-                        mJetEventListener.onJetEvent(
+                if (listener != null) {
+                    // call the appropriate listener after decoding the event parameters
+                    // encoded in msg.arg1
+                    mJetEventListener.onJetEvent(
                             mJet,
                             (short)((msg.arg1 & JET_EVENT_SEG_MASK)   >> JET_EVENT_SEG_SHIFT),
                             (byte) ((msg.arg1 & JET_EVENT_TRACK_MASK) >> JET_EVENT_TRACK_SHIFT),
@@ -261,28 +258,21 @@
                             (byte)(((msg.arg1 & JET_EVENT_CHAN_MASK)  >> JET_EVENT_CHAN_SHIFT) + 1),
                             (byte) ((msg.arg1 & JET_EVENT_CTRL_MASK)  >> JET_EVENT_CTRL_SHIFT),
                             (byte)  (msg.arg1 & JET_EVENT_VAL_MASK) );
-                    }
                 }
                 return;
             case JET_USERID_UPDATE:
-                synchronized (mStatusListenerLock) {
-                    if (mJetStatusUpdateListener != null) {
-                        mJetStatusUpdateListener.onJetUserIdUpdate(mJet, msg.arg1, msg.arg2);
-                    }
+                if (listener != null) {
+                    listener.onJetUserIdUpdate(mJet, msg.arg1, msg.arg2);
                 }
                 return;
             case JET_NUMQUEUEDSEGMENT_UPDATE:
-                synchronized (mStatusListenerLock) {
-                    if (mJetStatusUpdateListener != null) {
-                        mJetStatusUpdateListener.onJetNumQueuedSegmentUpdate(mJet, msg.arg1);
-                    }
+                if (listener != null) {
+                    listener.onJetNumQueuedSegmentUpdate(mJet, msg.arg1);
                 }
                 return;
             case JET_PAUSE_UPDATE:
-                synchronized (mStatusListenerLock) {
-                    if (mJetStatusUpdateListener != null)
-                        mJetStatusUpdateListener.onJetPauseUpdate(mJet, msg.arg1);
-                }
+                if (listener != null)
+                    listener.onJetPauseUpdate(mJet, msg.arg1);
                 return;
 
             default:
@@ -294,22 +284,48 @@
     
     
     //--------------------------------------------
-    // Jet status update listener
+    // Jet event listener
     //------------------------
-    public void setStatusUpdateListener(JetStatusUpdateListener listener) {
-        synchronized(mStatusListenerLock) {
-            mJetStatusUpdateListener = listener;
-        }
-        
-        if ((listener != null) && (mNativeEventHandler == null)) {
-            createNativeEventHandler();
+    public void setEventListener(OnJetEventListener listener) {
+        setEventListener(listener, null);
+    }
+    
+    public void setEventListener(OnJetEventListener listener, Handler handler) {
+        synchronized(mEventListenerLock) {
+            
+            mJetEventListener = listener;
+            
+            if (listener != null) {
+                if (handler != null) {
+                    mEventHandler = new NativeEventHandler(this, handler.getLooper());
+                } else {
+                    // no given handler, use the looper the AudioTrack was created in
+                    mEventHandler = new NativeEventHandler(this, mInitializationLooper);
+                }
+            } else {
+                mEventHandler = null;
+            }
+            
         }
     }
     
+    
     /**
-     * Handles the notification when the JET status is updated.
+     * Handles the notification when the JET engine generates an event.
      */
-    public interface JetStatusUpdateListener {
+    public interface OnJetEventListener {
+        /**
+         * Callback for when the JET engine generates a new event.
+         * 
+         * @param player the JET player the event is coming from
+         * @param segment 8 bit unsigned value
+         * @param track 6 bit unsigned value
+         * @param channel 4 bit unsigned value
+         * @param controller 7 bit unsigned value
+         * @param value 7 bit unsigned value
+         */
+        void onJetEvent(JetPlayer player,
+                short segment, byte track, byte channel, byte controller, byte value);
         /**
          * Callback for when JET's currently playing segment userID is updated.
          * 
@@ -338,38 +354,6 @@
     
     
     //--------------------------------------------
-    // Jet event listener
-    //------------------------
-    public void setEventListener(JetEventListener listener) {
-        synchronized(mEventListenerLock) {
-            mJetEventListener = listener;
-        }
-        
-        if ((listener != null) && (mNativeEventHandler == null)) {
-            createNativeEventHandler();
-        }
-    }
-    
-    /**
-     * Handles the notification when the JET engine generates an event.
-     */
-    public interface JetEventListener {
-        /**
-         * Callback for when the JET engine generates a new event.
-         * 
-         * @param player the JET player the event is coming from
-         * @param segment 8 bit unsigned value
-         * @param track 6 bit unsigned value
-         * @param channel 4 bit unsigned value
-         * @param controller 7 bit unsigned value
-         * @param value 7 bit unsigned value
-         */
-        void onJetEvent(JetPlayer player,
-                short segment, byte track, byte channel, byte controller, byte value);
-    }
-    
-    
-    //--------------------------------------------
     // Native methods
     //------------------------
     private native final boolean native_setup(Object Jet_this,
@@ -397,13 +381,15 @@
     @SuppressWarnings("unused")
     private static void postEventFromNative(Object jetplayer_ref,
             int what, int arg1, int arg2) {
-        
+        //logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2);
         JetPlayer jet = (JetPlayer)((WeakReference)jetplayer_ref).get();
 
-        if( (jet!=null) && (jet.mNativeEventHandler!=null) ){
-            Message m = jet.mNativeEventHandler.obtainMessage(what, arg1, arg2, null);
-            jet.mNativeEventHandler.sendMessage(m);
+        if ((jet != null) && (jet.mEventHandler != null)) {
+            Message m = 
+                jet.mEventHandler.obtainMessage(what, arg1, arg2, null);
+            jet.mEventHandler.sendMessage(m);
         }
+        
     }
     
  
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 202d0ae..9668efa 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1036,11 +1036,11 @@
      * Register a callback to be invoked when the media source is ready
      * for playback.
      *
-     * @param l the callback that will be run
+     * @param listener the callback that will be run
      */
-    public void setOnPreparedListener(OnPreparedListener l)
+    public void setOnPreparedListener(OnPreparedListener listener)
     {
-        mOnPreparedListener = l;
+        mOnPreparedListener = listener;
     }
 
     private OnPreparedListener mOnPreparedListener;
@@ -1063,11 +1063,11 @@
      * Register a callback to be invoked when the end of a media source
      * has been reached during playback.
      *
-     * @param l the callback that will be run
+     * @param listener the callback that will be run
      */
-    public void setOnCompletionListener(OnCompletionListener l)
+    public void setOnCompletionListener(OnCompletionListener listener)
     {
-        mOnCompletionListener = l;
+        mOnCompletionListener = listener;
     }
 
     private OnCompletionListener mOnCompletionListener;
@@ -1092,11 +1092,11 @@
      * Register a callback to be invoked when the status of a network
      * stream's buffer has changed.
      *
-     * @param l the callback that will be run
+     * @param listener the callback that will be run.
      */
-    public void setOnBufferingUpdateListener(OnBufferingUpdateListener l)
+    public void setOnBufferingUpdateListener(OnBufferingUpdateListener listener)
     {
-        mOnBufferingUpdateListener = l;
+        mOnBufferingUpdateListener = listener;
     }
 
     private OnBufferingUpdateListener mOnBufferingUpdateListener;
@@ -1119,11 +1119,11 @@
      * Register a callback to be invoked when a seek operation has been
      * completed.
      * 
-     * @param l the callback that will be run
+     * @param listener the callback that will be run
      */
-    public void setOnSeekCompleteListener(OnSeekCompleteListener l)
+    public void setOnSeekCompleteListener(OnSeekCompleteListener listener)
     {
-        mOnSeekCompleteListener = l;
+        mOnSeekCompleteListener = listener;
     }
     
     private OnSeekCompleteListener mOnSeekCompleteListener;
@@ -1151,12 +1151,12 @@
      * Register a callback to be invoked when the video size is
      * known or updated.
      * 
-     * @param l the callback that will be run
+     * @param listener the callback that will be run
      * @hide
      */
-    public void setOnVideoSizeChangedListener(OnVideoSizeChangedListener l)
+    public void setOnVideoSizeChangedListener(OnVideoSizeChangedListener listener)
     {
-        mOnVideoSizeChangedListener = l;
+        mOnVideoSizeChangedListener = listener;
     }
     
     private OnVideoSizeChangedListener mOnVideoSizeChangedListener;
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 1c08cba..676f241 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -259,6 +259,12 @@
     /**
      * Sets the maximum duration (in ms) of the recording session.
      * Call this after setOutFormat() but before prepare().
+     * After recording reaches the specified duration, a notification
+     * will be sent to the {@link android.media.MediaRecorder.OnInfoListener}
+     * with a "what" code of {@link #MEDIA_RECORDER_INFO_MAX_DURATION_REACHED}
+     * and recording will be stopped. Stopping happens asynchronously, there
+     * is no guarantee that the recorder will have stopped by the time the
+     * listener is notified.
      *
      * @param max_duration_ms the maximum duration in ms (if zero or negative, disables the duration limit)
      *
@@ -266,6 +272,21 @@
     public native void setMaxDuration(int max_duration_ms) throws IllegalArgumentException;
 
     /**
+     * Sets the maximum filesize (in bytes) of the recording session.
+     * Call this after setOutFormat() but before prepare().
+     * After recording reaches the specified filesize, a notification
+     * will be sent to the {@link android.media.MediaRecorder.OnInfoListener}
+     * with a "what" code of {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED}
+     * and recording will be stopped. Stopping happens asynchronously, there
+     * is no guarantee that the recorder will have stopped by the time the
+     * listener is notified.
+     *
+     * @param max_filesize_bytes the maximum filesize in bytes (if zero or negative, disables the limit)
+     *
+     */
+    public native void setMaxFileSize(long max_filesize_bytes) throws IllegalArgumentException;
+
+    /**
      * Sets the audio encoder to be used for recording. If this method is not
      * called, the output file will not contain an audio track. Call this after
      * setOutputFormat() but before prepare().
@@ -441,6 +462,10 @@
      * @see android.media.MediaRecorder.OnInfoListener
      */
     public static final int MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800;
+    /** A maximum filesize had been setup and has now been reached.
+     * @see android.media.MediaRecorder.OnInfoListener
+     */
+    public static final int MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED = 801;
 
     /**
      * Interface definition for a callback to be invoked when an error
@@ -455,6 +480,8 @@
          * @param what    the type of error that has occurred:
          * <ul>
          * <li>{@link #MEDIA_RECORDER_INFO_UNKNOWN}
+         * <li>{@link #MEDIA_RECORDER_INFO_MAX_DURATION_REACHED}
+         * <li>{@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED}
          * </ul>
          * @param extra   an extra code, specific to the error type
          */
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 1e508d2..209b09f 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -268,6 +268,19 @@
 }
 
 static void
+android_media_MediaRecorder_setMaxFileSize(
+        JNIEnv *env, jobject thiz, jlong max_filesize_bytes)
+{
+    LOGV("setMaxFileSize(%lld)", max_filesize_bytes);
+    sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
+
+    char params[64];
+    sprintf(params, "max-filesize=%lld", max_filesize_bytes);
+
+    process_media_recorder_call(env, mr->setParameters(String8(params)), "java/lang/RuntimeException", "setMaxFileSize failed.");
+}
+
+static void
 android_media_MediaRecorder_prepare(JNIEnv *env, jobject thiz)
 {
     LOGV("prepare");
@@ -370,6 +383,7 @@
     {"setVideoSize",         "(II)V",                           (void *)android_media_MediaRecorder_setVideoSize},
     {"setVideoFrameRate",    "(I)V",                            (void *)android_media_MediaRecorder_setVideoFrameRate},
     {"setMaxDuration",       "(I)V",                            (void *)android_media_MediaRecorder_setMaxDuration},
+    {"setMaxFileSize",       "(J)V",                            (void *)android_media_MediaRecorder_setMaxFileSize},
     {"_prepare",             "()V",                             (void *)android_media_MediaRecorder_prepare},
     {"getMaxAmplitude",      "()I",                             (void *)android_media_MediaRecorder_native_getMaxAmplitude},
     {"start",                "()V",                             (void *)android_media_MediaRecorder_start},
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index d26b0c5..7537ddf 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -387,12 +387,10 @@
     LOGV("flush");
 
     if (!mActive) {
-        mCblk->lock.lock();
         mAudioTrack->flush();
         // Release AudioTrack callback thread in case it was waiting for new buffers
         // in AudioTrack::obtainBuffer()
         mCblk->cv.signal();
-        mCblk->lock.unlock();
     }
 }
 
@@ -443,7 +441,7 @@
     if (rate > afSamplingRate*2) rate = afSamplingRate*2;
     if (rate > MAX_SAMPLE_RATE) rate = MAX_SAMPLE_RATE;
 
-    mCblk->sampleRate = rate;
+    mCblk->sampleRate = (uint16_t)rate;
 }
 
 uint32_t AudioTrack::getSampleRate()
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index 2c62104..77a9013 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -194,8 +194,15 @@
     }
 
    while (1) {
+    
         mMutex.lock(); // [[[[[[[[ LOCK ---------------------------------------
 
+        if (mEasData == NULL) {
+            mMutex.unlock();
+            LOGV("JetPlayer::render(): NULL EAS data, exiting render.");
+            goto threadExit;
+        }
+            
         // nothing to render, wait for client thread to wake us up
         while (!mRender)
         {
@@ -255,7 +262,10 @@
     }//while (1)
 
 threadExit:
-    mAudioTrack->flush();
+    if (mAudioTrack) {
+        mAudioTrack->stop();
+        mAudioTrack->flush();
+    }
     if (mAudioBuffer) {
         delete [] mAudioBuffer;
         mAudioBuffer = NULL;
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 23b3b9d..6b26faf 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -367,8 +367,9 @@
     status_t ret = mMediaRecorder->setParameters(params);
     if (OK != ret) {
         LOGE("setParameters(%s) failed: %d", params.string(), ret);
-        mCurrentState = MEDIA_RECORDER_ERROR;
-        return ret;
+        // Do not change our current state to MEDIA_RECORDER_ERROR, failures
+        // of the only currently supported parameters, "max-duration" and
+        // "max-filesize" are _not_ fatal.
     }
 
     return ret;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
index 3c449c9..6edc2cc 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
@@ -16,12 +16,13 @@
 
 package com.android.mediaframeworktest;
 
-import com.android.mediaframeworktest.functional.MediaPlayerApiTest;
-import com.android.mediaframeworktest.functional.SimTonesTest;
-import com.android.mediaframeworktest.functional.MediaMetadataTest;
 import com.android.mediaframeworktest.functional.CameraTest;
-import com.android.mediaframeworktest.functional.MediaRecorderTest;
 import com.android.mediaframeworktest.functional.MediaAudioTrackTest;
+import com.android.mediaframeworktest.functional.MediaMetadataTest;
+import com.android.mediaframeworktest.functional.MediaMimeTest;
+import com.android.mediaframeworktest.functional.MediaPlayerApiTest;
+import com.android.mediaframeworktest.functional.MediaRecorderTest;
+import com.android.mediaframeworktest.functional.SimTonesTest;
 
 import junit.framework.TestSuite;
 
@@ -50,6 +51,7 @@
         suite.addTestSuite(CameraTest.class);
         suite.addTestSuite(MediaRecorderTest.class);
         suite.addTestSuite(MediaAudioTrackTest.class);
+        suite.addTestSuite(MediaMimeTest.class);
         return suite;
     }
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java
new file mode 100644
index 0000000..d2809c1
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMimeTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mediaframeworktest.functional;
+
+import java.io.File;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+import com.android.mediaframeworktest.MediaFrameworkTest;
+
+/*
+ * System tests for the handling of mime type in the media framework.
+ *
+ * To run this test suite:
+     make frameworks/base/media/tests/MediaFrameworkTest
+     make mediaframeworktest
+
+     adb install -r out/target/product/dream/data/app/mediaframeworktest.apk
+
+     adb shell am instrument -e class \
+     com.android.mediaframeworktest.functional.MediaMimeTest \
+     -w com.android.mediaframeworktest/.MediaFrameworkTestRunner
+ *
+ */
+public class MediaMimeTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {    
+    private final String TAG = "MediaMimeTest";
+    private Context mContext;
+    private final String MP3_FILE = "/sdcard/media_api/music/SHORTMP3.mp3";
+    private final String MEDIA_PLAYBACK_NAME = "com.android.music.MediaPlaybackActivity";
+
+    public MediaMimeTest() {
+        super("com.android.mediaframeworktest", MediaFrameworkTest.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+      super.setUp();
+      mContext = getActivity();
+      // Checks you have all the test files on your SDCARD.
+      assertTrue(new File(MP3_FILE).exists());
+    }
+    
+    @Override 
+    protected void tearDown() throws Exception {     
+        super.tearDown();              
+    }
+
+    // ----------------------------------------------------------------------
+    // AUDIO mime type resolution tests.
+
+    @MediumTest
+    // Checks the MediaPlaybackActivity handles audio/mp3.
+    public void testCheckMediaPlaybackHandlesAudioMp3() throws Exception {
+        assertMediaPlaybackActivityHandles("audio/mp3");
+    }
+
+    @MediumTest
+    // Checks the MediaPlaybackActivity handles audio/*.
+    public void testCheckMediaPlaybackHandlesAudio() throws Exception {
+        assertMediaPlaybackActivityHandles("audio/*");
+    }
+
+    @MediumTest
+    // Checks the MediaPlaybackActivity handles application/itunes. Some servers
+    // set the Content-type header to application/iTunes (with capital T, but
+    // the download manager downcasts it) for their MP3 podcasts. This is non
+    // standard but we try to support it anyway.
+    // See bug 1401491
+    public void testCheckMediaPlaybackHandlesApplicationItunes() throws Exception {
+        assertMediaPlaybackActivityHandles("application/itunes");
+    }
+
+    @MediumTest
+    // Checks the activity resolver handling of mime types is case sensitive.
+    // See bug 1710534
+    public void testCheckActivityResolverMimeHandlingIsCaseSensitive() throws Exception {
+        assertNoActivityHandles("AUDIO/MP3");   // <--- look uppercase
+    }
+
+    @MediumTest
+    // Checks the activity resolver does not trims leading whitespaces when
+    // resolving mime types. Trailing whitespaces seems to be non
+    // significant.
+    // See bug 1710534
+    public void testCheckWhiteSpacesInMimeTypeHandling() throws Exception {
+        assertNoActivityHandles(" audio/mp3");
+        assertNoActivityHandles(" audio/mp3 ");
+        assertMediaPlaybackActivityHandles("audio/mp3 ");
+    }
+
+    // @return a ResolveInfo instance for the mime type or null if the type is
+    // not handled by any activity.
+    private ResolveInfo resolveMime(String mime) {
+        Intent viewIntent = new Intent(Intent.ACTION_VIEW);
+        Uri uri = Uri.fromParts("file", MP3_FILE, null);
+
+        viewIntent.setDataAndType(uri, mime);
+        return mContext.getPackageManager().resolveActivity(
+                viewIntent, PackageManager.MATCH_DEFAULT_ONLY);
+    }
+
+    // Helper method to check the media playback activity handles the given mime type.
+    // @param mime type to test for
+    private void assertMediaPlaybackActivityHandles(String mime) throws Exception {
+        ResolveInfo ri = resolveMime(mime);
+
+        assertNotNull(ri);
+        assertEquals(MEDIA_PLAYBACK_NAME, ri.activityInfo.name.toString());
+    }
+
+    // Helper method to check that NO activity handles the given mime type.
+    // @param mime type to test for
+    private void assertNoActivityHandles(String mime) throws Exception {
+        assertNull(resolveMime(mime));
+    }
+}