Merge change 23861 into eclair

* changes:
  Replace the bugreport symlink with a tool that starts the new dumpstate service.
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index ef67611..51a0649 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -24,6 +24,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=         \
+        SineSource.cpp    \
         record.cpp
 
 LOCAL_SHARED_LIBRARIES := \
diff --git a/cmds/stagefright/JPEGSource.cpp b/cmds/stagefright/JPEGSource.cpp
index a7994ed..4e9ca4e 100644
--- a/cmds/stagefright/JPEGSource.cpp
+++ b/cmds/stagefright/JPEGSource.cpp
@@ -102,7 +102,7 @@
     meta->setCString(kKeyMIMEType, "image/jpeg");
     meta->setInt32(kKeyWidth, mWidth);
     meta->setInt32(kKeyHeight, mHeight);
-    meta->setInt32(kKeyCompressedSize, mSize);
+    meta->setInt32(kKeyMaxInputSize, mSize);
 
     return meta;
 }
diff --git a/cmds/stagefright/SineSource.cpp b/cmds/stagefright/SineSource.cpp
new file mode 100644
index 0000000..3c25a7f
--- /dev/null
+++ b/cmds/stagefright/SineSource.cpp
@@ -0,0 +1,100 @@
+#include "SineSource.h"
+
+#include <math.h>
+
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+SineSource::SineSource(int32_t sampleRate, int32_t numChannels)
+    : mStarted(false),
+      mSampleRate(sampleRate),
+      mNumChannels(numChannels),
+      mPhase(0),
+      mGroup(NULL) {
+    CHECK(numChannels == 1 || numChannels == 2);
+}
+
+SineSource::~SineSource() {
+    if (mStarted) {
+        stop();
+    }
+}
+
+status_t SineSource::start(MetaData *params) {
+    CHECK(!mStarted);
+
+    mGroup = new MediaBufferGroup;
+    mGroup->add_buffer(new MediaBuffer(kBufferSize));
+
+    mPhase = 0;
+    mStarted = true;
+
+    return OK;
+}
+
+status_t SineSource::stop() {
+    CHECK(mStarted);
+
+    delete mGroup;
+    mGroup = NULL;
+
+    mStarted = false;
+
+    return OK;
+}
+
+sp<MetaData> SineSource::getFormat() {
+    sp<MetaData> meta = new MetaData;
+    meta->setCString(kKeyMIMEType, "audio/raw");
+    meta->setInt32(kKeyChannelCount, mNumChannels);
+    meta->setInt32(kKeySampleRate, mSampleRate);
+
+    return meta;
+}
+
+status_t SineSource::read(
+        MediaBuffer **out, const ReadOptions *options) {
+    *out = NULL;
+
+    MediaBuffer *buffer;
+    status_t err = mGroup->acquire_buffer(&buffer);
+
+    if (err != OK) {
+        return err;
+    }
+
+    size_t frameSize = mNumChannels * sizeof(int16_t);
+    size_t numFramesPerBuffer = buffer->size() / frameSize;
+
+    int16_t *ptr = (int16_t *)buffer->data();
+
+    const double k = kFrequency / mSampleRate * (2.0 * M_PI);
+
+    double x = mPhase * k;
+    for (size_t i = 0; i < numFramesPerBuffer; ++i) {
+        int16_t amplitude = (int16_t)(32767.0 * sin(x));
+        
+        *ptr++ = amplitude;
+        if (mNumChannels == 2) {
+            *ptr++ = amplitude;
+        }
+
+        x += k;
+    }
+
+    buffer->meta_data()->setInt32(kKeyTimeUnits, mPhase);
+    buffer->meta_data()->setInt32(kKeyTimeScale, mSampleRate);
+
+    mPhase += numFramesPerBuffer;
+
+    buffer->set_range(0, numFramesPerBuffer * frameSize);
+
+    *out = buffer;
+
+    return OK;
+}
+
+}  // namespace android
diff --git a/cmds/stagefright/SineSource.h b/cmds/stagefright/SineSource.h
new file mode 100644
index 0000000..76ab669
--- /dev/null
+++ b/cmds/stagefright/SineSource.h
@@ -0,0 +1,39 @@
+#ifndef SINE_SOURCE_H_
+
+#define SINE_SOURCE_H_
+
+#include <media/stagefright/MediaSource.h>
+
+namespace android {
+
+struct MediaBufferGroup;
+
+struct SineSource : public MediaSource {
+    SineSource(int32_t sampleRate, int32_t numChannels);
+
+    virtual status_t start(MetaData *params);
+    virtual status_t stop();
+
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t read(
+            MediaBuffer **out, const ReadOptions *options = NULL);
+
+protected:
+    virtual ~SineSource();
+
+private:
+    enum { kBufferSize = 8192 };
+    static const double kFrequency = 500.0;
+
+    bool mStarted;
+    int32_t mSampleRate;
+    int32_t mNumChannels;
+    size_t mPhase;
+
+    MediaBufferGroup *mGroup;
+};
+
+}  // namespace android
+
+#endif // SINE_SOURCE_H_
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 4b44761..81a1c0a 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -14,7 +14,10 @@
  * limitations under the License.
  */
 
+#include "SineSource.h"
+
 #include <binder/ProcessState.h>
+#include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/CameraSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
@@ -24,9 +27,11 @@
 #include <media/stagefright/MmapSource.h>
 #include <media/stagefright/OMXClient.h>
 #include <media/stagefright/OMXCodec.h>
+#include <media/MediaPlayerInterface.h>
 
 using namespace android;
 
+#if 0
 class DummySource : public MediaSource {
 public:
     DummySource(int width, int height)
@@ -45,11 +50,6 @@
         return meta;
     }
 
-    virtual status_t getMaxSampleSize(size_t *max_size) {
-        *max_size = mSize;
-        return OK;
-    }
-
     virtual status_t start(MetaData *params) {
         return OK;
     }
@@ -158,7 +158,7 @@
         OMXCodec::Create(
                 client.interface(), enc_meta, true /* createEncoder */, decoder);
 
-#if 1
+#if 0
     sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
     writer->addSource(enc_meta, encoder);
     writer->start();
@@ -204,4 +204,60 @@
 
     return 0;
 }
+#else
 
+int main(int argc, char **argv) {
+    android::ProcessState::self()->startThreadPool();
+
+    OMXClient client;
+    CHECK_EQ(client.connect(), OK);
+
+    const int32_t kSampleRate = 22050;
+    const int32_t kNumChannels = 2;
+    sp<MediaSource> audioSource = new SineSource(kSampleRate, kNumChannels);
+
+#if 0
+    sp<MediaPlayerBase::AudioSink> audioSink;
+    AudioPlayer *player = new AudioPlayer(audioSink);
+    player->setSource(audioSource);
+    player->start();
+
+    sleep(10);
+
+    player->stop();
+#endif
+
+    sp<MetaData> encMeta = new MetaData;
+    encMeta->setCString(kKeyMIMEType, 1 ? "audio/3gpp" : "audio/mp4a-latm");
+    encMeta->setInt32(kKeySampleRate, kSampleRate);
+    encMeta->setInt32(kKeyChannelCount, kNumChannels);
+    encMeta->setInt32(kKeyMaxInputSize, 8192);
+
+    sp<MediaSource> encoder =
+        OMXCodec::Create(client.interface(), encMeta, true, audioSource);
+
+    encoder->start();
+
+    int32_t n = 0;
+    status_t err;
+    MediaBuffer *buffer;
+    while ((err = encoder->read(&buffer)) == OK) {
+        printf(".");
+        fflush(stdout);
+
+        buffer->release();
+        buffer = NULL;
+
+        if (++n == 10000) {
+            break;
+        }
+    }
+    printf("$\n");
+
+    encoder->stop();
+
+    client.disconnect();
+
+    return 0;
+}
+#endif
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 342de2b..f5f8f30 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -54,7 +54,7 @@
     private final String mAttributesName;
 
     // no need to be synchronized since the map is never changed once mService is written
-    private volatile Map<V, ServiceInfo<V>> mServices;
+    volatile Map<V, ServiceInfo<V>> mServices;
 
     // synchronized on "this"
     private BroadcastReceiver mReceiver = null;
@@ -81,6 +81,7 @@
             if (mReceiver == null) {
                 synchronized (this) {
                     mReceiver = new BroadcastReceiver() {
+                        @Override
                         public void onReceive(Context context, Intent intent) {
                             mServices = generateServicesMap();
                         }
@@ -91,6 +92,7 @@
                 intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
                 intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
                 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+                intentFilter.addDataScheme("package");
                 mContext.registerReceiver(mReceiver, intentFilter);
                 return true;
             }
@@ -122,6 +124,7 @@
             this.uid = uid;
         }
 
+        @Override
         public String toString() {
             return "ServiceInfo: " + type + ", " + componentName;
         }
@@ -159,6 +162,7 @@
         maybeUnregisterForPackageChanges();
     }
 
+    @Override
     protected void finalize() throws Throwable {
         synchronized (this) {
             if (mReceiver != null) {
@@ -169,7 +173,7 @@
         super.finalize();
     }
 
-    private Map<V, ServiceInfo<V>> generateServicesMap() {
+    Map<V, ServiceInfo<V>> generateServicesMap() {
         Map<V, ServiceInfo<V>> services = Maps.newHashMap();
         PackageManager pm = mContext.getPackageManager();
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d569220..82bff4a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5410,6 +5410,18 @@
     }
 
     /**
+     *  @hide
+     */
+    protected void onDrawVScrollBar(Canvas canvas, ScrollBarDrawable scrollBar,
+                                    int l, int t, int r, int b) {
+        scrollBar.setBounds(l, t, r, b);
+        scrollBar.setParameters(computeVerticalScrollRange(),
+                                computeVerticalScrollOffset(),
+                                computeVerticalScrollExtent(), true);
+        scrollBar.draw(canvas);
+    }
+    
+    /**
      * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()}
      * returns true.</p>
      *
@@ -5441,13 +5453,11 @@
         // TODO: Deal with RTL languages to position scrollbar on left
         final int left = scrollX + width - size - (mUserPaddingRight & inside);
 
-        scrollBar.setBounds(left, scrollY + (mPaddingTop & inside),
-                left + size, scrollY + height - (mUserPaddingBottom & inside));
-        scrollBar.setParameters(
-                computeVerticalScrollRange(),
-                computeVerticalScrollOffset(),
-                computeVerticalScrollExtent(), true);
-        scrollBar.draw(canvas);
+        onDrawVScrollBar(canvas, scrollBar,
+                         left,
+                         scrollY + (mPaddingTop & inside),
+                         left + size,
+                         scrollY + height - (mUserPaddingBottom & inside));
     }
 
     /**
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 41e604d..e504591 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -177,17 +177,6 @@
     }
 
     /**
-     * Tell the host application that the WebView has changed viewing modes.
-     * @param newViewingMode  One of the values described in WebView as possible
-     *                        values for the viewing mode
-     */
-    /* package */ void uiOnChangeViewingMode(int newViewingMode) {
-        if (mWebChromeClient != null) {
-            mWebChromeClient.onChangeViewingMode(mWebView, newViewingMode);
-        }
-    }
-
-    /**
      * Called by the UI side.  Calling overrideUrlLoading from the WebCore
      * side will post a message to call this method.
      */
diff --git a/core/java/android/webkit/GeolocationService.java b/core/java/android/webkit/GeolocationService.java
index 78b25ba..646f8c5 100755
--- a/core/java/android/webkit/GeolocationService.java
+++ b/core/java/android/webkit/GeolocationService.java
@@ -156,11 +156,16 @@
      * Registers this object with the location service.
      */
     private void registerForLocationUpdates() {
-        mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
-        mIsNetworkProviderAvailable = true;
-        if (mIsGpsEnabled) {
-            mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
-            mIsGpsProviderAvailable = true;
+        try {
+            mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
+            mIsNetworkProviderAvailable = true;
+            if (mIsGpsEnabled) {
+                mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
+                mIsGpsProviderAvailable = true;
+            }
+        } catch(SecurityException e) {
+            Log.e(TAG, "Caught security exception registering for location updates from system. " +
+                "This should only happen in DumpRenderTree.");
         }
     }
 
diff --git a/core/java/android/webkit/ViewManager.java b/core/java/android/webkit/ViewManager.java
index af33b4f..63f4033 100644
--- a/core/java/android/webkit/ViewManager.java
+++ b/core/java/android/webkit/ViewManager.java
@@ -50,8 +50,8 @@
             }
             setBounds(x, y, width, height);
             final AbsoluteLayout.LayoutParams lp =
-                    new AbsoluteLayout.LayoutParams(ctv(width), ctv(height),
-                            ctv(x), ctv(y));
+                    new AbsoluteLayout.LayoutParams(ctvX(width), ctvX(height),
+                            ctvX(x), ctvY(y));
             mWebView.mPrivateHandler.post(new Runnable() {
                 public void run() {
                     // This method may be called multiple times. If the view is
@@ -97,9 +97,21 @@
         return new ChildView();
     }
 
-    // contentToView shorthand.
-    private int ctv(int val) {
-        return mWebView.contentToView(val);
+    /**
+     * Shorthand for calling mWebView.contentToViewX.  Used when obtaining a
+     * view x coordinate from a content x coordinate, or when getting a
+     * view dimension from a content dimension, whether it be in x or y.
+     */
+    private int ctvX(int val) {
+        return mWebView.contentToViewX(val);
+    }
+
+    /**
+     * Shorthand for calling mWebView.contentToViewY.  Used when obtaining a
+     * view y coordinate from a content y coordinate.
+     */
+    private int ctvY(int val) {
+        return mWebView.contentToViewY(val);
     }
 
     void scaleAll() {
@@ -107,10 +119,10 @@
             View view = v.mView;
             AbsoluteLayout.LayoutParams lp =
                     (AbsoluteLayout.LayoutParams) view.getLayoutParams();
-            lp.width = ctv(v.width);
-            lp.height = ctv(v.height);
-            lp.x = ctv(v.x);
-            lp.y = ctv(v.y);
+            lp.width = ctvX(v.width);
+            lp.height = ctvX(v.height);
+            lp.x = ctvX(v.x);
+            lp.y = ctvY(v.y);
             view.setLayoutParams(lp);
         }
     }
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index ad4ba05..6421fe7 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -23,15 +23,6 @@
 public class WebChromeClient {
 
     /**
-     * Tell the host application that the WebView has changed viewing modes.
-     * @param view The WebView that initiated the callback.
-     * @param newViewingMode  One of the values described in WebView as possible
-     *                        values for the viewing mode
-     * @hide
-     */
-    public void onChangeViewingMode(WebView view, int newViewingMode) {}
-
-    /**
      * Tell the host application the current progress of loading a page.
      * @param view The WebView that initiated the callback.
      * @param newProgress Current page loading progress, represented by
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 792fdf2..611681f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -525,48 +525,6 @@
     // the last zoom scale.
     boolean mInZoomOverview = false;
 
-    // The viewing mode of this webview.  Reported back to the WebChromeClient
-    // so we can hide and display the title bar as appropriate.
-    private int mViewingMode;
-    /**
-     * Not supporting overview vs reading mode
-     * @hide
-     */
-    public final static int NO_VIEWING_MODE = 0;
-    /**
-     * Zoom overview mode.  The page is zoomed all the way out, mInZoomOverview
-     * is true, and the title bar is showing.  Double tapping will change to
-     * reading mode.
-     * @hide
-     */
-    public final static int OVERVIEW_MODE = 1;
-    /**
-     * Reading mode. The page is at the level specified by the user,
-     * mInZoomOverview is false, and the title bar is not showing.  Double
-     * tapping will change to zoom overview mode.
-     * @hide
-     */
-    public final static int READING_MODE = 2;
-    /**
-     * Modified reading mode, which shows the title bar.  mInZoomOverview is
-     * false, and double tapping will change to zoom overview mode.  However,
-     * if the scrolling will change to reading mode.  Used when swiping a
-     * tab into view which was in reading mode, unless it was a mobile site
-     * with zero scroll.
-     * @hide
-     */
-    public final static int READING_MODE_WITH_TITLE_BAR = 3;
-    /**
-     * Another modified reading mode.  For loading a mobile site, or swiping a
-     * tab into view which was displaying a mobile site in reading mode
-     * with zero scroll
-     * @hide
-     */
-    public final static int TITLE_BAR_DISMISS_MODE = 4;
-    // Whether the current site is a mobile site.  Determined when we receive
-    // NEW_PICTURE_MSG_ID to help determine how to handle double taps
-    private boolean mMobileSite;
-
     // ideally mZoomOverviewWidth should be mContentWidth. But sites like espn,
     // engadget always have wider mContentWidth no matter what viewport size is.
     int mZoomOverviewWidth = WebViewCore.DEFAULT_VIEWPORT_WIDTH;
@@ -962,14 +920,20 @@
 
     /*
      * Return the height of the view where the content of WebView should render
-     * to.
+     * to.  Note that this excludes mTitleBar, if there is one.
      */
     private int getViewHeight() {
-        if (!isHorizontalScrollBarEnabled() || mOverlayHorizontalScrollbar) {
-            return getHeight();
-        } else {
-            return getHeight() - getHorizontalScrollbarHeight();
+        int height = getHeight();
+        if (isHorizontalScrollBarEnabled() && mOverlayHorizontalScrollbar) {
+            height -= getHorizontalScrollbarHeight();
         }
+        if (mTitleBar != null) {
+            int titleBarVisibleHeight = mTitleBar.getHeight() - mScrollY;
+            if (titleBarVisibleHeight > 0) {
+                height -= titleBarVisibleHeight;
+            }
+        }
+        return height;
     }
 
     /**
@@ -1180,7 +1144,6 @@
             if (mInZoomOverview) {
                 b.putFloat("lastScale", mLastScale);
             }
-            b.putBoolean("mobile", mMobileSite);
             return true;
         }
         return false;
@@ -1226,20 +1189,12 @@
                 // correctly
                 mActualScale = scale;
                 float lastScale = b.getFloat("lastScale", -1.0f);
-                mMobileSite = b.getBoolean("mobile", false);
                 if (lastScale > 0) {
                     mInZoomOverview = true;
-                    mViewingMode = OVERVIEW_MODE;
                     mLastScale = lastScale;
                 } else {
                     mInZoomOverview = false;
-                    if (mMobileSite && (mScrollX | mScrollY) == 0) {
-                        mViewingMode = TITLE_BAR_DISMISS_MODE;
-                    } else {
-                        mViewingMode = READING_MODE_WITH_TITLE_BAR;
-                    }
                 }
-                mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
                 invalidate();
                 return true;
             }
@@ -1692,8 +1647,8 @@
         if (type == HitTestResult.UNKNOWN_TYPE
                 || type == HitTestResult.SRC_ANCHOR_TYPE) {
             // Now check to see if it is an image.
-            int contentX = viewToContent((int) mLastTouchX + mScrollX);
-            int contentY = viewToContent((int) mLastTouchY + mScrollY);
+            int contentX = viewToContentX((int) mLastTouchX + mScrollX);
+            int contentY = viewToContentY((int) mLastTouchY + mScrollY);
             String text = nativeImageURI(contentX, contentY);
             if (text != null) {
                 result.setType(type == HitTestResult.UNKNOWN_TYPE ?
@@ -1736,8 +1691,8 @@
      *            as the data member with "url" as key. The result can be null.
      */
     public void requestImageRef(Message msg) {
-        int contentX = viewToContent((int) mLastTouchX + mScrollX);
-        int contentY = viewToContent((int) mLastTouchY + mScrollY);
+        int contentX = viewToContentX((int) mLastTouchX + mScrollX);
+        int contentY = viewToContentY((int) mLastTouchY + mScrollY);
         String ref = nativeImageURI(contentX, contentY);
         Bundle data = msg.getData();
         data.putString("url", ref);
@@ -1771,31 +1726,88 @@
         return pinLoc(y, getViewHeight(), computeVerticalScrollRange());
     }
 
-    /*package*/ int viewToContent(int x) {
+    /**
+     * A title bar which is embedded in this WebView, and scrolls along with it
+     * vertically, but not horizontally.
+     */
+    private View mTitleBar;
+
+    /**
+     * Add or remove a title bar to be embedded into the WebView, and scroll
+     * along with it vertically, while remaining in view horizontally. Pass
+     * null to remove the title bar from the WebView, and return to drawing
+     * the WebView normally without translating to account for the title bar.
+     * @hide
+     */
+    public void addTitleBar(View v) {
+        if (null == v) {
+            removeView(mTitleBar);
+        } else {
+            addView(v, new AbsoluteLayout.LayoutParams(
+                    ViewGroup.LayoutParams.FILL_PARENT,
+                    ViewGroup.LayoutParams.WRAP_CONTENT, mScrollX, 0));
+        }
+        mTitleBar = v;
+    }
+
+    /**
+     * Given an x coordinate in view space, convert it to content space.  Also
+     * may be used for absolute heights (such as for the WebTextView's
+     * textSize, which is unaffected by the height of the title bar).
+     */
+    /*package*/ int viewToContentX(int x) {
         return Math.round(x * mInvActualScale);
     }
 
-    /*package*/ int contentToView(int x) {
+    /**
+     * Given a y coordinate in view space, convert it to content space.
+     * Takes into account the height of the title bar if there is one
+     * embedded into the WebView.
+     */
+    /*package*/ int viewToContentY(int y) {
+        if (mTitleBar != null) {
+            y -= mTitleBar.getHeight();
+        }
+        return viewToContentX(y);
+    }
+
+    /**
+     * Given an x coordinate in content space, convert it to view
+     * space.  Also used for absolute heights.
+     */
+    /*package*/ int contentToViewX(int x) {
         return Math.round(x * mActualScale);
     }
 
+    /**
+     * Given a y coordinate in content space, convert it to view
+     * space.  Takes into account the height of the title bar.
+     */
+    /*package*/ int contentToViewY(int y) {
+        int val = Math.round(y * mActualScale);
+        if (mTitleBar != null) {
+            val += mTitleBar.getHeight();
+        }
+        return val;
+    }
+
     // Called by JNI to invalidate the View, given rectangle coordinates in
     // content space
     private void viewInvalidate(int l, int t, int r, int b) {
-        invalidate(contentToView(l), contentToView(t), contentToView(r),
-                contentToView(b));
+        invalidate(contentToViewX(l), contentToViewY(t), contentToViewX(r),
+                contentToViewY(b));
     }
 
     // Called by JNI to invalidate the View after a delay, given rectangle
     // coordinates in content space
     private void viewInvalidateDelayed(long delay, int l, int t, int r, int b) {
-        postInvalidateDelayed(delay, contentToView(l), contentToView(t),
-                contentToView(r), contentToView(b));
+        postInvalidateDelayed(delay, contentToViewX(l), contentToViewY(t),
+                contentToViewX(r), contentToViewY(b));
     }
 
     private Rect contentToView(Rect x) {
-        return new Rect(contentToView(x.left), contentToView(x.top)
-                , contentToView(x.right), contentToView(x.bottom));
+        return new Rect(contentToViewX(x.left), contentToViewY(x.top)
+                , contentToViewX(x.right), contentToViewY(x.bottom));
     }
 
     // stop the scroll animation, and don't let a subsequent fling add
@@ -1934,10 +1946,10 @@
     // Sets r to be our visible rectangle in content coordinates
     private void calcOurContentVisibleRect(Rect r) {
         calcOurVisibleRect(r);
-        r.left = viewToContent(r.left);
-        r.top = viewToContent(r.top);
-        r.right = viewToContent(r.right);
-        r.bottom = viewToContent(r.bottom);
+        r.left = viewToContentX(r.left);
+        r.top = viewToContentY(r.top);
+        r.right = viewToContentX(r.right);
+        r.bottom = viewToContentY(r.bottom);
     }
 
     static class ViewSizeData {
@@ -1994,7 +2006,7 @@
         if (mDrawHistory) {
             return mHistoryWidth;
         } else {
-            return contentToView(mContentWidth);
+            return contentToViewX(mContentWidth);
         }
     }
 
@@ -2006,7 +2018,7 @@
         if (mDrawHistory) {
             return mHistoryHeight;
         } else {
-            int height = contentToView(mContentHeight);
+            int height = contentToViewX(mContentHeight);
             if (mFindIsUp) {
                 height += FIND_HEIGHT;
             }
@@ -2014,6 +2026,23 @@
         }
     }
 
+    @Override
+    protected int computeVerticalScrollOffset() {
+        int offset = super.computeVerticalScrollOffset();
+        if (mTitleBar != null) {
+            // Need to adjust so that the resulting offset is at minimum
+            // the height of the title bar, if it is visible.
+            offset += mTitleBar.getHeight()*computeVerticalScrollRange()
+                    /getViewHeight();
+        }
+        return offset;
+    }
+
+    @Override
+    protected int computeVerticalScrollExtent() {
+        return getViewHeight();
+    }
+
     /**
      * Get the url for the current page. This is not always the same as the url
      * passed to WebViewClient.onPageStarted because although the load for
@@ -2365,8 +2394,8 @@
             // keys are hit, this should be safe. Right?
             return false;
         }
-        cx = contentToView(cx);
-        cy = contentToView(cy);
+        cx = contentToViewX(cx);
+        cy = contentToViewY(cy);
         if (mHeightCanMeasure) {
             // move our visible rect according to scroll request
             if (cy != 0) {
@@ -2398,8 +2427,8 @@
             // saved scroll position, it is ok to skip this.
             return false;
         }
-        int vx = contentToView(cx);
-        int vy = contentToView(cy);
+        int vx = contentToViewX(cx);
+        int vy = contentToViewY(cy);
 //        Log.d(LOGTAG, "content scrollTo [" + cx + " " + cy + "] view=[" +
 //                      vx + " " + vy + "]");
         pinScrollTo(vx, vy, false, 0);
@@ -2417,8 +2446,8 @@
             // is used in the view system.
             return;
         }
-        int vx = contentToView(cx);
-        int vy = contentToView(cy);
+        int vx = contentToViewX(cx);
+        int vy = contentToViewY(cy);
         pinScrollTo(vx, vy, true, 0);
     }
 
@@ -2435,12 +2464,12 @@
         }
 
         if (mHeightCanMeasure) {
-            if (getMeasuredHeight() != contentToView(mContentHeight)
+            if (getMeasuredHeight() != contentToViewX(mContentHeight)
                     && updateLayout) {
                 requestLayout();
             }
         } else if (mWidthCanMeasure) {
-            if (getMeasuredWidth() != contentToView(mContentWidth)
+            if (getMeasuredWidth() != contentToViewX(mContentWidth)
                     && updateLayout) {
                 requestLayout();
             }
@@ -2582,7 +2611,22 @@
     }
 
     @Override
+    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+        if (child == mTitleBar) {
+            // When drawing the title bar, move it horizontally to always show
+            // at the top of the WebView.
+            mTitleBar.offsetLeftAndRight(mScrollX - mTitleBar.getLeft());
+        }
+        return super.drawChild(canvas, child, drawingTime);
+    }
+
+    @Override
     protected void onDraw(Canvas canvas) {
+        int saveCount = canvas.getSaveCount();
+        if (mTitleBar != null) {
+            canvas.save();
+            canvas.translate(0, (int) mTitleBar.getHeight());
+        }
         // if mNativeClass is 0, the WebView has been destroyed. Do nothing.
         if (mNativeClass == 0) {
             return;
@@ -2596,7 +2640,7 @@
                 mTouchMode = TOUCH_DONE_MODE;
             }
         }
-        int sc = canvas.save();
+        canvas.save();
         if (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM) {
             scrollZoomDraw(canvas);
         } else {
@@ -2613,7 +2657,7 @@
                     || mTrackballDown || mGotCenterDown, false);
             drawCoreAndCursorRing(canvas, mBackgroundColor, mDrawCursorRing);
         }
-        canvas.restoreToCount(sc);
+        canvas.restoreToCount(saveCount);
 
         if (AUTO_REDRAW_HACK && mAutoRedraw) {
             invalidate();
@@ -3210,7 +3254,7 @@
             // Initialize our generation number.
             mTextGeneration = 0;
         }
-        mWebTextView.setTextSize(contentToView(nativeFocusCandidateTextSize()));
+        mWebTextView.setTextSize(contentToViewX(nativeFocusCandidateTextSize()));
         Rect visibleRect = new Rect();
         calcOurContentVisibleRect(visibleRect);
         // Note that sendOurVisibleRect calls viewToContent, so the coordinates
@@ -3370,8 +3414,8 @@
             mShiftIsPressed = true;
             if (nativeHasCursorNode()) {
                 Rect rect = nativeCursorNodeBounds();
-                mSelectX = contentToView(rect.left);
-                mSelectY = contentToView(rect.top);
+                mSelectX = contentToViewX(rect.left);
+                mSelectY = contentToViewY(rect.top);
             } else {
                 mSelectX = mScrollX + (int) mLastTouchX;
                 mSelectY = mScrollY + (int) mLastTouchY;
@@ -3758,12 +3802,6 @@
     protected void onScrollChanged(int l, int t, int oldl, int oldt) {
         super.onScrollChanged(l, t, oldl, oldt);
 
-        if (mViewingMode == READING_MODE_WITH_TITLE_BAR
-                || mViewingMode == TITLE_BAR_DISMISS_MODE) {
-            mViewingMode = READING_MODE;
-            mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
-        }
-
         sendOurVisibleRect();
     }
 
@@ -3840,8 +3878,8 @@
                         eventTime - mLastSentTouchTime > TOUCH_SENT_INTERVAL)) {
             WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
             ted.mAction = action;
-            ted.mX = viewToContent((int) x + mScrollX);
-            ted.mY = viewToContent((int) y + mScrollY);
+            ted.mX = viewToContentX((int) x + mScrollX);
+            ted.mY = viewToContentY((int) y + mScrollY);
             mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
             mLastSentTouchTime = eventTime;
         }
@@ -3873,8 +3911,8 @@
                     if (DebugFlags.WEB_VIEW) {
                         Log.v(LOGTAG, "select=" + mSelectX + "," + mSelectY);
                     }
-                    nativeMoveSelection(viewToContent(mSelectX)
-                            , viewToContent(mSelectY), false);
+                    nativeMoveSelection(viewToContentX(mSelectX),
+                            viewToContentY(mSelectY), false);
                     mTouchSelection = mExtendSelection = true;
                 } else if (mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
                     mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
@@ -3930,8 +3968,8 @@
                         if (DebugFlags.WEB_VIEW) {
                             Log.v(LOGTAG, "xtend=" + mSelectX + "," + mSelectY);
                         }
-                        nativeMoveSelection(viewToContent(mSelectX)
-                                , viewToContent(mSelectY), true);
+                        nativeMoveSelection(viewToContentX(mSelectX),
+                               viewToContentY(mSelectY), true);
                         invalidate();
                         break;
                     }
@@ -3981,13 +4019,6 @@
                 deltaY = newScrollY - mScrollY;
                 boolean done = false;
                 if (deltaX == 0 && deltaY == 0) {
-                    // The user attempted to pan the page, so dismiss the title
-                    // bar
-                    if (mViewingMode == READING_MODE_WITH_TITLE_BAR
-                            || mViewingMode == TITLE_BAR_DISMISS_MODE) {
-                        mViewingMode = READING_MODE;
-                        mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
-                    }
                     done = true;
                 } else {
                     if (mSnapScrollMode == SNAP_X || mSnapScrollMode == SNAP_Y) {
@@ -4307,8 +4338,8 @@
                     + " yRate=" + yRate
                     );
         }
-        nativeMoveSelection(viewToContent(mSelectX)
-                , viewToContent(mSelectY), mExtendSelection);
+        nativeMoveSelection(viewToContentX(mSelectX),
+                viewToContentY(mSelectY), mExtendSelection);
         int scrollX = mSelectX < mScrollX ? -SELECT_CURSOR_OFFSET
                 : mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
                 : 0;
@@ -4687,8 +4718,8 @@
             return;
         }
         // mLastTouchX and mLastTouchY are the point in the current viewport
-        int contentX = viewToContent((int) mLastTouchX + mScrollX);
-        int contentY = viewToContent((int) mLastTouchY + mScrollY);
+        int contentX = viewToContentX((int) mLastTouchX + mScrollX);
+        int contentY = viewToContentY((int) mLastTouchY + mScrollY);
         Rect rect = new Rect(contentX - mNavSlop, contentY - mNavSlop,
                 contentX + mNavSlop, contentY + mNavSlop);
         nativeSelectBestAt(rect);
@@ -4703,8 +4734,8 @@
         if (!inEditingMode() || mWebViewCore == null) {
             return;
         }
-        mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT, viewToContent(x),
-                viewToContent(y));
+        mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT, viewToContentX(x),
+                viewToContentY(y));
     }
 
     /**
@@ -4751,16 +4782,16 @@
         if (!inEditingMode()) {
             return;
         }
-        int x = viewToContent((int) event.getX() + mWebTextView.getLeft());
-        int y = viewToContent((int) event.getY() + mWebTextView.getTop());
+        int x = viewToContentX((int) event.getX() + mWebTextView.getLeft());
+        int y = viewToContentY((int) event.getY() + mWebTextView.getTop());
         nativeTextInputMotionUp(x, y);
     }
 
     /*package*/ void shortPressOnTextField() {
         if (inEditingMode()) {
             View v = mWebTextView;
-            int x = viewToContent((v.getLeft() + v.getRight()) >> 1);
-            int y = viewToContent((v.getTop() + v.getBottom()) >> 1);
+            int x = viewToContentX((v.getLeft() + v.getRight()) >> 1);
+            int y = viewToContentY((v.getTop() + v.getBottom()) >> 1);
             nativeTextInputMotionUp(x, y);
         }
     }
@@ -4771,8 +4802,8 @@
         }
         switchOutDrawHistory();
         // mLastTouchX and mLastTouchY are the point in the current viewport
-        int contentX = viewToContent((int) mLastTouchX + mScrollX);
-        int contentY = viewToContent((int) mLastTouchY + mScrollY);
+        int contentX = viewToContentX((int) mLastTouchX + mScrollX);
+        int contentY = viewToContentY((int) mLastTouchY + mScrollY);
         if (nativeMotionUp(contentX, contentY, mNavSlop)) {
             if (mLogEvent) {
                 Checkin.updateStats(mContext.getContentResolver(),
@@ -4784,42 +4815,13 @@
         }
     }
 
-    /**
-     * Called when the Tabs are used to slide this WebView's tab into view.
-     * @hide
-     */
-    public void slideIntoFocus() {
-        if (mViewingMode == READING_MODE) {
-            if (!mMobileSite || (mScrollX | mScrollY) != 0) {
-                mViewingMode = READING_MODE_WITH_TITLE_BAR;
-            } else {
-                mViewingMode = TITLE_BAR_DISMISS_MODE;
-            }
-            mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
-        }
-    }
-
     private void doDoubleTap() {
-        if (mWebViewCore.getSettings().getUseWideViewPort() == false ||
-                mViewingMode == NO_VIEWING_MODE) {
+        if (mWebViewCore.getSettings().getUseWideViewPort() == false) {
             return;
         }
-        if (mViewingMode == TITLE_BAR_DISMISS_MODE) {
-            mViewingMode = READING_MODE;
-            // mInZoomOverview will not change, so change the viewing mode
-            // and return
-            mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
-            return;
-        }
-        if (mViewingMode == READING_MODE_WITH_TITLE_BAR && mMobileSite) {
-            scrollTo(0,0);
-        }
-        // READING_MODE_WITH_TITLE_BAR will go to OVERVIEW_MODE here.
         mZoomCenterX = mLastTouchX;
         mZoomCenterY = mLastTouchY;
         mInZoomOverview = !mInZoomOverview;
-        mViewingMode = mInZoomOverview ? OVERVIEW_MODE : READING_MODE;
-        mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
         // remove the zoom control after double tap
         if (getSettings().getBuiltInZoomControls()) {
             if (mZoomButtonsController.isVisible()) {
@@ -4837,8 +4839,8 @@
             zoomWithPreview((float) getViewWidth() / mZoomOverviewWidth);
         } else {
             // mLastTouchX and mLastTouchY are the point in the current viewport
-            int contentX = viewToContent((int) mLastTouchX + mScrollX);
-            int contentY = viewToContent((int) mLastTouchY + mScrollY);
+            int contentX = viewToContentX((int) mLastTouchX + mScrollX);
+            int contentY = viewToContentY((int) mLastTouchY + mScrollY);
             int left = nativeGetBlockLeftEdge(contentX, contentY, mActualScale);
             if (left != NO_LEFTEDGE) {
                 // add a 5pt padding to the left edge. Re-calculate the zoom
@@ -5169,22 +5171,12 @@
                                 restoreState.mScrollY);
                         if (!ENABLE_DOUBLETAP_ZOOM
                                 || !settings.getLoadWithOverviewMode()) {
-                            mMobileSite = false;
-                            mViewingMode = NO_VIEWING_MODE;
                         } else {
-                            mMobileSite = restoreState.mMobileSite;
                             if (useWideViewport
                                     && restoreState.mViewScale == 0) {
-                                mViewingMode = OVERVIEW_MODE;
                                 mInZoomOverview = true;
-                            } else if (mMobileSite
-                                    && (mScrollX | mScrollY) == 0) {
-                                mViewingMode = TITLE_BAR_DISMISS_MODE;
-                            } else {
-                                mViewingMode = READING_MODE_WITH_TITLE_BAR;
                             }
                         }
-                        mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
                         // As we are on a new page, remove the WebTextView. This
                         // is necessary for page loads driven by webkit, and in
                         // particular when the user was on a password field, so
@@ -5648,7 +5640,7 @@
             width = visRect.width() / 2;
         }
         // FIXME the divisor should be retrieved from somewhere
-        return viewToContent(width);
+        return viewToContentX(width);
     }
 
     private int getScaledMaxYScroll() {
@@ -5663,7 +5655,7 @@
         // FIXME the divisor should be retrieved from somewhere
         // the closest thing today is hard-coded into ScrollView.java
         // (from ScrollView.java, line 363)   int maxJump = height/2;
-        return viewToContent(height);
+        return viewToContentY(height);
     }
 
     /**
diff --git a/core/res/res/drawable-hdpi/divider_vertical_bright.9.png b/core/res/res/drawable-hdpi/divider_vertical_bright.9.png
index 128a4de..1035656 100644
--- a/core/res/res/drawable-hdpi/divider_vertical_bright.9.png
+++ b/core/res/res/drawable-hdpi/divider_vertical_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_focus.9.png b/core/res/res/drawable-hdpi/tab_focus.9.png
index 0c3a9ee..6e8a71f 100644
--- a/core/res/res/drawable-hdpi/tab_focus.9.png
+++ b/core/res/res/drawable-hdpi/tab_focus.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_focus_bar_left.9.png b/core/res/res/drawable-hdpi/tab_focus_bar_left.9.png
index 54e3022..51194a4 100644
--- a/core/res/res/drawable-hdpi/tab_focus_bar_left.9.png
+++ b/core/res/res/drawable-hdpi/tab_focus_bar_left.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_focus_bar_right.9.png b/core/res/res/drawable-hdpi/tab_focus_bar_right.9.png
index 34a85f0..51194a4 100644
--- a/core/res/res/drawable-hdpi/tab_focus_bar_right.9.png
+++ b/core/res/res/drawable-hdpi/tab_focus_bar_right.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_press.9.png b/core/res/res/drawable-hdpi/tab_press.9.png
index 6b3c1c7..119b2c6 100644
--- a/core/res/res/drawable-hdpi/tab_press.9.png
+++ b/core/res/res/drawable-hdpi/tab_press.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_press_bar_left.9.png b/core/res/res/drawable-hdpi/tab_press_bar_left.9.png
index f998532..dc2fbce 100644
--- a/core/res/res/drawable-hdpi/tab_press_bar_left.9.png
+++ b/core/res/res/drawable-hdpi/tab_press_bar_left.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_press_bar_right.9.png b/core/res/res/drawable-hdpi/tab_press_bar_right.9.png
index 43515bd..dc2fbce 100644
--- a/core/res/res/drawable-hdpi/tab_press_bar_right.9.png
+++ b/core/res/res/drawable-hdpi/tab_press_bar_right.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected.9.png b/core/res/res/drawable-hdpi/tab_selected.9.png
index b128b48..29d45a17 100644
--- a/core/res/res/drawable-hdpi/tab_selected.9.png
+++ b/core/res/res/drawable-hdpi/tab_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected_bar_left.9.png b/core/res/res/drawable-hdpi/tab_selected_bar_left.9.png
index a49ef68..aa935fe 100644
--- a/core/res/res/drawable-hdpi/tab_selected_bar_left.9.png
+++ b/core/res/res/drawable-hdpi/tab_selected_bar_left.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected_bar_right.9.png b/core/res/res/drawable-hdpi/tab_selected_bar_right.9.png
index 472f839..aa935fe 100644
--- a/core/res/res/drawable-hdpi/tab_selected_bar_right.9.png
+++ b/core/res/res/drawable-hdpi/tab_selected_bar_right.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_unselected.9.png b/core/res/res/drawable-hdpi/tab_unselected.9.png
index ed9e311..f5781ab 100644
--- a/core/res/res/drawable-hdpi/tab_unselected.9.png
+++ b/core/res/res/drawable-hdpi/tab_unselected.9.png
Binary files differ
diff --git a/include/media/mediascanner.h b/include/media/mediascanner.h
index 7749566..cd0b86e 100644
--- a/include/media/mediascanner.h
+++ b/include/media/mediascanner.h
@@ -59,16 +59,17 @@
 class MediaScannerClient
 {
 public:
-	MediaScannerClient();
-	virtual ~MediaScannerClient();
-	void setLocale(const char* locale);
-	void beginFile();
-	bool addStringTag(const char* name, const char* value);
-	void endFile();
-	
-	virtual bool scanFile(const char* path, long long lastModified, long long fileSize) = 0;
-	virtual bool handleStringTag(const char* name, const char* value) = 0;
-	virtual bool setMimeType(const char* mimeType) = 0;
+    MediaScannerClient();
+    virtual ~MediaScannerClient();
+    void setLocale(const char* locale);
+    void beginFile();
+    bool addStringTag(const char* name, const char* value);
+    void endFile();
+
+    virtual bool scanFile(const char* path, long long lastModified, long long fileSize) = 0;
+    virtual bool handleStringTag(const char* name, const char* value) = 0;
+    virtual bool setMimeType(const char* mimeType) = 0;
+    virtual bool addNoMediaFolder(const char* path) = 0;
 
 protected:
     void convertValues(uint32_t encoding);
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index be60565..abb45a9 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -45,7 +45,7 @@
     kKeyPlatformPrivate   = 'priv',
     kKeyDecoderComponent  = 'decC',
     kKeyBufferID          = 'bfID',
-    kKeyCompressedSize    = 'cmpS',
+    kKeyMaxInputSize      = 'inpS',
 };
 
 enum {
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 5b0e0b4..ac45481 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -135,6 +135,8 @@
     void addCodecSpecificData(const void *data, size_t size);
     void clearCodecSpecificData();
 
+    void setComponentRole();
+
     void setAMRFormat();
     void setAACFormat(int32_t numChannels, int32_t sampleRate);
 
@@ -155,6 +157,11 @@
     void setJPEGInputFormat(
             OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize);
 
+    void setMinBufferSize(OMX_U32 portIndex, OMX_U32 size);
+
+    void setRawAudioFormat(
+            OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels);
+
     status_t allocateBuffers();
     status_t allocateBuffersOnPort(OMX_U32 portIndex);
 
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 3d5aae3..fcc76ca5 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -825,6 +825,22 @@
             }
         }
 
+        public void addNoMediaFolder(String path) {
+            ContentValues values = new ContentValues();
+            values.put(MediaStore.Images.ImageColumns.DATA, "");
+            String [] pathSpec = new String[] {path + '%'};
+            try {
+                mMediaProvider.update(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values,
+                        MediaStore.Images.ImageColumns.DATA + " LIKE ?", pathSpec);
+                mMediaProvider.update(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values,
+                        MediaStore.Images.ImageColumns.DATA + " LIKE ?", pathSpec);
+                mMediaProvider.update(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values,
+                        MediaStore.Images.ImageColumns.DATA + " LIKE ?", pathSpec);
+            } catch (RemoteException e) {
+                throw new RuntimeException();
+            }
+        }
+
     }; // end of anonymous MediaScannerClient instance
 
     private void prescan(String filePath) throws RemoteException {
diff --git a/media/java/android/media/MediaScannerClient.java b/media/java/android/media/MediaScannerClient.java
index cf1a8da..258c3b4 100644
--- a/media/java/android/media/MediaScannerClient.java
+++ b/media/java/android/media/MediaScannerClient.java
@@ -25,11 +25,13 @@
     
     public void scanFile(String path, String mimeType, long lastModified, long fileSize);
 
+    public void addNoMediaFolder(String path);
+
     /**
      * Called by native code to return metadata extracted from media files.
      */
     public void handleStringTag(String name, String value);
-    
+
     /**
      * Called by native code to return mime type extracted from DRM content.
      */
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 97de486..6a5404e3 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -65,6 +65,8 @@
                                                      "(Ljava/lang/String;Ljava/lang/String;)V");
             mSetMimeTypeMethodID = env->GetMethodID(mediaScannerClientInterface, "setMimeType",
                                                      "(Ljava/lang/String;)V");
+            mAddNoMediaFolderMethodID = env->GetMethodID(mediaScannerClientInterface, "addNoMediaFolder",
+                                                     "(Ljava/lang/String;)V");
         }
     }
     
@@ -111,12 +113,26 @@
         return (!mEnv->ExceptionCheck());
     }
 
+    // returns true if it succeeded, false if an exception occured in the Java code
+    virtual bool addNoMediaFolder(const char* path)
+    {
+        jstring pathStr;
+        if ((pathStr = mEnv->NewStringUTF(path)) == NULL) return false;
+
+        mEnv->CallVoidMethod(mClient, mAddNoMediaFolderMethodID, pathStr);
+
+        mEnv->DeleteLocalRef(pathStr);
+        return (!mEnv->ExceptionCheck());
+    }
+
+
 private:
     JNIEnv *mEnv;
     jobject mClient;
     jmethodID mScanFileMethodID; 
     jmethodID mHandleStringTagMethodID; 
     jmethodID mSetMimeTypeMethodID;
+    jmethodID mAddNoMediaFolderMethodID;
 };
 
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 7c8defc..de808e5 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -77,6 +77,8 @@
     { "video/avc", "OMX.PV.avcenc" },
 };
 
+#define CODEC_LOGV(x, ...) LOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
+
 struct OMXCodecObserver : public BnOMXObserver {
     OMXCodecObserver(const wp<OMXCodec> &target)
         : mTarget(target) {
@@ -150,6 +152,15 @@
     }
 }
 
+template<class T>
+static void InitOMXParams(T *params) {
+    params->nSize = sizeof(T);
+    params->nVersion.s.nVersionMajor = 1;
+    params->nVersion.s.nVersionMinor = 0;
+    params->nVersion.s.nRevision = 0;
+    params->nVersion.s.nStep = 0;
+}
+
 // static
 sp<OMXCodec> OMXCodec::Create(
         const sp<IOMX> &omx,
@@ -180,6 +191,7 @@
 
         status_t err = omx->allocate_node(componentName, &node);
         if (err == OK) {
+            LOGV("Successfully allocated OMX node '%s'", componentName);
             break;
         }
     }
@@ -301,7 +313,7 @@
     if (!strcasecmp("audio/3gpp", mime)) {
         codec->setAMRFormat();
     }
-    if (!createEncoder && !strcasecmp("audio/mp4a-latm", mime)) {
+    if (!strcasecmp("audio/mp4a-latm", mime)) {
         int32_t numChannels, sampleRate;
         CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
         CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
@@ -334,7 +346,7 @@
 
         int32_t compressedSize;
         success = success && meta->findInt32(
-                kKeyCompressedSize, &compressedSize);
+                kKeyMaxInputSize, &compressedSize);
 
         CHECK(success);
         CHECK(compressedSize > 0);
@@ -343,19 +355,46 @@
         codec->setJPEGInputFormat(width, height, (OMX_U32)compressedSize);
     }
 
+    int32_t maxInputSize;
+    if (createEncoder && meta->findInt32(kKeyMaxInputSize, &maxInputSize)) {
+        codec->setMinBufferSize(kPortIndexInput, (OMX_U32)maxInputSize);
+    }
+
+    if (!strcmp(componentName, "OMX.TI.AMR.encode")
+        || !strcmp(componentName, "OMX.TI.WBAMR.encode")) {
+        codec->setMinBufferSize(kPortIndexOutput, 8192);  // XXX
+    }
+
     codec->initOutputFormat(meta);
 
     return codec;
 }
 
+void OMXCodec::setMinBufferSize(OMX_U32 portIndex, OMX_U32 size) {
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+    def.nPortIndex = portIndex;
+
+    status_t err = mOMX->get_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+
+    if (def.nBufferSize < size) {
+        def.nBufferSize = size;
+
+    }
+
+    err = mOMX->set_parameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+}
+
 status_t OMXCodec::setVideoPortFormatType(
         OMX_U32 portIndex,
         OMX_VIDEO_CODINGTYPE compressionFormat,
         OMX_COLOR_FORMATTYPE colorFormat) {
     OMX_VIDEO_PARAM_PORTFORMATTYPE format;
-    format.nSize = sizeof(format);
-    format.nVersion.s.nVersionMajor = 1;
-    format.nVersion.s.nVersionMinor = 1;
+    InitOMXParams(&format);
     format.nPortIndex = portIndex;
     format.nIndex = 0;
     bool found = false;
@@ -447,13 +486,11 @@
             kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused);
 
     OMX_PARAM_PORTDEFINITIONTYPE def;
-    OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
-
-    def.nSize = sizeof(def);
-    def.nVersion.s.nVersionMajor = 1;
-    def.nVersion.s.nVersionMinor = 1;
+    InitOMXParams(&def);
     def.nPortIndex = kPortIndexOutput;
 
+    OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+
     status_t err = mOMX->get_parameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
 
@@ -472,9 +509,7 @@
 
     ////////////////////////////////////////////////////////////////////////////
 
-    def.nSize = sizeof(def);
-    def.nVersion.s.nVersionMajor = 1;
-    def.nVersion.s.nVersionMinor = 1;
+    InitOMXParams(&def);
     def.nPortIndex = kPortIndexInput;
 
     err = mOMX->get_parameter(
@@ -482,7 +517,7 @@
     CHECK_EQ(err, OK);
 
     def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
-    LOGI("setting nBufferSize = %ld", def.nBufferSize);
+    LOGI("Setting nBufferSize = %ld", def.nBufferSize);
 
     CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
 
@@ -500,37 +535,6 @@
         const char *mime, OMX_U32 width, OMX_U32 height) {
     LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
 
-    // Enabling this code appears to be the right thing(tm), but,...
-    // the TI decoder then loses the ability to output YUV420 and only outputs
-    // YCbYCr (16bit)
-
-#if 1
-    if (!strcmp("OMX.TI.Video.Decoder", mComponentName)) {
-        OMX_PARAM_COMPONENTROLETYPE role;
-        role.nSize = sizeof(role);
-        role.nVersion.s.nVersionMajor = 1;
-        role.nVersion.s.nVersionMinor = 1;
-
-        if (!strcasecmp("video/avc", mime)) {
-            strncpy((char *)role.cRole, "video_decoder.avc",
-                    OMX_MAX_STRINGNAME_SIZE - 1);
-        } else if (!strcasecmp("video/mp4v-es", mime)) {
-            strncpy((char *)role.cRole, "video_decoder.mpeg4",
-                    OMX_MAX_STRINGNAME_SIZE - 1);
-        } else if (!strcasecmp("video/3gpp", mime)) {
-            strncpy((char *)role.cRole, "video_decoder.h263",
-                    OMX_MAX_STRINGNAME_SIZE - 1);
-        }
-
-        role.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
-
-        status_t err = mOMX->set_parameter(
-                mNode, OMX_IndexParamStandardComponentRole,
-                &role, sizeof(role));
-        CHECK_EQ(err, OK);
-    }
-#endif
-
     OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
     if (!strcasecmp("video/avc", mime)) {
         compressionFormat = OMX_VIDEO_CodingAVC;
@@ -549,9 +553,7 @@
 #if 1
     {
         OMX_VIDEO_PARAM_PORTFORMATTYPE format;
-        format.nSize = sizeof(format);
-        format.nVersion.s.nVersionMajor = 1;
-        format.nVersion.s.nVersionMinor = 1;
+        InitOMXParams(&format);
         format.nPortIndex = kPortIndexOutput;
         format.nIndex = 0;
 
@@ -576,13 +578,11 @@
 #endif
 
     OMX_PARAM_PORTDEFINITIONTYPE def;
-    OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
-
-    def.nSize = sizeof(def);
-    def.nVersion.s.nVersionMajor = 1;
-    def.nVersion.s.nVersionMinor = 1;
+    InitOMXParams(&def);
     def.nPortIndex = kPortIndexInput;
 
+    OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+
     status_t err = mOMX->get_parameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
 
@@ -609,9 +609,7 @@
 
     ////////////////////////////////////////////////////////////////////////////
 
-    def.nSize = sizeof(def);
-    def.nVersion.s.nVersionMajor = 1;
-    def.nVersion.s.nVersionMinor = 1;
+    InitOMXParams(&def);
     def.nPortIndex = kPortIndexOutput;
 
     err = mOMX->get_parameter(
@@ -657,6 +655,63 @@
 
     mObserver = new OMXCodecObserver(this);
     mOMX->observe_node(mNode, mObserver);
+
+    setComponentRole();
+}
+
+void OMXCodec::setComponentRole() {
+    struct MimeToRole {
+        const char *mime;
+        const char *decoderRole;
+        const char *encoderRole;
+    };
+
+    static const MimeToRole kMimeToRole[] = {
+        { "audio/mpeg", "audio_decoder.mp3", "audio_encoder.mp3" },
+        { "audio/3gpp", "audio_decoder.amrnb", "audio_encoder.amrnb" },
+        { "audio/mp4a-latm", "audio_decoder.aac", "audio_encoder.aac" },
+        { "video/avc",  "video_decoder.avc", "video_encoder.avc" },
+        { "video/mp4v-es", "video_decoder.mpeg4", "video_encoder.mpeg4" },
+        { "video/3gpp", "video_decoder.h263", "video_encoder.h263" },
+    };
+
+    static const size_t kNumMimeToRole =
+        sizeof(kMimeToRole) / sizeof(kMimeToRole[0]);
+
+    size_t i;
+    for (i = 0; i < kNumMimeToRole; ++i) {
+        if (!strcasecmp(mMIME, kMimeToRole[i].mime)) {
+            break;
+        }
+    }
+
+    if (i == kNumMimeToRole) {
+        return;
+    }
+
+    const char *role =
+        mIsEncoder ? kMimeToRole[i].encoderRole
+                   : kMimeToRole[i].decoderRole;
+
+    if (role != NULL) {
+        CODEC_LOGV("Setting component role '%s'.", role);
+
+        OMX_PARAM_COMPONENTROLETYPE roleParams;
+        InitOMXParams(&roleParams);
+
+        strncpy((char *)roleParams.cRole,
+                role, OMX_MAX_STRINGNAME_SIZE - 1);
+
+        roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
+
+        status_t err = mOMX->set_parameter(
+                mNode, OMX_IndexParamStandardComponentRole,
+                &roleParams, sizeof(roleParams));
+
+        if (err != OK) {
+            LOGW("Failed to set standard component role '%s'.", role);
+        }
+    }
 }
 
 OMXCodec::~OMXCodec() {
@@ -689,7 +744,6 @@
     if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
         err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
         CHECK_EQ(err, OK);
-
         setState(LOADED_TO_IDLE);
     }
 
@@ -731,11 +785,7 @@
 
 status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
     OMX_PARAM_PORTDEFINITIONTYPE def;
-    def.nSize = sizeof(def);
-    def.nVersion.s.nVersionMajor = 1;
-    def.nVersion.s.nVersionMinor = 1;
-    def.nVersion.s.nRevision = 0;
-    def.nVersion.s.nStep = 0;
+    InitOMXParams(&def);
     def.nPortIndex = portIndex;
 
     status_t err = mOMX->get_parameter(
@@ -783,7 +833,7 @@
 
         mPortBuffers[portIndex].push(info);
 
-        LOGV("allocated buffer %p on %s port", buffer,
+        CODEC_LOGV("allocated buffer %p on %s port", buffer,
              portIndex == kPortIndexInput ? "input" : "output");
     }
 
@@ -809,7 +859,7 @@
         {
             IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
 
-            LOGV("EMPTY_BUFFER_DONE(buffer: %p)", buffer);
+            CODEC_LOGV("EMPTY_BUFFER_DONE(buffer: %p)", buffer);
 
             Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
             size_t i = 0;
@@ -826,7 +876,7 @@
             buffers->editItemAt(i).mOwnedByComponent = false;
 
             if (mPortStatus[kPortIndexInput] == DISABLING) {
-                LOGV("Port is disabled, freeing buffer %p", buffer);
+                CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
 
                 status_t err =
                     mOMX->free_buffer(mNode, kPortIndexInput, buffer);
@@ -846,12 +896,12 @@
             IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer;
             OMX_U32 flags = msg.u.extended_buffer_data.flags;
 
-            LOGV("FILL_BUFFER_DONE(buffer: %p, size: %ld, flags: 0x%08lx)",
+            CODEC_LOGV("FILL_BUFFER_DONE(buffer: %p, size: %ld, flags: 0x%08lx)",
                  buffer,
                  msg.u.extended_buffer_data.range_length,
                  flags);
 
-            LOGV("FILL_BUFFER_DONE(timestamp: %lld us (%.2f secs))",
+            CODEC_LOGV("FILL_BUFFER_DONE(timestamp: %lld us (%.2f secs))",
                  msg.u.extended_buffer_data.timestamp,
                  msg.u.extended_buffer_data.timestamp / 1E6);
 
@@ -872,7 +922,7 @@
             info->mOwnedByComponent = false;
 
             if (mPortStatus[kPortIndexOutput] == DISABLING) {
-                LOGV("Port is disabled, freeing buffer %p", buffer);
+                CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
 
                 status_t err =
                     mOMX->free_buffer(mNode, kPortIndexOutput, buffer);
@@ -881,7 +931,7 @@
                 buffers->removeAt(i);
             } else if (mPortStatus[kPortIndexOutput] == ENABLED
                        && (flags & OMX_BUFFERFLAG_EOS)) {
-                LOGV("No more output data.");
+                CODEC_LOGV("No more output data.");
                 mNoMoreOutputData = true;
                 mBufferFilled.signal();
             } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) {
@@ -953,7 +1003,7 @@
 
         case OMX_EventBufferFlag:
         {
-            LOGV("EVENT_BUFFER_FLAG(%ld)", data1);
+            CODEC_LOGV("EVENT_BUFFER_FLAG(%ld)", data1);
 
             if (data1 == kPortIndexOutput) {
                 mNoMoreOutputData = true;
@@ -963,7 +1013,7 @@
 
         default:
         {
-            LOGV("EVENT(%d, %ld, %ld)", event, data1, data2);
+            CODEC_LOGV("EVENT(%d, %ld, %ld)", event, data1, data2);
             break;
         }
     }
@@ -980,7 +1030,7 @@
         case OMX_CommandPortDisable:
         {
             OMX_U32 portIndex = data;
-            LOGV("PORT_DISABLED(%ld)", portIndex);
+            CODEC_LOGV("PORT_DISABLED(%ld)", portIndex);
 
             CHECK(mState == EXECUTING || mState == RECONFIGURING);
             CHECK_EQ(mPortStatus[portIndex], DISABLING);
@@ -1002,7 +1052,7 @@
         case OMX_CommandPortEnable:
         {
             OMX_U32 portIndex = data;
-            LOGV("PORT_ENABLED(%ld)", portIndex);
+            CODEC_LOGV("PORT_ENABLED(%ld)", portIndex);
 
             CHECK(mState == EXECUTING || mState == RECONFIGURING);
             CHECK_EQ(mPortStatus[portIndex], ENABLING);
@@ -1023,7 +1073,7 @@
         {
             OMX_U32 portIndex = data;
 
-            LOGV("FLUSH_DONE(%ld)", portIndex);
+            CODEC_LOGV("FLUSH_DONE(%ld)", portIndex);
 
             CHECK_EQ(mPortStatus[portIndex], SHUTTING_DOWN);
             mPortStatus[portIndex] = ENABLED;
@@ -1038,7 +1088,7 @@
             } else if (mState == EXECUTING_TO_IDLE) {
                 if (mPortStatus[kPortIndexInput] == ENABLED
                     && mPortStatus[kPortIndexOutput] == ENABLED) {
-                    LOGV("Finished flushing both ports, now completing "
+                    CODEC_LOGV("Finished flushing both ports, now completing "
                          "transition from EXECUTING to IDLE.");
 
                     mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
@@ -1053,7 +1103,7 @@
 
                 if (mPortStatus[kPortIndexInput] == ENABLED
                     && mPortStatus[kPortIndexOutput] == ENABLED) {
-                    LOGV("Finished flushing both ports, now continuing from"
+                    CODEC_LOGV("Finished flushing both ports, now continuing from"
                          " seek-time.");
 
                     drainInputBuffers();
@@ -1066,7 +1116,7 @@
 
         default:
         {
-            LOGV("CMD_COMPLETE(%d, %ld)", cmd, data);
+            CODEC_LOGV("CMD_COMPLETE(%d, %ld)", cmd, data);
             break;
         }
     }
@@ -1076,7 +1126,7 @@
     switch (newState) {
         case OMX_StateIdle:
         {
-            LOGV("Now Idle.");
+            CODEC_LOGV("Now Idle.");
             if (mState == LOADED_TO_IDLE) {
                 status_t err = mOMX->send_command(
                         mNode, OMX_CommandStateSet, OMX_StateExecuting);
@@ -1118,7 +1168,7 @@
         {
             CHECK_EQ(mState, IDLE_TO_EXECUTING);
 
-            LOGV("Now Executing.");
+            CODEC_LOGV("Now Executing.");
 
             setState(EXECUTING);
 
@@ -1134,7 +1184,7 @@
         {
             CHECK_EQ(mState, IDLE_TO_LOADED);
 
-            LOGV("Now Loaded.");
+            CODEC_LOGV("Now Loaded.");
 
             setState(LOADED);
             break;
@@ -1200,7 +1250,7 @@
 }
 
 void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) {
-    LOGV("PORT_SETTINGS_CHANGED(%ld)", portIndex);
+    CODEC_LOGV("PORT_SETTINGS_CHANGED(%ld)", portIndex);
 
     CHECK_EQ(mState, EXECUTING);
     CHECK_EQ(portIndex, kPortIndexOutput);
@@ -1219,7 +1269,7 @@
     CHECK(mState == EXECUTING || mState == RECONFIGURING
             || mState == EXECUTING_TO_IDLE);
 
-    LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.",
+    CODEC_LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.",
          portIndex, countBuffersWeOwn(mPortBuffers[portIndex]),
          mPortBuffers[portIndex].size());
 
@@ -1342,7 +1392,7 @@
     size_t srcLength = 0;
 
     if (err != OK) {
-        LOGV("signalling end of input stream.");
+        CODEC_LOGV("signalling end of input stream.");
         flags |= OMX_BUFFERFLAG_EOS;
 
         mSignalledEOS = true;
@@ -1363,9 +1413,9 @@
             && srcBuffer->meta_data()->findInt32(kKeyTimeScale, &scale)) {
             timestamp = ((OMX_TICKS)units * 1000000) / scale;
 
-            LOGV("Calling empty_buffer on buffer %p (length %d)",
+            CODEC_LOGV("Calling empty_buffer on buffer %p (length %d)",
                  info->mBuffer, srcLength);
-            LOGV("Calling empty_buffer with timestamp %lld us (%.2f secs)",
+            CODEC_LOGV("Calling empty_buffer with timestamp %lld us (%.2f secs)",
                  timestamp, timestamp / 1E6);
         }
     }
@@ -1386,12 +1436,12 @@
     CHECK_EQ(info->mOwnedByComponent, false);
 
     if (mNoMoreOutputData) {
-        LOGV("There is no more output data available, not "
+        CODEC_LOGV("There is no more output data available, not "
              "calling fillOutputBuffer");
         return;
     }
 
-    LOGV("Calling fill_buffer on buffer %p", info->mBuffer);
+    CODEC_LOGV("Calling fill_buffer on buffer %p", info->mBuffer);
     mOMX->fill_buffer(mNode, info->mBuffer);
 
     info->mOwnedByComponent = true;
@@ -1430,12 +1480,43 @@
     mBufferFilled.signal();
 }
 
+void OMXCodec::setRawAudioFormat(
+        OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) {
+    OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
+    InitOMXParams(&pcmParams);
+    pcmParams.nPortIndex = portIndex;
+
+    status_t err = mOMX->get_parameter(
+            mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
+
+    CHECK_EQ(err, OK);
+
+    pcmParams.nChannels = numChannels;
+    pcmParams.eNumData = OMX_NumericalDataSigned;
+    pcmParams.bInterleaved = OMX_TRUE;
+    pcmParams.nBitPerSample = 16;
+    pcmParams.nSamplingRate = sampleRate;
+    pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
+
+    if (numChannels == 1) {
+        pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
+    } else {
+        CHECK_EQ(numChannels, 2);
+
+        pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+        pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+    }
+
+    err = mOMX->set_parameter(
+            mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
+
+    CHECK_EQ(err, OK);
+}
+
 void OMXCodec::setAMRFormat() {
     if (!mIsEncoder) {
         OMX_AUDIO_PARAM_AMRTYPE def;
-        def.nSize = sizeof(def);
-        def.nVersion.s.nVersionMajor = 1;
-        def.nVersion.s.nVersionMinor = 1;
+        InitOMXParams(&def);
         def.nPortIndex = kPortIndexInput;
 
         status_t err =
@@ -1459,62 +1540,35 @@
         CHECK(format->findInt32(kKeySampleRate, &sampleRate));
         CHECK(format->findInt32(kKeyChannelCount, &numChannels));
 
-        OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
-        pcmParams.nSize = sizeof(pcmParams);
-        pcmParams.nVersion.s.nVersionMajor = 1;
-        pcmParams.nVersion.s.nVersionMinor = 1;
-        pcmParams.nPortIndex = kPortIndexInput;
-
-        status_t err = mOMX->get_parameter(
-                mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
-
-        CHECK_EQ(err, OK);
-
-        pcmParams.nChannels = numChannels;
-        pcmParams.eNumData = OMX_NumericalDataSigned;
-        pcmParams.bInterleaved = OMX_TRUE;
-        pcmParams.nBitPerSample = 16;
-        pcmParams.nSamplingRate = sampleRate;
-        pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
-
-        if (numChannels == 1) {
-            pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
-        } else {
-            CHECK_EQ(numChannels, 2);
-
-            pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
-            pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
-        }
-
-        err = mOMX->set_parameter(
-                mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
-
-        CHECK_EQ(err, OK);
+        setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
     }
 }
 
 void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate) {
-    OMX_AUDIO_PARAM_AACPROFILETYPE profile;
-    profile.nSize = sizeof(profile);
-    profile.nVersion.s.nVersionMajor = 1;
-    profile.nVersion.s.nVersionMinor = 1;
-    profile.nPortIndex = kPortIndexInput;
+    if (mIsEncoder) {
+        setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
+    } else {
+        OMX_AUDIO_PARAM_AACPROFILETYPE profile;
+        InitOMXParams(&profile);
+        profile.nPortIndex = kPortIndexInput;
 
-    status_t err =
-        mOMX->get_parameter(mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
-    CHECK_EQ(err, OK);
+        status_t err = mOMX->get_parameter(
+                mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
+        CHECK_EQ(err, OK);
 
-    profile.nChannels = numChannels;
-    profile.nSampleRate = sampleRate;
-    profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
+        profile.nChannels = numChannels;
+        profile.nSampleRate = sampleRate;
+        profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
 
-    err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
-    CHECK_EQ(err, OK);
+        err = mOMX->set_parameter(
+                mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
+        CHECK_EQ(err, OK);
+    }
 }
 
 void OMXCodec::setImageOutputFormat(
         OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height) {
-    LOGV("setImageOutputFormat(%ld, %ld)", width, height);
+    CODEC_LOGV("setImageOutputFormat(%ld, %ld)", width, height);
 
 #if 0
     OMX_INDEXTYPE index;
@@ -1527,9 +1581,7 @@
 #endif
 
     OMX_PARAM_PORTDEFINITIONTYPE def;
-    def.nSize = sizeof(def);
-    def.nVersion.s.nVersionMajor = 1;
-    def.nVersion.s.nVersionMinor = 1;
+    InitOMXParams(&def);
     def.nPortIndex = kPortIndexOutput;
 
     status_t err = mOMX->get_parameter(
@@ -1580,9 +1632,7 @@
 void OMXCodec::setJPEGInputFormat(
         OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize) {
     OMX_PARAM_PORTDEFINITIONTYPE def;
-    def.nSize = sizeof(def);
-    def.nVersion.s.nVersionMajor = 1;
-    def.nVersion.s.nVersionMinor = 1;
+    InitOMXParams(&def);
     def.nPortIndex = kPortIndexInput;
 
     status_t err = mOMX->get_parameter(
@@ -1650,7 +1700,7 @@
 }
 
 status_t OMXCodec::stop() {
-    LOGV("stop");
+    CODEC_LOGV("stop");
 
     Mutex::Autolock autoLock(mLock);
 
@@ -1668,7 +1718,7 @@
             setState(EXECUTING_TO_IDLE);
 
             if (mQuirks & kRequiresFlushBeforeShutdown) {
-                LOGV("This component requires a flush before transitioning "
+                CODEC_LOGV("This component requires a flush before transitioning "
                      "from EXECUTING to IDLE...");
 
                 bool emulateInputFlushCompletion =
@@ -1740,7 +1790,7 @@
 
     int64_t seekTimeUs;
     if (options && options->getSeekTo(&seekTimeUs)) {
-        LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
+        CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
 
         mSignalledEOS = false;
         mNoMoreOutputData = false;
@@ -1969,9 +2019,7 @@
 
 void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
     OMX_PARAM_PORTDEFINITIONTYPE def;
-    def.nSize = sizeof(def);
-    def.nVersion.s.nVersionMajor = 1;
-    def.nVersion.s.nVersionMinor = 1;
+    InitOMXParams(&def);
     def.nPortIndex = portIndex;
 
     status_t err = mOMX->get_parameter(
@@ -2037,9 +2085,7 @@
 
             if (audioDef->eEncoding == OMX_AUDIO_CodingPCM) {
                 OMX_AUDIO_PARAM_PCMMODETYPE params;
-                params.nSize = sizeof(params);
-                params.nVersion.s.nVersionMajor = 1;
-                params.nVersion.s.nVersionMinor = 1;
+                InitOMXParams(&params);
                 params.nPortIndex = portIndex;
 
                 err = mOMX->get_parameter(
@@ -2076,9 +2122,7 @@
     mOutputFormat->setCString(kKeyDecoderComponent, mComponentName);
 
     OMX_PARAM_PORTDEFINITIONTYPE def;
-    def.nSize = sizeof(def);
-    def.nVersion.s.nVersionMajor = 1;
-    def.nVersion.s.nVersionMinor = 1;
+    InitOMXParams(&def);
     def.nPortIndex = kPortIndexOutput;
 
     status_t err = mOMX->get_parameter(
@@ -2102,40 +2146,44 @@
         {
             OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio;
 
-            CHECK_EQ(audio_def->eEncoding, OMX_AUDIO_CodingPCM);
+            if (audio_def->eEncoding == OMX_AUDIO_CodingPCM) {
+                OMX_AUDIO_PARAM_PCMMODETYPE params;
+                InitOMXParams(&params);
+                params.nPortIndex = kPortIndexOutput;
 
-            OMX_AUDIO_PARAM_PCMMODETYPE params;
-            params.nSize = sizeof(params);
-            params.nVersion.s.nVersionMajor = 1;
-            params.nVersion.s.nVersionMinor = 1;
-            params.nPortIndex = kPortIndexOutput;
+                err = mOMX->get_parameter(
+                        mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
+                CHECK_EQ(err, OK);
 
-            err = mOMX->get_parameter(
-                    mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
-            CHECK_EQ(err, OK);
+                CHECK_EQ(params.eNumData, OMX_NumericalDataSigned);
+                CHECK_EQ(params.nBitPerSample, 16);
+                CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear);
 
-            CHECK_EQ(params.eNumData, OMX_NumericalDataSigned);
-            CHECK_EQ(params.nBitPerSample, 16);
-            CHECK_EQ(params.ePCMMode, OMX_AUDIO_PCMModeLinear);
+                int32_t numChannels, sampleRate;
+                inputFormat->findInt32(kKeyChannelCount, &numChannels);
+                inputFormat->findInt32(kKeySampleRate, &sampleRate);
 
-            int32_t numChannels, sampleRate;
-            inputFormat->findInt32(kKeyChannelCount, &numChannels);
-            inputFormat->findInt32(kKeySampleRate, &sampleRate);
+                if ((OMX_U32)numChannels != params.nChannels) {
+                    LOGW("Codec outputs a different number of channels than "
+                         "the input stream contains.");
+                }
 
-            if ((OMX_U32)numChannels != params.nChannels) {
-                LOGW("Codec outputs a different number of channels than "
-                     "the input stream contains.");
+                mOutputFormat->setCString(kKeyMIMEType, "audio/raw");
+
+                // Use the codec-advertised number of channels, as some
+                // codecs appear to output stereo even if the input data is
+                // mono.
+                mOutputFormat->setInt32(kKeyChannelCount, params.nChannels);
+
+                // The codec-reported sampleRate is not reliable...
+                mOutputFormat->setInt32(kKeySampleRate, sampleRate);
+            } else if (audio_def->eEncoding == OMX_AUDIO_CodingAMR) {
+                mOutputFormat->setCString(kKeyMIMEType, "audio/3gpp");
+            } else if (audio_def->eEncoding == OMX_AUDIO_CodingAAC) {
+                mOutputFormat->setCString(kKeyMIMEType, "audio/mp4a-latm");
+            } else {
+                CHECK(!"Should not be here. Unknown audio encoding.");
             }
-
-            mOutputFormat->setCString(kKeyMIMEType, "audio/raw");
-
-            // Use the codec-advertised number of channels, as some
-            // codecs appear to output stereo even if the input data is
-            // mono.
-            mOutputFormat->setInt32(kKeyChannelCount, params.nChannels);
-
-            // The codec-reported sampleRate is not reliable...
-            mOutputFormat->setInt32(kKeySampleRate, sampleRate);
             break;
         }
 
diff --git a/telephony/java/com/android/internal/telephony/IccRecords.java b/telephony/java/com/android/internal/telephony/IccRecords.java
index ea24c25..b8d9e3c 100644
--- a/telephony/java/com/android/internal/telephony/IccRecords.java
+++ b/telephony/java/com/android/internal/telephony/IccRecords.java
@@ -31,7 +31,7 @@
 public abstract class IccRecords extends Handler implements IccConstants {
 
     protected static final boolean DBG = true;
-    //***** Instance Variables
+    // ***** Instance Variables
 
     protected PhoneBase phone;
     protected RegistrantList recordsLoadedRegistrants = new RegistrantList();
@@ -40,7 +40,7 @@
 
     protected AdnRecordCache adnCache;
 
-    //***** Cached SIM State; cleared on channel close
+    // ***** Cached SIM State; cleared on channel close
 
     protected boolean recordsRequested = false; // true if we've made requests for the sim records
 
@@ -54,23 +54,26 @@
     protected boolean isVoiceMailFixed = false;
     protected int countVoiceMessages = 0;
 
-    protected int mncLength = 0;   // 0 is used to indicate that the value
-                         // is not initialized
+    protected int mncLength = UNINITIALIZED;
     protected int mailboxIndex = 0; // 0 is no mailbox dailing number associated
 
     protected String spn;
     protected int spnDisplayCondition;
 
-    //***** Constants
+    // ***** Constants
+
+    // Markers for mncLength
+    protected static final int UNINITIALIZED = -1;
+    protected static final int UNKNOWN = 0;
 
     // Bitmasks for SPN display rules.
     protected static final int SPN_RULE_SHOW_SPN  = 0x01;
     protected static final int SPN_RULE_SHOW_PLMN = 0x02;
 
-    //***** Event Constants
+    // ***** Event Constants
     protected static final int EVENT_SET_MSISDN_DONE = 30;
 
-    //***** Constructor
+    // ***** Constructor
 
     public IccRecords(PhoneBase p) {
         this.phone = p;
@@ -234,4 +237,3 @@
 
     protected abstract void log(String s);
 }
-
diff --git a/telephony/java/com/android/internal/telephony/gsm/MccTable.java b/telephony/java/com/android/internal/telephony/MccTable.java
similarity index 84%
rename from telephony/java/com/android/internal/telephony/gsm/MccTable.java
rename to telephony/java/com/android/internal/telephony/MccTable.java
index 9343f44..0d11f8c 100644
--- a/telephony/java/com/android/internal/telephony/gsm/MccTable.java
+++ b/telephony/java/com/android/internal/telephony/MccTable.java
@@ -14,7 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.internal.telephony.gsm;
+package com.android.internal.telephony;
+
+import android.app.ActivityManagerNative;
+import android.app.AlarmManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.net.wifi.WifiManager;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.provider.Settings;
+import android.util.Log;
 
 import java.util.Arrays;
 
@@ -475,8 +485,10 @@
         0x65630400, 0x67660400, 0x70790400, 0x73720400, 0x75790400, 0x666b0400
     };
 
+    static final String LOG_TAG = "MccTable";
+
     /**
-     * Given a GSM Mobile Country Code, returns a default time zone ID
+     * Given a Mobile Country Code, returns a default time zone ID
      * if available.  Returns null if unavailable.
      */
     public static String defaultTimeZoneForMcc(int mcc) {
@@ -494,7 +506,7 @@
     }
 
     /**
-     * Given a GSM Mobile Country Code, returns an ISO two-character
+     * Given a Mobile Country Code, returns an ISO two-character
      * country code if available.  Returns "" if unavailable.
      */
     public static String countryCodeForMcc(int mcc) {
@@ -553,4 +565,95 @@
         return wifi;
     }
 
+    /**
+     * Updates MCC and MNC device configuration information for application retrieving
+     * correct version of resources.  If either MCC or MNC is 0, they will be ignored (not set).
+     * @param phone PhoneBae to act on.
+     * @param mccmnc truncated imsi with just the MCC and MNC - MNC assumed to be from 4th to end
+     */
+    public static void updateMccMncConfiguration(PhoneBase phone, String mccmnc) {
+        Configuration config = new Configuration();
+        int mcc, mnc;
+
+        try {
+            mcc = Integer.parseInt(mccmnc.substring(0,3));
+            mnc = Integer.parseInt(mccmnc.substring(3));
+        } catch (NumberFormatException e) {
+            Log.e(LOG_TAG, "Error parsing IMSI");
+            return;
+        }
+
+        Log.d(LOG_TAG, "updateMccMncConfiguration: mcc=" + mcc + ", mnc=" + mnc);
+
+        if (mcc != 0) {
+            config.mcc = mcc;
+            setTimezoneFromMccIfNeeded(phone, mcc);
+            setLocaleFromMccIfNeeded(phone, mcc);
+            setWifiChannelsFromMccIfNeeded(phone, mcc);
+        }
+        if (mnc != 0) {
+            config.mnc = mnc;
+        }
+        try {
+            ActivityManagerNative.getDefault().updateConfiguration(config);
+        } catch (RemoteException e) {
+            Log.e(LOG_TAG, "Can't update configuration", e);
+        }
+    }
+
+    /**
+     * If the timezone is not already set, set it based on the MCC of the SIM.
+     * @param phone PhoneBase to act on (get context from).
+     * @param mcc Mobile Country Code of the SIM or SIM-like entity (build prop on CDMA)
+     */
+    private static void setTimezoneFromMccIfNeeded(PhoneBase phone, int mcc) {
+        String timezone = SystemProperties.get(ServiceStateTracker.TIMEZONE_PROPERTY);
+        if (timezone == null || timezone.length() == 0) {
+            String zoneId = defaultTimeZoneForMcc(mcc);
+            if (zoneId != null && zoneId.length() > 0) {
+                Context context = phone.getContext();
+                // Set time zone based on MCC
+                AlarmManager alarm =
+                        (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+                alarm.setTimeZone(zoneId);
+                Log.d(LOG_TAG, "timezone set to "+zoneId);
+            }
+        }
+    }
+
+    /**
+     * If the locale is not already set, set it based on the MCC of the SIM.
+     * @param phone PhoneBase to act on.
+     * @param mcc Mobile Country Code of the SIM or SIM-like entity (build prop on CDMA)
+     */
+    private static void setLocaleFromMccIfNeeded(PhoneBase phone, int mcc) {
+        String language = MccTable.defaultLanguageForMcc(mcc);
+        String country = MccTable.countryCodeForMcc(mcc);
+
+        Log.d(LOG_TAG, "locale set to "+language+"_"+country);
+        phone.setSystemLocale(language, country);
+    }
+
+    /**
+     * If the number of allowed wifi channels has not been set, set it based on
+     * the MCC of the SIM.
+     * @param phone PhoneBase to act on (get context from).
+     * @param mcc Mobile Country Code of the SIM or SIM-like entity (build prop on CDMA)
+     */
+    private static void setWifiChannelsFromMccIfNeeded(PhoneBase phone, int mcc) {
+        int wifiChannels = MccTable.wifiChannelsForMcc(mcc);
+        if (wifiChannels != 0) {
+            Context context = phone.getContext();
+            // only set to this default if the user hasn't manually set it
+            try {
+                Settings.Secure.getInt(context.getContentResolver(),
+                        Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS);
+            } catch (Settings.SettingNotFoundException e) {
+                Log.d(LOG_TAG, "WIFI_NUM_ALLOWED_CHANNESL set to " + wifiChannels);
+                WifiManager wM = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+                // don't persist
+                wM.setNumAllowedChannels(wifiChannels, false);
+            }
+        }
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 958e96d..ff06bc0 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -48,10 +48,7 @@
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.Connection;
 import com.android.internal.telephony.DataConnection;
-// TODO(Moto): need to move MccTable from telephony.gsm to telephony
-// since there is no difference between CDMA and GSM for MccTable and
-// CDMA uses gsm's MccTable is not good.
-import com.android.internal.telephony.gsm.MccTable;
+import com.android.internal.telephony.MccTable;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.IccException;
 import com.android.internal.telephony.IccFileHandler;
@@ -179,6 +176,10 @@
         // This is needed to handle phone process crashes
         String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
         mIsPhoneInEcmState = inEcm.equals("true");
+        if (mIsPhoneInEcmState) {
+            // Send a message which will invoke handleExitEmergencyCallbackMode
+            mCM.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE));
+        }
 
         // get the string that specifies the carrier OTA Sp number
         mCarrierOtaSpNumSchema = SystemProperties.get(
@@ -199,7 +200,7 @@
         updateCurrentCarrierInProvider(operatorNumeric);
 
         // Updates MCC MNC device configuration information
-        updateMccMncConfiguration(operatorNumeric);
+        MccTable.updateMccMncConfiguration(this, operatorNumeric);
 
 
         // Notify voicemails.
@@ -1011,7 +1012,6 @@
                     Log.d(LOG_TAG, "ERI read, notify registrants");
                     mEriFileLoadedRegistrants.notifyRegistrants();
                 }
-                setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE,"false");
             }
             break;
 
@@ -1403,21 +1403,4 @@
         return false;
     }
 
-    /**
-     * Updates MCC and MNC device configuration information for application retrieving
-     * correct version of resources
-     *
-     */
-    private void updateMccMncConfiguration(String operatorNumeric) {
-        if (operatorNumeric.length() >= 5) {
-            Configuration config = new Configuration();
-            config.mcc = Integer.parseInt(operatorNumeric.substring(0,3));
-            config.mnc = Integer.parseInt(operatorNumeric.substring(3));
-            try {
-                ActivityManagerNative.getDefault().updateConfiguration(config);
-            } catch (RemoteException e) {
-                Log.e(LOG_TAG, "Can't update configuration", e);
-            }
-        }
-    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index dab529e..46e360b 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -45,9 +45,8 @@
 import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.DataConnectionTracker;
-import com.android.internal.telephony.gsm.MccTable;
 import com.android.internal.telephony.IccCard;
-import com.android.internal.telephony.PhoneProxy;
+import com.android.internal.telephony.MccTable;
 import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.TelephonyEventLog;
 import com.android.internal.telephony.TelephonyIntents;
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
index 7c74314..b9ece8b 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
@@ -28,7 +28,7 @@
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.cdma.RuimCard;
-import com.android.internal.telephony.gsm.MccTable;
+import com.android.internal.telephony.MccTable;
 
 // can't be used since VoiceMailConstants is not public
 //import com.android.internal.telephony.gsm.VoiceMailConstants;
@@ -47,7 +47,7 @@
     private static final boolean DBG = true;
     private boolean  m_ota_commited=false;
 
-    //***** Instance Variables
+    // ***** Instance Variables
 
     private String mImsi;
     private String mMyMobileNumber;
@@ -55,7 +55,7 @@
 
     private String mPrlVersion;
 
-    //***** Event Constants
+    // ***** Event Constants
 
     private static final int EVENT_RUIM_READY = 1;
     private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 2;
@@ -109,7 +109,7 @@
     @Override
     protected void onRadioOffOrNotAvailable() {
         countVoiceMessages = 0;
-        mncLength = 0;
+        mncLength = UNINITIALIZED;
         iccid = null;
 
         adnCache.reset();
@@ -167,7 +167,7 @@
         }
 
         // TODO(Moto): mncLength is not set anywhere.
-        if (mncLength != 0) {
+        if (mncLength != UNINITIALIZED && mncLength != UNKNOWN) {
             // Length = length of MCC + length of MNC
             // TODO: change spec name
             // length of mcc = 3 (3GPP2 C.S0005 - Section 2.3)
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index a9be068..65463e5 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -49,6 +49,7 @@
 import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.DataConnectionTracker;
 import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.MccTable;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.TelephonyEventLog;
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index 4272faa..7f7855a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -19,13 +19,10 @@
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
-import android.app.AlarmManager;
 import android.content.Context;
-import android.net.wifi.WifiManager;
 import android.os.AsyncResult;
 import android.os.Message;
 import android.os.SystemProperties;
-import android.provider.Settings;
 import android.util.Log;
 
 import com.android.internal.telephony.AdnRecord;
@@ -37,6 +34,7 @@
 import com.android.internal.telephony.IccUtils;
 import com.android.internal.telephony.IccVmFixedException;
 import com.android.internal.telephony.IccVmNotSupportedException;
+import com.android.internal.telephony.MccTable;
 
 import java.util.ArrayList;
 
@@ -51,14 +49,14 @@
 
     private static final boolean DBG = true;
 
-    //***** Instance Variables
+    // ***** Instance Variables
 
     VoiceMailConstants mVmConfig;
 
 
     SpnOverride mSpnOverride;
 
-    //***** Cached SIM State; cleared on channel close
+    // ***** Cached SIM State; cleared on channel close
 
     String imsi;
     boolean callForwardingEnabled;
@@ -88,7 +86,7 @@
 
     String pnnHomeName = null;
 
-    //***** Constants
+    // ***** Constants
 
     // Bitmasks for SPN display rules.
     static final int SPN_RULE_SHOW_SPN  = 0x01;
@@ -113,7 +111,7 @@
     private static final int CPHS_SST_MBN_MASK = 0x30;
     private static final int CPHS_SST_MBN_ENABLED = 0x30;
 
-    //***** Event Constants
+    // ***** Event Constants
 
     private static final int EVENT_SIM_READY = 1;
     private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 2;
@@ -143,9 +141,7 @@
     private static final int EVENT_SIM_REFRESH = 31;
     private static final int EVENT_GET_CFIS_DONE = 32;
 
-    private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
-
-    //***** Constructor
+    // ***** Constructor
 
     SIMRecords(GSMPhone p) {
         super(p);
@@ -188,7 +184,7 @@
         msisdn = null;
         voiceMailNum = null;
         countVoiceMessages = 0;
-        mncLength = 0;
+        mncLength = UNINITIALIZED;
         iccid = null;
         // -1 means no EF_SPN found; treat accordingly.
         spnDisplayCondition = -1;
@@ -453,79 +449,16 @@
      *  provided the SIM card. Returns null of SIM is not yet ready
      */
     String getSIMOperatorNumeric() {
-        if (imsi == null) {
+        if (imsi == null || mncLength == UNINITIALIZED || mncLength == UNKNOWN) {
             return null;
         }
 
-        if (mncLength != 0) {
-            // Length = length of MCC + length of MNC
-            // length of mcc = 3 (TS 23.003 Section 2.2)
-            return imsi.substring(0, 3 + mncLength);
-        }
-
-        // Guess the MNC length based on the MCC if we don't
-        // have a valid value in ef[ad]
-
-        int mcc;
-
-        mcc = Integer.parseInt(imsi.substring(0,3));
-
-        return imsi.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc));
+        // Length = length of MCC + length of MNC
+        // length of mcc = 3 (TS 23.003 Section 2.2)
+        return imsi.substring(0, 3 + mncLength);
     }
 
-     /**
-     * If the timezone is not already set, set it based on the MCC of the SIM.
-     * @param mcc Mobile Country Code of the SIM
-     */
-    private void setTimezoneFromMccIfNeeded(int mcc) {
-        String timezone = SystemProperties.get(TIMEZONE_PROPERTY);
-        if (timezone == null || timezone.length() == 0) {
-            String zoneId = MccTable.defaultTimeZoneForMcc(mcc);
-
-            if (zoneId != null && zoneId.length() > 0) {
-                // Set time zone based on MCC
-                AlarmManager alarm =
-                    (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE);
-                alarm.setTimeZone(zoneId);
-            }
-        }
-    }
-
-    /**
-     * If the locale is not already set, set it based on the MCC of the SIM.
-     * @param mcc Mobile Country Code of the SIM
-     */
-    private void setLocaleFromMccIfNeeded(int mcc) {
-        String language = MccTable.defaultLanguageForMcc(mcc);
-        String country = MccTable.countryCodeForMcc(mcc);
-
-        phone.setSystemLocale(language, country);
-    }
-
-    /**
-     * If the number of allowed wifi channels has not been set, set it based on
-     * the MCC of the SIM.
-     * @param mcc Mobile Country Code of the SIM
-     */
-    private void setWifiChannelsFromMccIfNeeded(int mcc) {
-        int wifiChannels = MccTable.wifiChannelsForMcc(mcc);
-
-        if (wifiChannels != 0) {
-            Context context = phone.getContext();
-            // only set to this default if the user hasn't manually set it
-            try {
-                Settings.Secure.getInt(context.getContentResolver(),
-                        Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS);
-            } catch (Settings.SettingNotFoundException e) {
-                WifiManager wM = (WifiManager)
-                        context.getSystemService(Context.WIFI_SERVICE);
-                // don't persist
-                wM.setNumAllowedChannels(wifiChannels, false);
-            }
-        }
-    }
-
-    //***** Overridden from Handler
+    // ***** Overridden from Handler
     public void handleMessage(Message msg) {
         AsyncResult ar;
         AdnRecord adn;
@@ -564,14 +497,25 @@
                 }
 
                 Log.d(LOG_TAG, "IMSI: " + imsi.substring(0, 6) + "xxxxxxxxx");
-                ((GSMPhone) phone).mSimCard.updateImsiConfiguration(imsi);
+
+                if (mncLength == UNKNOWN) {
+                    // the SIM has told us all it knows, but it didn't know the mnc length.
+                    // guess using the mcc
+                    try {
+                        int mcc = Integer.parseInt(imsi.substring(0,3));
+                        mncLength = MccTable.smallestDigitsMccForMnc(mcc);
+                    } catch (NumberFormatException e) {
+                        mncLength = UNKNOWN;
+                        Log.e(LOG_TAG, "SIMRecords: Corrupt IMSI!");
+                    }
+                }
+
+                if (mncLength != UNKNOWN && mncLength != UNINITIALIZED) {
+                    // finally have both the imsi and the mncLength and can parse the imsi properly
+                    MccTable.updateMccMncConfiguration(phone, imsi.substring(0, 3 + mncLength));
+                }
                 ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
                         SimCard.INTENT_VALUE_ICC_IMSI, null);
-
-                int mcc = Integer.parseInt(imsi.substring(0, 3));
-                setTimezoneFromMccIfNeeded(mcc);
-                setLocaleFromMccIfNeeded(mcc);
-                setWifiChannelsFromMccIfNeeded(mcc);
             break;
 
             case EVENT_GET_MBI_DONE:
@@ -794,12 +738,25 @@
                 mncLength = (int)data[3] & 0xf;
 
                 if (mncLength == 0xf) {
-                    // Resetting mncLength to 0 to indicate that it is not
-                    // initialised
-                    mncLength = 0;
+                    if (imsi != null) {
+                        try {
+                            int mcc = Integer.parseInt(imsi.substring(0,3));
 
-                    Log.d(LOG_TAG, "SIMRecords: MNC length not present in EF_AD");
-                    break;
+                            mncLength = MccTable.smallestDigitsMccForMnc(mcc);
+                        } catch (NumberFormatException e) {
+                            mncLength = UNKNOWN;
+                            Log.e(LOG_TAG, "SIMRecords: Corrupt IMSI!");
+                        }
+                    } else {
+                        // Indicate we got this info, but it didn't contain the length.
+                        mncLength = UNKNOWN;
+
+                        Log.d(LOG_TAG, "SIMRecords: MNC length not present in EF_AD");
+                    }
+                }
+                if (imsi != null && mncLength != UNKNOWN) {
+                    // finally have both imsi and the length of the mnc and can parse it properly
+                    MccTable.updateMccMncConfiguration(phone, imsi.substring(0, 3 + mncLength));
                 }
 
             break;
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
index 6c56682..835cb29 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimCard.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
@@ -16,9 +16,6 @@
 
 package com.android.internal.telephony.gsm;
 
-import android.app.ActivityManagerNative;
-import android.content.res.Configuration;
-import android.os.RemoteException;
 import android.util.Log;
 
 import com.android.internal.telephony.IccCard;
@@ -50,20 +47,4 @@
         return ((GSMPhone)mPhone).mSIMRecords.getServiceProviderName();
     }
 
-    public void updateImsiConfiguration(String imsi) {
-        if (imsi.length() >= 6) {
-            Configuration config = new Configuration();
-            config.mcc = ((imsi.charAt(0)-'0')*100)
-                    + ((imsi.charAt(1)-'0')*10)
-                    + (imsi.charAt(2)-'0');
-            config.mnc = ((imsi.charAt(3)-'0')*100)
-                    + ((imsi.charAt(4)-'0')*10)
-                    + (imsi.charAt(5)-'0');
-            try {
-                ActivityManagerNative.getDefault().updateConfiguration(config);
-            } catch (RemoteException e) {
-                Log.e(mLogTag, "[SimCard] Remote Exception when updating imsi configuration");
-            }
-        }
-    }
 }
diff --git a/test-runner/android/test/IsolatedContext.java b/test-runner/android/test/IsolatedContext.java
index 4bd9528..5c66169 100644
--- a/test-runner/android/test/IsolatedContext.java
+++ b/test-runner/android/test/IsolatedContext.java
@@ -4,6 +4,7 @@
 
 import android.accounts.AccountManager;
 import android.accounts.OnAccountsUpdatedListener;
+import android.accounts.Account;
 import android.content.ContextWrapper;
 import android.content.ContentResolver;
 import android.content.Intent;
@@ -101,6 +102,10 @@
                 Handler handler, boolean updateImmediately) {
             // do nothing
         }
+
+        public Account[] getAccounts() {
+            return new Account[]{};
+        }
     }
     @Override
     public File getFilesDir() {
diff --git a/tests/AndroidTests/src/com/android/unit_tests/MccTableTest.java b/tests/AndroidTests/src/com/android/unit_tests/MccTableTest.java
index 875376a..b2f1ded 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/MccTableTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/MccTableTest.java
@@ -16,7 +16,7 @@
 
 package com.android.unit_tests;
 
-import com.android.internal.telephony.gsm.MccTable;
+import com.android.internal.telephony.MccTable;
 
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
diff --git a/tests/BrowserPowerTest/Android.mk b/tests/BrowserPowerTest/Android.mk
new file mode 100644
index 0000000..f2c07b3
--- /dev/null
+++ b/tests/BrowserPowerTest/Android.mk
@@ -0,0 +1,30 @@
+# Copyright 2008, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := BrowserPowerTests
+
+#LOCAL_INSTRUMENTATION_FOR := browserpowertest
+
+include $(BUILD_PACKAGE)
diff --git a/tests/BrowserPowerTest/AndroidManifest.xml b/tests/BrowserPowerTest/AndroidManifest.xml
new file mode 100644
index 0000000..43eeaad
--- /dev/null
+++ b/tests/BrowserPowerTest/AndroidManifest.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.browserpowertest">
+
+    <!-- We add an application tag here just so that we can indicate that
+         this package needs to link against the android.test library,
+         which is needed when building test cases. -->
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <activity android:name="PowerTestActivity" android:label="Power">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TEST" />
+            </intent-filter>
+        </activity>
+    </application>
+    <!--
+    This declares that this app uses the instrumentation test runner targeting
+    the package of browserpowertest. To run the tests use the command:
+    "adb shell am instrument -w com.android.browserpowertest/.PowerTestRunner"
+    -->
+    <instrumentation android:name=".PowerTestRunner"
+        android:targetPackage="com.android.browserpowertest"
+        android:label="Test runner for Browser Power Tests."
+    />
+
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.WRITE_SDCARD" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+</manifest>
diff --git a/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerMeasurement.java b/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerMeasurement.java
new file mode 100644
index 0000000..74ac865f
--- /dev/null
+++ b/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerMeasurement.java
@@ -0,0 +1,51 @@
+package com.android.browserpowertest;
+
+import android.content.Intent;
+import android.app.Instrumentation;
+import android.os.Handler;
+import android.os.Message;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+import junit.framework.*;
+
+public class PowerMeasurement extends ActivityInstrumentationTestCase2<PowerTestActivity> {
+
+    private static final String LOGTAG = "PowerMeasurement";
+    private static final String PKG_NAME = "com.android.browserpowertest";
+    private static final String TESTING_URL = "http://www.espn.com";
+    private static final int TIME_OUT = 2 * 60 * 1000;
+    private static final int DELAY = 0;
+
+    public PowerMeasurement() {
+        super(PKG_NAME, PowerTestActivity.class);
+    }
+
+    public void testPageLoad() throws Throwable {
+        Instrumentation mInst = getInstrumentation();
+        PowerTestActivity act = getActivity();
+
+        Intent intent = new Intent(mInst.getContext(), PowerTestActivity.class);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        long start = System.currentTimeMillis();
+        PowerTestActivity activity = (PowerTestActivity)mInst.startActivitySync(
+                intent);
+        activity.reset();
+        //send a message with the new URL
+        Handler handler = activity.getHandler();
+        Message msg = handler.obtainMessage(
+                PowerTestActivity.MSG_NAVIGATE, TIME_OUT, DELAY);
+        msg.getData().putString(PowerTestActivity.MSG_NAV_URL, TESTING_URL);
+        msg.getData().putBoolean(PowerTestActivity.MSG_NAV_LOGTIME, true);
+
+        handler.sendMessage(msg);
+        boolean timeoutFlag = activity.waitUntilDone();
+        long end = System.currentTimeMillis();
+        assertFalse(TESTING_URL + " failed to load", timeoutFlag);
+        boolean pageErrorFlag = activity.getPageError();
+        assertFalse(TESTING_URL + " is not available, either network is down or the server is down",
+                pageErrorFlag);
+        Log.v(LOGTAG, "Page is loaded in " + activity.getPageLoadTime() + " ms.");
+
+        activity.finish();
+    }
+}
diff --git a/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerTestActivity.java b/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerTestActivity.java
new file mode 100644
index 0000000..77e390b
--- /dev/null
+++ b/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerTestActivity.java
@@ -0,0 +1,253 @@
+package com.android.browserpowertest;
+
+import android.app.Activity;
+import android.app.ActivityThread;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.ViewGroup;
+import android.webkit.WebChromeClient;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.webkit.WebSettings.LayoutAlgorithm;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+
+public class PowerTestActivity extends Activity {
+
+    public static final String LOGTAG = "PowerTestActivity";
+    public static final String PARAM_URL = "URL";
+    public static final String PARAM_TIMEOUT = "Timeout";
+    public static final int RESULT_TIMEOUT = 0xDEAD;
+    public static final int MSG_TIMEOUT = 0xC001;
+    public static final int MSG_NAVIGATE = 0xC002;
+    public static final String MSG_NAV_URL = "url";
+    public static final String MSG_NAV_LOGTIME = "logtime";
+
+    private WebView webView;
+    private SimpleWebViewClient webViewClient;
+    private SimpleChromeClient chromeClient;
+    private Handler handler;
+    private boolean timeoutFlag;
+    private boolean logTime;
+    private boolean pageDone;
+    private Object pageDoneLock;
+    private int pageStartCount;
+    private int manualDelay;
+    private long startTime;
+    private long pageLoadTime;
+    private PageDoneRunner pageDoneRunner = new PageDoneRunner();
+
+    public PowerTestActivity() {
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Log.v(LOGTAG, "onCreate, inst=" + Integer.toHexString(hashCode()));
+
+        LinearLayout contentView = new LinearLayout(this);
+        contentView.setOrientation(LinearLayout.VERTICAL);
+        setContentView(contentView);
+        setTitle("Idle");
+
+        webView = new WebView(this);
+        webView.getSettings().setJavaScriptEnabled(true);
+        webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(false);
+        webView.getSettings().setLayoutAlgorithm(LayoutAlgorithm.NORMAL);
+
+        webViewClient = new SimpleWebViewClient();
+        chromeClient = new SimpleChromeClient();
+        webView.setWebViewClient(webViewClient);
+        webView.setWebChromeClient(chromeClient);
+
+        contentView.addView(webView, new LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT, 0.0f));
+
+        handler = new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                switch (msg.what) {
+                    case MSG_TIMEOUT:
+                        handleTimeout();
+                        return;
+                    case MSG_NAVIGATE:
+                        manualDelay = msg.arg2;
+                        navigate(msg.getData().getString(MSG_NAV_URL), msg.arg1);
+                        logTime = msg.getData().getBoolean(MSG_NAV_LOGTIME);
+                        return;
+                }
+            }
+        };
+
+        pageDoneLock = new Object();
+    }
+
+    public void reset() {
+        synchronized (pageDoneLock) {
+            pageDone = false;
+        }
+        timeoutFlag = false;
+        pageStartCount = 0;
+        chromeClient.resetJsTimeout();
+    }
+
+    private void navigate(String url, int timeout) {
+        if(url == null) {
+            Log.v(LOGTAG, "URL is null, cancelling...");
+            finish();
+        }
+        webView.stopLoading();
+        if(logTime) {
+            webView.clearCache(true);
+        }
+        startTime = System.currentTimeMillis();
+        Log.v(LOGTAG, "Navigating to URL: " + url);
+        webView.loadUrl(url);
+
+        if(timeout != 0) {
+            //set a timer with specified timeout (in ms)
+            handler.sendMessageDelayed(handler.obtainMessage(MSG_TIMEOUT),
+                    timeout);
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        Log.v(LOGTAG, "onDestroy, inst=" + Integer.toHexString(hashCode()));
+        webView.clearCache(true);
+        webView.destroy();
+    }
+
+    private boolean isPageDone() {
+        synchronized (pageDoneLock) {
+            return pageDone;
+        }
+    }
+
+    private void setPageDone(boolean pageDone) {
+        synchronized (pageDoneLock) {
+            this.pageDone = pageDone;
+            pageDoneLock.notifyAll();
+        }
+    }
+
+    private void handleTimeout() {
+        int progress = webView.getProgress();
+        webView.stopLoading();
+        Log.v(LOGTAG, "Page timeout triggered, progress = " + progress);
+        timeoutFlag = true;
+        handler.postDelayed(pageDoneRunner, manualDelay);
+    }
+
+    public boolean waitUntilDone() {
+        validateNotAppThread();
+        synchronized (pageDoneLock) {
+            while(!isPageDone()) {
+                try {
+                    pageDoneLock.wait();
+                } catch (InterruptedException ie) {
+                    //no-op
+                }
+            }
+        }
+        return timeoutFlag;
+    }
+
+    public Handler getHandler() {
+        return handler;
+    }
+
+    private final void validateNotAppThread() {
+        if (ActivityThread.currentActivityThread() != null) {
+            throw new RuntimeException(
+                "This method can not be called from the main application thread");
+        }
+    }
+
+    public long getPageLoadTime() {
+        return pageLoadTime;
+    }
+
+    public boolean getPageError() {
+        return webViewClient.getPageErrorFlag();
+    }
+
+    class SimpleWebViewClient extends WebViewClient {
+
+        private boolean pageErrorFlag = false;
+
+        @Override
+        public void onReceivedError(WebView view, int errorCode, String description,
+                String failingUrl) {
+            pageErrorFlag = true;
+            Log.v(LOGTAG, "WebCore error: code=" + errorCode
+                    + ", description=" + description
+                    + ", url=" + failingUrl);
+        }
+
+        @Override
+        public void onPageStarted(WebView view, String url, Bitmap favicon) {
+            pageStartCount++;
+            Log.v(LOGTAG, "onPageStarted: " + url);
+        }
+
+        @Override
+        public void onPageFinished(WebView view, String url) {
+            Log.v(LOGTAG, "onPageFinished: " + url);
+            // let handleTimeout take care of finishing the page
+            if(!timeoutFlag)
+                handler.postDelayed(new WebViewStatusChecker(), 500);
+        }
+
+        // return true if the URL is not available or the page is down
+        public boolean getPageErrorFlag() {
+            return pageErrorFlag;
+        }
+    }
+
+    class SimpleChromeClient extends WebChromeClient {
+
+        private int timeoutCounter = 0;
+
+        public void resetJsTimeout() {
+            timeoutCounter = 0;
+        }
+
+        @Override
+        public void onReceivedTitle(WebView view, String title) {
+            PowerTestActivity.this.setTitle(title);
+        }
+    }
+
+    class WebViewStatusChecker implements Runnable {
+
+        private int initialStartCount;
+
+        public WebViewStatusChecker() {
+            initialStartCount = pageStartCount;
+        }
+
+        public void run() {
+            if (initialStartCount == pageStartCount && !isPageDone()) {
+                handler.removeMessages(MSG_TIMEOUT);
+                webView.stopLoading();
+                handler.postDelayed(pageDoneRunner, manualDelay);
+            }
+        }
+    }
+
+    class PageDoneRunner implements Runnable {
+
+        public void run() {
+            Log.v(LOGTAG, "Finishing URL: " + webView.getUrl());
+            pageLoadTime = System.currentTimeMillis() - startTime;
+            setPageDone(true);
+        }
+    }
+}
diff --git a/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerTestRunner.java b/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerTestRunner.java
new file mode 100644
index 0000000..4857209
--- /dev/null
+++ b/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerTestRunner.java
@@ -0,0 +1,31 @@
+package com.android.browserpowertest;
+
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+
+import junit.framework.TestSuite;
+
+
+/**
+ * Instrumentation Test Runner for all browser power tests.
+ *
+ * Running power tests:
+ *
+ * adb shell am instrument \
+ *   -w com.android.browserpowertest/.PowerTestRunner
+ */
+
+public class PowerTestRunner extends InstrumentationTestRunner {
+    @Override
+    public TestSuite getAllTests() {
+        TestSuite suite = new InstrumentationTestSuite(this);
+        suite.addTestSuite(PowerMeasurement.class);
+        return suite;
+    }
+
+    @Override
+    public ClassLoader getLoader() {
+        return PowerTestRunner.class.getClassLoader();
+    }
+
+}
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index f9d2434..3cf6a71 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -984,7 +984,7 @@
 
                 while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
                     if (code == ResXMLTree::END_TAG) {
-                        if (strcmp16(block.getElementName(&len), private_symbols16.string()) == 0) {
+                        if (strcmp16(block.getElementName(&len), add_resource16.string()) == 0) {
                             break;
                         }
                     }