Merge "Bug 2372180: pass multi-touch events from browser to webkit. Since the UI uses multi-touch for zooming, the event is passed to webkit only when the webpage doesn't allow zooming. 1. Updated the data structure TouchEventData in WebViewCore.java    to take multiple points and used it everywhere. 2. Added a passMultiTouchToWebkit() function to do what its name means. 3. Added the multi-point touch support to dumprendertree."
diff --git a/api/current.xml b/api/current.xml
index 42787e6..69d02d1 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -153459,6 +153459,21 @@
 <parameter name="volumeName" type="java.lang.String">
 </parameter>
 </method>
+<method name="getContentUriForAudioId"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="volumeName" type="java.lang.String">
+</parameter>
+<parameter name="audioId" type="int">
+</parameter>
+</method>
 <field name="CONTENT_TYPE"
  type="java.lang.String"
  transient="false"
diff --git a/cmds/screencap/Android.mk b/cmds/screencap/Android.mk
new file mode 100644
index 0000000..1a6e23e
--- /dev/null
+++ b/cmds/screencap/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	screencap.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+	libutils \
+	libbinder \
+    libui \
+    libsurfaceflinger_client
+
+LOCAL_MODULE:= screencap
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
new file mode 100644
index 0000000..6ce5b86
--- /dev/null
+++ b/cmds/screencap/screencap.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+
+#include <binder/IMemory.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+    const String16 name("SurfaceFlinger");
+    sp<ISurfaceComposer> composer;
+    if (getService(name, &composer) != NO_ERROR)
+        return 0;
+
+    sp<IMemoryHeap> heap;
+    uint32_t w, h;
+    PixelFormat f;
+    status_t err = composer->captureScreen(0, &heap, &w, &h, &f);
+    if (err != NO_ERROR)
+        return 0;
+
+    uint8_t* base = (uint8_t*)heap->getBase();
+    int fd = dup(STDOUT_FILENO);
+    write(fd, &w, 4);
+    write(fd, &h, 4);
+    write(fd, &f, 4);
+    write(fd, base, w*h*4);
+    close(fd);
+    return 0;
+}
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index de544fb..fa7f794 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -55,6 +55,18 @@
     public static final int DISABLE_NOTIFICATION_TICKER = 0x00000008;
 
     /**
+     * Flag for {@link #disable} to hide the center system info area.
+     */
+    public static final int DISABLE_SYSTEM_INFO = 0x00000010;
+
+    /**
+     * Flag for {@link #disable} to hide only the navigation buttons.  Don't use this
+     * unless you're the setup wizard.
+     */
+    public static final int DISABLE_NAVIGATION = 0x00000020;
+
+
+    /**
      * Re-enable all of the status bar features that you've disabled.
      */
     public static final int DISABLE_NONE = 0x00000000;
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index da02845..b74e76f 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -1234,6 +1234,19 @@
             }
 
             /**
+             * Get the content:// style URI for querying the genres of an audio file.
+             *
+             * @param volumeName the name of the volume to get the URI for
+             * @param audioId the ID of the audio file for which to retrieve the genres
+             * @return the URI to for querying the genres for the audio file
+             * with the given the volume and audioID
+             */
+            public static Uri getContentUriForAudioId(String volumeName, int audioId) {
+                return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName +
+                        "/audio/media/" + audioId + "/genres");
+            }
+
+            /**
              * The content:// style URI for the internal storage.
              */
             public static final Uri INTERNAL_CONTENT_URI =
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index cd57ab2..bbf3509 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -241,7 +241,8 @@
     Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(storage);
     Res_png_9patch::deserialize(patch);
 
-    renderer->drawPatch(bitmap, patch, left, top, right, bottom, paint);
+    renderer->drawPatch(bitmap, &patch->xDivs[0], &patch->yDivs[0],
+            patch->numXDivs, patch->numYDivs, left, top, right, bottom, paint);
 
     env->ReleaseByteArrayElements(chunks, storage, 0);
 }
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index c37bb66..ebaaada 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -227,7 +227,7 @@
 
     <style name="Widget.AbsListView">
         <item name="android:scrollbars">vertical</item>
-        <item name="android:fadingEdge">vertical</item>
+        <item name="android:fadingEdge">none</item>
     </style>
 
     <style name="Widget.GestureOverlayView">
@@ -495,12 +495,12 @@
 
     <style name="Widget.ScrollView">
         <item name="android:scrollbars">vertical</item>
-        <item name="android:fadingEdge">vertical</item>
+        <item name="android:fadingEdge">none</item>
     </style>
 
     <style name="Widget.HorizontalScrollView">
         <item name="android:scrollbars">horizontal</item>
-        <item name="android:fadingEdge">horizontal</item>
+        <item name="android:fadingEdge">none</item>
     </style>
 
     <style name="Widget.ListView" parent="Widget.AbsListView">
@@ -523,7 +523,7 @@
     <style name="Widget.ListView.Menu">
 		<item name="android:cacheColorHint">@null</item>
         <item name="android:scrollbars">vertical</item>
-        <item name="android:fadingEdge">vertical</item>
+        <item name="android:fadingEdge">none</item>
         <item name="listSelector">@android:drawable/menu_selector</item>
         <!-- Light background for the list in menus, so the divider for bright themes -->
         <item name="android:divider">@android:drawable/divider_horizontal_dark</item>
@@ -556,7 +556,7 @@
     </style>
 
     <style name="Widget.Gallery">
-        <item name="android:fadingEdge">horizontal</item>
+        <item name="android:fadingEdge">none</item>
         <item name="android:gravity">center_vertical</item>
         <item name="android:spacing">-20dip</item>
         <item name="android:unselectedAlpha">0.85</item>
diff --git a/core/tests/coretests/src/android/pim/RecurrenceSetTest.java b/core/tests/coretests/src/android/pim/RecurrenceSetTest.java
index 64cd6c4..5d01ba0 100644
--- a/core/tests/coretests/src/android/pim/RecurrenceSetTest.java
+++ b/core/tests/coretests/src/android/pim/RecurrenceSetTest.java
@@ -46,7 +46,7 @@
         String recurrence = "DTSTART;VALUE=DATE:20090821\nDTEND;VALUE=DATE:20090822\n"
                 + "RRULE:FREQ=YEARLY;WKST=SU";
         verifyPopulateContentValues(recurrence, "FREQ=YEARLY;WKST=SU", null,
-                null, null, 1250812800000L, null, "P1D", 1);
+                null, null, 1250812800000L, "UTC", "P1D", 1);
     }
 
     // Test 2 day all-day event
@@ -55,7 +55,7 @@
         String recurrence = "DTSTART;VALUE=DATE:20090821\nDTEND;VALUE=DATE:20090823\n"
                 + "RRULE:FREQ=YEARLY;WKST=SU";
         verifyPopulateContentValues(recurrence, "FREQ=YEARLY;WKST=SU", null,
-                null, null, 1250812800000L, null,  "P2D", 1);
+                null, null, 1250812800000L, "UTC",  "P2D", 1);
     }
 
     // run populateContentValues and verify the results
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index e8ffd99..43af702 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -5,6 +5,7 @@
 # defined in the current device/board configuration
 ifeq ($(USE_OPENGL_RENDERER),true)
 	LOCAL_SRC_FILES:= \
+		DisplayListRenderer.cpp \
 		FboCache.cpp \
 		FontRenderer.cpp \
 		GammaFontRenderer.cpp \
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
new file mode 100644
index 0000000..16b6b56
--- /dev/null
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include "DisplayListRenderer.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Base structure
+///////////////////////////////////////////////////////////////////////////////
+
+DisplayListRenderer::DisplayListRenderer():
+        mHeap(HEAP_BLOCK_SIZE), mWriter(MIN_WRITER_SIZE) {
+    mBitmapIndex = mMatrixIndex = mPaintIndex = 1;
+    mPathHeap = NULL;
+}
+
+DisplayListRenderer::~DisplayListRenderer() {
+    reset();
+}
+
+void DisplayListRenderer::reset() {
+    if (mPathHeap) {
+        mPathHeap->unref();
+        mPathHeap = NULL;
+    }
+
+    mBitmaps.reset();
+    mMatrices.reset();
+    mPaints.reset();
+
+    mWriter.reset();
+    mHeap.reset();
+
+    mRCRecorder.reset();
+    mTFRecorder.reset();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Operations
+///////////////////////////////////////////////////////////////////////////////
+
+void DisplayListRenderer::acquireContext() {
+    addOp(AcquireContext);
+    OpenGLRenderer::acquireContext();
+}
+
+void DisplayListRenderer::releaseContext() {
+    addOp(ReleaseContext);
+    OpenGLRenderer::releaseContext();
+}
+
+int DisplayListRenderer::save(int flags) {
+    addOp(Save);
+    addInt(flags);
+    return OpenGLRenderer::save(flags);
+}
+
+void DisplayListRenderer::restore() {
+    addOp(Restore);
+    OpenGLRenderer::restore();
+}
+
+void DisplayListRenderer::restoreToCount(int saveCount) {
+    addOp(RestoreToCount);
+    addInt(saveCount);
+    OpenGLRenderer::restoreToCount(saveCount);
+}
+
+int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom,
+        const SkPaint* p, int flags) {
+    addOp(SaveLayer);
+    addBounds(left, top, right, bottom);
+    addPaint(p);
+    addInt(flags);
+    return OpenGLRenderer::saveLayer(left, top, right, bottom, p, flags);
+}
+
+void DisplayListRenderer::translate(float dx, float dy) {
+    addOp(Translate);
+    addPoint(dx, dy);
+    OpenGLRenderer::translate(dx, dy);
+}
+
+void DisplayListRenderer::rotate(float degrees) {
+    addOp(Rotate);
+    addFloat(degrees);
+    OpenGLRenderer::rotate(degrees);
+}
+
+void DisplayListRenderer::scale(float sx, float sy) {
+    addOp(Scale);
+    addPoint(sx, sy);
+    OpenGLRenderer::scale(sx, sy);
+}
+
+void DisplayListRenderer::setMatrix(SkMatrix* matrix) {
+    addOp(SetMatrix);
+    addMatrix(matrix);
+    OpenGLRenderer::setMatrix(matrix);
+}
+
+void DisplayListRenderer::concatMatrix(SkMatrix* matrix) {
+    addOp(ConcatMatrix);
+    addMatrix(matrix);
+    OpenGLRenderer::concatMatrix(matrix);
+}
+
+bool DisplayListRenderer::clipRect(float left, float top, float right, float bottom,
+        SkRegion::Op op) {
+    addOp(ClipRect);
+    addBounds(left, top, right, bottom);
+    addInt(op);
+    return OpenGLRenderer::clipRect(left, top, right, bottom, op);
+}
+
+void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float left, float top,
+        const SkPaint* paint) {
+    addOp(DrawBitmap);
+    addBitmap(bitmap);
+    addPoint(left, top);
+    addPaint(paint);
+    OpenGLRenderer::drawBitmap(bitmap, left, top, paint);
+}
+
+void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix,
+        const SkPaint* paint) {
+    addOp(DrawBitmapMatrix);
+    addBitmap(bitmap);
+    addMatrix(matrix);
+    addPaint(paint);
+    OpenGLRenderer::drawBitmap(bitmap, matrix, paint);
+}
+
+void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
+        float srcRight, float srcBottom, float dstLeft, float dstTop,
+        float dstRight, float dstBottom, const SkPaint* paint) {
+    addOp(DrawBitmapRect);
+    addBitmap(bitmap);
+    addBounds(srcLeft, srcTop, srcRight, srcBottom);
+    addBounds(dstLeft, dstTop, dstRight, dstBottom);
+    addPaint(paint);
+    OpenGLRenderer::drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
+            dstLeft, dstTop, dstRight, dstBottom, paint);
+}
+
+void DisplayListRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
+        uint32_t width, uint32_t height, float left, float top, float right, float bottom,
+        const SkPaint* paint) {
+    addOp(DrawPatch);
+    addBitmap(bitmap);
+    addInts(xDivs, width);
+    addInts(yDivs, height);
+    addBounds(left, top, right, bottom);
+    addPaint(paint);
+    OpenGLRenderer::drawPatch(bitmap, xDivs, yDivs, width, height,
+            left, top, right, bottom, paint);
+}
+
+void DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) {
+    addOp(DrawColor);
+    addInt(color);
+    addInt(mode);
+    OpenGLRenderer::drawColor(color, mode);
+}
+
+void DisplayListRenderer::drawRect(float left, float top, float right, float bottom,
+        const SkPaint* paint) {
+    addOp(DrawRect);
+    addBounds(left, top, right, bottom);
+    addPaint(paint);
+    OpenGLRenderer::drawRect(left, top, right, bottom, paint);
+}
+
+void DisplayListRenderer::drawPath(SkPath* path, SkPaint* paint) {
+    addOp(DrawPath);
+    addPath(path);
+    addPaint(paint);
+    OpenGLRenderer::drawPath(path, paint);
+}
+
+void DisplayListRenderer::drawLines(float* points, int count, const SkPaint* paint) {
+    addOp(DrawLines);
+    addFloats(points, count);
+    addPaint(paint);
+    OpenGLRenderer::drawLines(points, count, paint);
+}
+
+void DisplayListRenderer::drawText(const char* text, int bytesCount, int count,
+        float x, float y, SkPaint* paint) {
+    addOp(DrawText);
+    addText(text, bytesCount);
+    addInt(count);
+    addPoint(x, y);
+    addPaint(paint);
+    OpenGLRenderer::drawText(text, bytesCount, count, x, y, paint);
+}
+
+void DisplayListRenderer::resetShader() {
+    addOp(ResetShader);
+    OpenGLRenderer::resetShader();
+}
+
+void DisplayListRenderer::setupShader(SkiaShader* shader) {
+    // TODO: Implement
+    OpenGLRenderer::setupShader(shader);
+}
+
+void DisplayListRenderer::resetColorFilter() {
+    addOp(ResetColorFilter);
+    OpenGLRenderer::resetColorFilter();
+}
+
+void DisplayListRenderer::setupColorFilter(SkiaColorFilter* filter) {
+    // TODO: Implement
+    OpenGLRenderer::setupColorFilter(filter);
+}
+
+void DisplayListRenderer::resetShadow() {
+    addOp(ResetShadow);
+    OpenGLRenderer::resetShadow();
+}
+
+void DisplayListRenderer::setupShadow(float radius, float dx, float dy, int color) {
+    addOp(SetupShadow);
+    addFloat(radius);
+    addPoint(dx, dy);
+    addInt(color);
+    OpenGLRenderer::setupShadow(radius, dx, dy, color);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Recording management
+///////////////////////////////////////////////////////////////////////////////
+
+int DisplayListRenderer::find(SkTDArray<const SkFlatPaint*>& paints, const SkPaint* paint) {
+    if (paint == NULL) {
+        return 0;
+    }
+
+    SkFlatPaint* flat = SkFlatPaint::Flatten(&mHeap, *paint, mPaintIndex,
+            &mRCRecorder, &mTFRecorder);
+    int index = SkTSearch<SkFlatData>((const SkFlatData**) paints.begin(),
+            paints.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare);
+    if (index >= 0) {
+        (void) mHeap.unalloc(flat);
+        return paints[index]->index();
+    }
+
+    index = ~index;
+    *paints.insert(index) = flat;
+    return mPaintIndex++;
+}
+
+int DisplayListRenderer::find(SkTDArray<const SkFlatMatrix*>& matrices, const SkMatrix* matrix) {
+    if (matrix == NULL) {
+        return 0;
+    }
+
+    SkFlatMatrix* flat = SkFlatMatrix::Flatten(&mHeap, *matrix, mMatrixIndex);
+    int index = SkTSearch<SkFlatData>((const SkFlatData**) matrices.begin(),
+            matrices.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare);
+    if (index >= 0) {
+        (void) mHeap.unalloc(flat);
+        return matrices[index]->index();
+    }
+    index = ~index;
+    *matrices.insert(index) = flat;
+    return mMatrixIndex++;
+}
+
+int DisplayListRenderer::find(SkTDArray<const SkFlatBitmap*>& bitmaps, const SkBitmap& bitmap) {
+    SkFlatBitmap* flat = SkFlatBitmap::Flatten(&mHeap, bitmap, mBitmapIndex, &mRCRecorder);
+    int index = SkTSearch<SkFlatData>((const SkFlatData**) bitmaps.begin(),
+            bitmaps.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare);
+    if (index >= 0) {
+        (void) mHeap.unalloc(flat);
+        return bitmaps[index]->index();
+    }
+    index = ~index;
+    *bitmaps.insert(index) = flat;
+    return mBitmapIndex++;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
new file mode 100644
index 0000000..7a20b59
--- /dev/null
+++ b/libs/hwui/DisplayListRenderer.h
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UI_DISPLAY_LIST_RENDERER_H
+#define ANDROID_UI_DISPLAY_LIST_RENDERER_H
+
+#include <SkChunkAlloc.h>
+#include <SkFlattenable.h>
+#include <SkMatrix.h>
+#include <SkPaint.h>
+#include <SkPath.h>
+#include <SkPictureFlat.h>
+#include <SkRefCnt.h>
+#include <SkTDArray.h>
+#include <SkTSearch.h>
+
+#include "OpenGLRenderer.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+#define MIN_WRITER_SIZE 16384
+#define HEAP_BLOCK_SIZE 4096
+
+///////////////////////////////////////////////////////////////////////////////
+// Helpers
+///////////////////////////////////////////////////////////////////////////////
+
+class PathHeap: public SkRefCnt {
+public:
+    PathHeap(): mHeap(64 * sizeof(SkPath)) {
+    };
+
+    PathHeap(SkFlattenableReadBuffer& buffer): mHeap(64 * sizeof(SkPath)) {
+        int count = buffer.readS32();
+
+        mPaths.setCount(count);
+        SkPath** ptr = mPaths.begin();
+        SkPath* p = (SkPath*) mHeap.allocThrow(count * sizeof(SkPath));
+
+        for (int i = 0; i < count; i++) {
+            new (p) SkPath;
+            p->unflatten(buffer);
+            *ptr++ = p;
+            p++;
+        }
+    }
+
+    ~PathHeap() {
+        SkPath** iter = mPaths.begin();
+        SkPath** stop = mPaths.end();
+        while (iter < stop) {
+            (*iter)->~SkPath();
+            iter++;
+        }
+    }
+
+    int append(const SkPath& path) {
+        SkPath* p = (SkPath*) mHeap.allocThrow(sizeof(SkPath));
+        new (p) SkPath(path);
+        *mPaths.append() = p;
+        return mPaths.count();
+    }
+
+    int count() const { return mPaths.count(); }
+
+    const SkPath& operator[](int index) const {
+        return *mPaths[index];
+    }
+
+    void flatten(SkFlattenableWriteBuffer& buffer) const {
+        int count = mPaths.count();
+
+        buffer.write32(count);
+        SkPath** iter = mPaths.begin();
+        SkPath** stop = mPaths.end();
+        while (iter < stop) {
+            (*iter)->flatten(buffer);
+            iter++;
+        }
+    }
+
+private:
+    SkChunkAlloc mHeap;
+    SkTDArray<SkPath*> mPaths;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Renderer
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Records drawing commands in a display list for latter playback.
+ */
+class DisplayListRenderer: public OpenGLRenderer {
+public:
+    DisplayListRenderer();
+    ~DisplayListRenderer();
+
+    enum Op {
+        AcquireContext,
+        ReleaseContext,
+        Save,
+        Restore,
+        RestoreToCount,
+        SaveLayer,
+        SaveLayerAlpha,
+        Translate,
+        Rotate,
+        Scale,
+        SetMatrix,
+        ConcatMatrix,
+        ClipRect,
+        DrawBitmap,
+        DrawBitmapMatrix,
+        DrawBitmapRect,
+        DrawPatch,
+        DrawColor,
+        DrawRect,
+        DrawPath,
+        DrawLines,
+        DrawText,
+        ResetShader,
+        SetupShader,
+        ResetColorFilter,
+        SetupColorFilter,
+        ResetShadow,
+        SetupShadow
+    };
+
+    void acquireContext();
+    void releaseContext();
+
+    int save(int flags);
+    void restore();
+    void restoreToCount(int saveCount);
+
+    int saveLayer(float left, float top, float right, float bottom,
+            const SkPaint* p, int flags);
+
+    void translate(float dx, float dy);
+    void rotate(float degrees);
+    void scale(float sx, float sy);
+
+    void setMatrix(SkMatrix* matrix);
+    void concatMatrix(SkMatrix* matrix);
+
+    bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
+
+    void drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint);
+    void drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint);
+    void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
+            float srcRight, float srcBottom, float dstLeft, float dstTop,
+            float dstRight, float dstBottom, const SkPaint* paint);
+    void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
+            uint32_t width, uint32_t height, float left, float top, float right, float bottom,
+            const SkPaint* paint);
+    void drawColor(int color, SkXfermode::Mode mode);
+    void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
+    void drawPath(SkPath* path, SkPaint* paint);
+    void drawLines(float* points, int count, const SkPaint* paint);
+    void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint);
+
+    void resetShader();
+    void setupShader(SkiaShader* shader);
+
+    void resetColorFilter();
+    void setupColorFilter(SkiaColorFilter* filter);
+
+    void resetShadow();
+    void setupShadow(float radius, float dx, float dy, int color);
+
+    void reset();
+
+private:
+    inline void addOp(Op drawOp) {
+        mWriter.writeInt(drawOp);
+    }
+
+    inline void addInt(int value) {
+        mWriter.writeInt(value);
+    }
+
+    void addInts(const int32_t* values, uint32_t count) {
+        for (uint32_t i = 0; i < count; i++) {
+            mWriter.writeInt(values[i]);
+        }
+    }
+
+    inline void addFloat(float value) {
+        mWriter.writeScalar(value);
+    }
+
+    void addFloats(const float* values, int count) {
+        for (int i = 0; i < count; i++) {
+            mWriter.writeScalar(values[i]);
+        }
+    }
+
+    inline void addPoint(float x, float y) {
+        mWriter.writeScalar(x);
+        mWriter.writeScalar(y);
+    }
+
+    inline void addBounds(float left, float top, float right, float bottom) {
+        mWriter.writeScalar(left);
+        mWriter.writeScalar(top);
+        mWriter.writeScalar(right);
+        mWriter.writeScalar(bottom);
+    }
+
+    inline void addText(const void* text, size_t byteLength) {
+        mWriter.writeInt(byteLength);
+        mWriter.writePad(text, byteLength);
+    }
+
+    inline void addPath(const SkPath* path) {
+        if (mPathHeap == NULL) {
+            mPathHeap = new PathHeap();
+        }
+        addInt(mPathHeap->append(*path));
+    }
+
+    int find(SkTDArray<const SkFlatPaint*>& paints, const SkPaint* paint);
+
+    inline void addPaint(const SkPaint* paint) {
+        addInt(find(mPaints, paint));
+    }
+
+    int find(SkTDArray<const SkFlatMatrix*>& matrices, const SkMatrix* matrix);
+
+    inline void addMatrix(const SkMatrix* matrix) {
+        addInt(find(mMatrices, matrix));
+    }
+
+    int find(SkTDArray<const SkFlatBitmap*>& bitmaps, const SkBitmap& bitmap);
+
+    inline void addBitmap(const SkBitmap* bitmap) {
+        addInt(find(mBitmaps, *bitmap));
+    }
+
+    SkChunkAlloc mHeap;
+
+    int mBitmapIndex;
+    SkTDArray<const SkFlatBitmap*> mBitmaps;
+
+    int mMatrixIndex;
+    SkTDArray<const SkFlatMatrix*> mMatrices;
+
+    int mPaintIndex;
+    SkTDArray<const SkFlatPaint*> mPaints;
+
+    PathHeap* mPathHeap;
+    SkWriter32 mWriter;
+
+    SkRefCntRecorder mRCRecorder;
+    SkRefCntRecorder mTFRecorder;
+
+}; // class DisplayListRenderer
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_DISPLAY_LIST_RENDERER_H
diff --git a/libs/hwui/OpenGLDebugRenderer.cpp b/libs/hwui/OpenGLDebugRenderer.cpp
index f5a4286..4e5123e 100644
--- a/libs/hwui/OpenGLDebugRenderer.cpp
+++ b/libs/hwui/OpenGLDebugRenderer.cpp
@@ -71,11 +71,13 @@
             dstLeft, dstTop, dstRight, dstBottom, paint);
 }
 
-void OpenGLDebugRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
-        float left, float top, float right, float bottom, const SkPaint* paint) {
+void OpenGLDebugRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
+        uint32_t width, uint32_t height, float left, float top, float right, float bottom,
+        const SkPaint* paint) {
     mPrimitivesCount++;
     StopWatch w("drawPatch");
-    OpenGLRenderer::drawPatch(bitmap, patch, left, top, right, bottom, paint);
+    OpenGLRenderer::drawPatch(bitmap, xDivs, yDivs, width, height,
+            left, top, right, bottom, paint);
 }
 
 void OpenGLDebugRenderer::drawColor(int color, SkXfermode::Mode mode) {
diff --git a/libs/hwui/OpenGLDebugRenderer.h b/libs/hwui/OpenGLDebugRenderer.h
index 37fac93..ce15512 100644
--- a/libs/hwui/OpenGLDebugRenderer.h
+++ b/libs/hwui/OpenGLDebugRenderer.h
@@ -45,8 +45,9 @@
     void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
             float srcRight, float srcBottom, float dstLeft, float dstTop,
             float dstRight, float dstBottom, const SkPaint* paint);
-    void drawPatch(SkBitmap* bitmap, Res_png_9patch* patch, float left, float top,
-            float right, float bottom, const SkPaint* paint);
+    void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
+            uint32_t width, uint32_t height, float left, float top, float right, float bottom,
+            const SkPaint* paint);
     void drawColor(int color, SkXfermode::Mode mode);
     void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
     void drawPath(SkPath* path, SkPaint* paint);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index dbd499e..23de3a5 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -585,8 +585,9 @@
     resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
 }
 
-void OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
-        float left, float top, float right, float bottom, const SkPaint* paint) {
+void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
+        uint32_t width, uint32_t height, float left, float top, float right, float bottom,
+        const SkPaint* paint) {
     if (quickReject(left, top, right, bottom)) {
         return;
     }
@@ -600,9 +601,9 @@
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
-    Patch* mesh = mCaches.patchCache.get(patch);
+    Patch* mesh = mCaches.patchCache.get(width, height);
     mesh->updateVertices(bitmap->width(), bitmap->height(),left, top, right, bottom,
-            &patch->xDivs[0], &patch->yDivs[0], patch->numXDivs, patch->numYDivs);
+            xDivs, yDivs, width, height);
 
     // Specify right and bottom as +1.0f from left/top to prevent scaling since the
     // patch mesh already defines the final size
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index af2a70b..d505d80 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -28,7 +28,6 @@
 #include <SkXfermode.h>
 
 #include <utils/RefBase.h>
-#include <utils/ResourceTypes.h>
 #include <utils/Vector.h>
 
 #include "Extensions.h"
@@ -69,38 +68,39 @@
     virtual void prepare();
     virtual void finish();
 
-    void acquireContext();
-    void releaseContext();
+    virtual void acquireContext();
+    virtual void releaseContext();
 
     int getSaveCount() const;
-    int save(int flags);
-    void restore();
-    void restoreToCount(int saveCount);
+    virtual int save(int flags);
+    virtual void restore();
+    virtual void restoreToCount(int saveCount);
 
     virtual int saveLayer(float left, float top, float right, float bottom,
             const SkPaint* p, int flags);
     virtual int saveLayerAlpha(float left, float top, float right, float bottom,
             int alpha, int flags);
 
-    void translate(float dx, float dy);
-    void rotate(float degrees);
-    void scale(float sx, float sy);
+    virtual void translate(float dx, float dy);
+    virtual void rotate(float degrees);
+    virtual void scale(float sx, float sy);
 
-    void setMatrix(SkMatrix* matrix);
     void getMatrix(SkMatrix* matrix);
-    void concatMatrix(SkMatrix* matrix);
+    virtual void setMatrix(SkMatrix* matrix);
+    virtual void concatMatrix(SkMatrix* matrix);
 
     const Rect& getClipBounds();
     bool quickReject(float left, float top, float right, float bottom);
-    bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
+    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
 
     virtual void drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
             float srcRight, float srcBottom, float dstLeft, float dstTop,
             float dstRight, float dstBottom, const SkPaint* paint);
-    virtual void drawPatch(SkBitmap* bitmap, Res_png_9patch* patch, float left, float top,
-            float right, float bottom, const SkPaint* paint);
+    virtual void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
+            uint32_t width, uint32_t height, float left, float top, float right, float bottom,
+            const SkPaint* paint);
     virtual void drawColor(int color, SkXfermode::Mode mode);
     virtual void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
     virtual void drawPath(SkPath* path, SkPaint* paint);
@@ -108,14 +108,14 @@
     virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
             SkPaint* paint);
 
-    void resetShader();
-    void setupShader(SkiaShader* shader);
+    virtual void resetShader();
+    virtual void setupShader(SkiaShader* shader);
 
-    void resetColorFilter();
-    void setupColorFilter(SkiaColorFilter* filter);
+    virtual void resetColorFilter();
+    virtual void setupColorFilter(SkiaColorFilter* filter);
 
-    void resetShadow();
-    void setupShadow(float radius, float dx, float dy, int color);
+    virtual void resetShadow();
+    virtual void setupShadow(float radius, float dx, float dy, int color);
 
 protected:
     /**
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index a7c0cce..f2cf548 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -57,9 +57,7 @@
     mCache.setOnEntryRemovedListener(NULL);
 }
 
-Patch* PatchCache::get(const Res_png_9patch* patch) {
-    const uint32_t width = patch->numXDivs;
-    const uint32_t height = patch->numYDivs;
+Patch* PatchCache::get(uint32_t width, uint32_t height) {
     const PatchDescription description(width, height);
 
     Patch* mesh = mCache.get(description);
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index 6dad831..b077469 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -17,8 +17,6 @@
 #ifndef ANDROID_UI_PATCH_CACHE_H
 #define ANDROID_UI_PATCH_CACHE_H
 
-#include <utils/ResourceTypes.h>
-
 #include "Patch.h"
 #include "GenerationCache.h"
 
@@ -55,7 +53,7 @@
      */
     void operator()(PatchDescription& description, Patch*& mesh);
 
-    Patch* get(const Res_png_9patch* patch);
+    Patch* get(uint32_t width, uint32_t height);
     void clear();
 
 private:
diff --git a/media/java/android/media/MtpDatabase.java b/media/java/android/media/MtpDatabase.java
index 403ed58..630d7112e 100644
--- a/media/java/android/media/MtpDatabase.java
+++ b/media/java/android/media/MtpDatabase.java
@@ -25,8 +25,9 @@
 import android.net.Uri;
 import android.os.RemoteException;
 import android.provider.MediaStore.Audio;
-import android.provider.MediaStore.MediaColumns;
 import android.provider.MediaStore.Files;
+import android.provider.MediaStore.Images;
+import android.provider.MediaStore.MediaColumns;
 import android.provider.Mtp;
 import android.util.Log;
 
@@ -278,8 +279,9 @@
         return null;
     }
 
-    private int[] getSupportedObjectProperties(int handle) {
-        return new int[] {
+    static final int[] FILE_PROPERTIES = {
+            // NOTE must match beginning of AUDIO_PROPERTIES, VIDEO_PROPERTIES
+            // and IMAGE_PROPERTIES below
             MtpConstants.PROPERTY_STORAGE_ID,
             MtpConstants.PROPERTY_OBJECT_FORMAT,
             MtpConstants.PROPERTY_PROTECTION_STATUS,
@@ -289,7 +291,93 @@
             MtpConstants.PROPERTY_PARENT_OBJECT,
             MtpConstants.PROPERTY_PERSISTENT_UID,
             MtpConstants.PROPERTY_NAME,
-        };
+            MtpConstants.PROPERTY_DATE_ADDED,
+    };
+
+    static final int[] AUDIO_PROPERTIES = {
+            // NOTE must match FILE_PROPERTIES above
+            MtpConstants.PROPERTY_STORAGE_ID,
+            MtpConstants.PROPERTY_OBJECT_FORMAT,
+            MtpConstants.PROPERTY_PROTECTION_STATUS,
+            MtpConstants.PROPERTY_OBJECT_SIZE,
+            MtpConstants.PROPERTY_OBJECT_FILE_NAME,
+            MtpConstants.PROPERTY_DATE_MODIFIED,
+            MtpConstants.PROPERTY_PARENT_OBJECT,
+            MtpConstants.PROPERTY_PERSISTENT_UID,
+            MtpConstants.PROPERTY_NAME,
+            MtpConstants.PROPERTY_DISPLAY_NAME,
+            MtpConstants.PROPERTY_DATE_ADDED,
+
+            // audio specific properties
+            MtpConstants.PROPERTY_ARTIST,
+            MtpConstants.PROPERTY_ALBUM_NAME,
+            MtpConstants.PROPERTY_ALBUM_ARTIST,
+            MtpConstants.PROPERTY_TRACK,
+            MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE,
+            MtpConstants.PROPERTY_DURATION,
+            MtpConstants.PROPERTY_GENRE,
+            MtpConstants.PROPERTY_COMPOSER,
+    };
+
+    static final int[] VIDEO_PROPERTIES = {
+            // NOTE must match FILE_PROPERTIES above
+            MtpConstants.PROPERTY_STORAGE_ID,
+            MtpConstants.PROPERTY_OBJECT_FORMAT,
+            MtpConstants.PROPERTY_PROTECTION_STATUS,
+            MtpConstants.PROPERTY_OBJECT_SIZE,
+            MtpConstants.PROPERTY_OBJECT_FILE_NAME,
+            MtpConstants.PROPERTY_DATE_MODIFIED,
+            MtpConstants.PROPERTY_PARENT_OBJECT,
+            MtpConstants.PROPERTY_PERSISTENT_UID,
+            MtpConstants.PROPERTY_NAME,
+            MtpConstants.PROPERTY_DISPLAY_NAME,
+            MtpConstants.PROPERTY_DATE_ADDED,
+
+            // video specific properties
+            MtpConstants.PROPERTY_ARTIST,
+            MtpConstants.PROPERTY_ALBUM_NAME,
+            MtpConstants.PROPERTY_DURATION,
+            MtpConstants.PROPERTY_DESCRIPTION,
+    };
+
+    static final int[] IMAGE_PROPERTIES = {
+            // NOTE must match FILE_PROPERTIES above
+            MtpConstants.PROPERTY_STORAGE_ID,
+            MtpConstants.PROPERTY_OBJECT_FORMAT,
+            MtpConstants.PROPERTY_PROTECTION_STATUS,
+            MtpConstants.PROPERTY_OBJECT_SIZE,
+            MtpConstants.PROPERTY_OBJECT_FILE_NAME,
+            MtpConstants.PROPERTY_DATE_MODIFIED,
+            MtpConstants.PROPERTY_PARENT_OBJECT,
+            MtpConstants.PROPERTY_PERSISTENT_UID,
+            MtpConstants.PROPERTY_NAME,
+            MtpConstants.PROPERTY_DISPLAY_NAME,
+            MtpConstants.PROPERTY_DATE_ADDED,
+
+            // image specific properties
+            MtpConstants.PROPERTY_DESCRIPTION,
+    };
+
+    private int[] getSupportedObjectProperties(int format) {
+        switch (format) {
+            case MtpConstants.FORMAT_MP3:
+            case MtpConstants.FORMAT_WAV:
+            case MtpConstants.FORMAT_WMA:
+            case MtpConstants.FORMAT_OGG:
+            case MtpConstants.FORMAT_AAC:
+                return AUDIO_PROPERTIES;
+            case MtpConstants.FORMAT_MPEG:
+            case MtpConstants.FORMAT_3GP_CONTAINER:
+            case MtpConstants.FORMAT_WMV:
+                return VIDEO_PROPERTIES;
+            case MtpConstants.FORMAT_EXIF_JPEG:
+            case MtpConstants.FORMAT_GIF:
+            case MtpConstants.FORMAT_PNG:
+            case MtpConstants.FORMAT_BMP:
+                return IMAGE_PROPERTIES;
+            default:
+                return FILE_PROPERTIES;
+        }
     }
 
     private int[] getSupportedDeviceProperties() {
@@ -299,17 +387,90 @@
         };
     }
 
+    private String queryString(int id, String column) {
+        Cursor c = null;
+        try {
+            // for now we are only reading properties from the "objects" table
+            c = mMediaProvider.query(mObjectsUri,
+                            new String [] { Files.FileColumns._ID, column },
+                            ID_WHERE, new String[] { Integer.toString(id) }, null);
+            if (c != null && c.moveToNext()) {
+                return c.getString(1);
+            } else {
+                return "";
+            }
+        } catch (Exception e) {
+            return null;
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+    }
+
+    private String queryGenre(int id) {
+        Cursor c = null;
+        try {
+            Uri uri = Audio.Genres.getContentUriForAudioId(mVolumeName, id);
+            c = mMediaProvider.query(uri,
+                            new String [] { Files.FileColumns._ID, Audio.GenresColumns.NAME },
+                            null, null, null);
+            if (c != null && c.moveToNext()) {
+                return c.getString(1);
+            } else {
+                return "";
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "queryGenre exception", e);
+            return null;
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+    }
+
+    private boolean queryInt(int id, String column, long[] outValue) {
+        Cursor c = null;
+        try {
+            // for now we are only reading properties from the "objects" table
+            c = mMediaProvider.query(mObjectsUri,
+                            new String [] { Files.FileColumns._ID, column },
+                            ID_WHERE, new String[] { Integer.toString(id) }, null);
+            if (c != null && c.moveToNext()) {
+                outValue[0] = c.getLong(1);
+                return true;
+            }
+            return false;
+        } catch (Exception e) {
+            return false;
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+    }
+
+    private String nameFromPath(String path) {
+        // extract name from full path
+        int start = 0;
+        int lastSlash = path.lastIndexOf('/');
+        if (lastSlash >= 0) {
+            start = lastSlash + 1;
+        }
+        int end = path.length();
+        if (end - start > 255) {
+            end = start + 255;
+        }
+        return path.substring(start, end);
+    }
+
     private int getObjectProperty(int handle, int property,
                             long[] outIntValue, char[] outStringValue) {
         Log.d(TAG, "getObjectProperty: " + property);
         String column = null;
         boolean isString = false;
 
-        // temporary hack
-        if (property == MtpConstants.PROPERTY_NAME) {
-            property = MtpConstants.PROPERTY_OBJECT_FILE_NAME;
-        }
-
         switch (property) {
             case MtpConstants.PROPERTY_STORAGE_ID:
                 outIntValue[0] = mStorageID;
@@ -325,12 +486,46 @@
                 column = Files.FileColumns.SIZE;
                 break;
             case MtpConstants.PROPERTY_OBJECT_FILE_NAME:
-                column = Files.FileColumns.DATA;
-                isString = true;
-                break;
+                // special case - need to extract file name from full path
+                String value = queryString(handle, Files.FileColumns.DATA);
+                if (value != null) {
+                    value = nameFromPath(value);
+                    value.getChars(0, value.length(), outStringValue, 0);
+                    outStringValue[value.length()] = 0;
+                    return MtpConstants.RESPONSE_OK;
+                } else {
+                    return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
+                }
+            case MtpConstants.PROPERTY_NAME:
+                // first try title
+                String name = queryString(handle, MediaColumns.TITLE);
+                // then try name
+                if (name == null) {
+                    name = queryString(handle, Audio.PlaylistsColumns.NAME);
+                }
+                // if title and name fail, extract name from full path
+                if (name == null) {
+                    name = queryString(handle, Files.FileColumns.DATA);
+                    if (name != null) {
+                        name = nameFromPath(name);
+                    }
+                }
+                if (name != null) {
+                    name.getChars(0, name.length(), outStringValue, 0);
+                    outStringValue[name.length()] = 0;
+                    return MtpConstants.RESPONSE_OK;
+                } else {
+                    return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
+                }
             case MtpConstants.PROPERTY_DATE_MODIFIED:
                 column = Files.FileColumns.DATE_MODIFIED;
                 break;
+            case MtpConstants.PROPERTY_DATE_ADDED:
+                column = Files.FileColumns.DATE_ADDED;
+                break;
+            case MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE:
+                column = Audio.AudioColumns.YEAR;
+                break;
             case MtpConstants.PROPERTY_PARENT_OBJECT:
                 column = Files.FileColumns.PARENT;
                 break;
@@ -341,44 +536,64 @@
                 puid += handle;
                 outIntValue[0] = puid;
                 return MtpConstants.RESPONSE_OK;
+            case MtpConstants.PROPERTY_DURATION:
+                column = Audio.AudioColumns.DURATION;
+                break;
+            case MtpConstants.PROPERTY_TRACK:
+                if (queryInt(handle, Audio.AudioColumns.TRACK, outIntValue)) {
+                    // track is stored in lower 3 decimal digits
+                    outIntValue[0] %= 1000;
+                    return MtpConstants.RESPONSE_OK;
+                } else {
+                    return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
+                }
+            case MtpConstants.PROPERTY_DISPLAY_NAME:
+                column = MediaColumns.DISPLAY_NAME;
+                isString = true;
+                break;
+            case MtpConstants.PROPERTY_ARTIST:
+                column = Audio.AudioColumns.ARTIST;
+                isString = true;
+                break;
+            case MtpConstants.PROPERTY_ALBUM_NAME:
+                column = Audio.AudioColumns.ALBUM;
+                isString = true;
+                break;
+            case MtpConstants.PROPERTY_ALBUM_ARTIST:
+                column = Audio.AudioColumns.ALBUM_ARTIST;
+                isString = true;
+                break;
+            case MtpConstants.PROPERTY_GENRE:
+                String genre = queryGenre(handle);
+                if (genre != null) {
+                    genre.getChars(0, genre.length(), outStringValue, 0);
+                    outStringValue[genre.length()] = 0;
+                    return MtpConstants.RESPONSE_OK;
+                } else {
+                    return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
+                }
+            case MtpConstants.PROPERTY_COMPOSER:
+                column = Audio.AudioColumns.COMPOSER;
+                isString = true;
+                break;
+            case MtpConstants.PROPERTY_DESCRIPTION:
+                column = Images.ImageColumns.DESCRIPTION;
+                isString = true;
+                break;
             default:
                 return MtpConstants.RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
         }
 
-        Cursor c = null;
-        try {
-            // for now we are only reading properties from the "objects" table
-            c = mMediaProvider.query(mObjectsUri,
-                            new String [] { Files.FileColumns._ID, column },
-                            ID_WHERE, new String[] { Integer.toString(handle) }, null);
-            if (c != null && c.moveToNext()) {
-                if (isString) {
-                    String value = c.getString(1);
-                    int start = 0;
-
-                    if (property == MtpConstants.PROPERTY_OBJECT_FILE_NAME) {
-                        // extract name from full path
-                        int lastSlash = value.lastIndexOf('/');
-                        if (lastSlash >= 0) {
-                            start = lastSlash + 1;
-                        }
-                    }
-                    int end = value.length();
-                    if (end - start > 255) {
-                        end = start + 255;
-                    }
-                    value.getChars(start, end, outStringValue, 0);
-                    outStringValue[end - start] = 0;
-                } else {
-                    outIntValue[0] = c.getLong(1);
-                }
+        if (isString) {
+            String value = queryString(handle, column);
+            if (value != null) {
+                value.getChars(0, value.length(), outStringValue, 0);
+                outStringValue[value.length()] = 0;
                 return MtpConstants.RESPONSE_OK;
             }
-        } catch (Exception e) {
-            return MtpConstants.RESPONSE_GENERAL_ERROR;
-        } finally {
-            if (c != null) {
-                c.close();
+        } else {
+            if (queryInt(handle, column, outIntValue)) {
+                return MtpConstants.RESPONSE_OK;
             }
         }
         // query failed if we get here
diff --git a/media/jni/android_media_MtpDatabase.cpp b/media/jni/android_media_MtpDatabase.cpp
index b5f4856..10ad29d 100644
--- a/media/jni/android_media_MtpDatabase.cpp
+++ b/media/jni/android_media_MtpDatabase.cpp
@@ -342,14 +342,21 @@
     jlong longValue = longValues[0];
     env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
 
-    // special case MTP_PROPERTY_DATE_MODIFIED, which is a string to MTP
+    // special case date properties, which are strings to MTP
     // but stored internally as a uint64
-    if (property == MTP_PROPERTY_DATE_MODIFIED) {
+    if (property == MTP_PROPERTY_DATE_MODIFIED || property == MTP_PROPERTY_DATE_ADDED) {
         char    date[20];
         formatDateTime(longValue, date, sizeof(date));
         packet.putString(date);
         return MTP_RESPONSE_OK;
     }
+    // release date is stored internally as just the year
+    if (property == MTP_PROPERTY_ORIGINAL_RELEASE_DATE) {
+        char    date[20];
+        snprintf(date, sizeof(date), "%04lld0101T000000", longValue);
+        packet.putString(date);
+        return MTP_RESPONSE_OK;
+    }
 
     switch (type) {
         case MTP_TYPE_INT8:
@@ -680,6 +687,17 @@
     {   MTP_PROPERTY_PARENT_OBJECT,     MTP_TYPE_UINT32     },
     {   MTP_PROPERTY_PERSISTENT_UID,    MTP_TYPE_UINT128    },
     {   MTP_PROPERTY_NAME,              MTP_TYPE_STR        },
+    {   MTP_PROPERTY_DISPLAY_NAME,      MTP_TYPE_STR        },
+    {   MTP_PROPERTY_DATE_ADDED,        MTP_TYPE_STR        },
+    {   MTP_PROPERTY_ARTIST,            MTP_TYPE_STR        },
+    {   MTP_PROPERTY_ALBUM_NAME,        MTP_TYPE_STR        },
+    {   MTP_PROPERTY_ALBUM_ARTIST,      MTP_TYPE_STR        },
+    {   MTP_PROPERTY_TRACK,             MTP_TYPE_UINT16     },
+    {   MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_TYPE_STR    },
+    {   MTP_PROPERTY_GENRE,             MTP_TYPE_STR        },
+    {   MTP_PROPERTY_COMPOSER,          MTP_TYPE_STR        },
+    {   MTP_PROPERTY_DURATION,          MTP_TYPE_UINT32     },
+    {   MTP_PROPERTY_DESCRIPTION,       MTP_TYPE_STR        },
 };
 
 static const PropertyTableEntry   kDevicePropertyTable[] = {
@@ -754,10 +772,12 @@
     switch (property) {
         case MTP_PROPERTY_OBJECT_FORMAT:
         case MTP_PROPERTY_PROTECTION_STATUS:
+        case MTP_PROPERTY_TRACK:
             result = new MtpProperty(property, MTP_TYPE_UINT16);
             break;
         case MTP_PROPERTY_STORAGE_ID:
         case MTP_PROPERTY_PARENT_OBJECT:
+        case MTP_PROPERTY_DURATION:
             result = new MtpProperty(property, MTP_TYPE_UINT32);
             break;
         case MTP_PROPERTY_OBJECT_SIZE:
@@ -769,6 +789,15 @@
         case MTP_PROPERTY_NAME:
         case MTP_PROPERTY_OBJECT_FILE_NAME:
         case MTP_PROPERTY_DATE_MODIFIED:
+        case MTP_PROPERTY_DISPLAY_NAME:
+        case MTP_PROPERTY_DATE_ADDED:
+        case MTP_PROPERTY_ARTIST:
+        case MTP_PROPERTY_ALBUM_NAME:
+        case MTP_PROPERTY_ALBUM_ARTIST:
+        case MTP_PROPERTY_ORIGINAL_RELEASE_DATE:
+        case MTP_PROPERTY_GENRE:
+        case MTP_PROPERTY_COMPOSER:
+        case MTP_PROPERTY_DESCRIPTION:
             result = new MtpProperty(property, MTP_TYPE_STR);
             break;
     }
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 03a6bbb..5505f14 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -65,8 +65,8 @@
 {
     pContext->mCaptureIdx = 0;
     pContext->mCurrentBuf = 0;
-    memset(pContext->mCaptureBuf[0], 0, VISUALIZER_CAPTURE_SIZE_MAX);
-    memset(pContext->mCaptureBuf[1], 0, VISUALIZER_CAPTURE_SIZE_MAX);
+    memset(pContext->mCaptureBuf[0], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
+    memset(pContext->mCaptureBuf[1], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
 }
 
 //----------------------------------------------------------------------------
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index 0f3e245..88b8c86 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -228,24 +228,32 @@
                               void *replyData)
 {
     if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
+        LOGV("command() bad status %d", mStatus);
         return INVALID_OPERATION;
     }
 
+    if ((cmdCode == EFFECT_CMD_ENABLE || cmdCode == EFFECT_CMD_DISABLE) &&
+            (replySize == NULL || *replySize != sizeof(status_t) || replyData == NULL)) {
+        return BAD_VALUE;
+    }
+
     status_t status = mIEffect->command(cmdCode, cmdSize, cmdData, replySize, replyData);
     if (status != NO_ERROR) {
         return status;
     }
-    status = *(status_t *)replyData;
-    if (status != NO_ERROR) {
-        return status;
+
+    if (cmdCode == EFFECT_CMD_ENABLE || cmdCode == EFFECT_CMD_DISABLE) {
+        status = *(status_t *)replyData;
+        if (status != NO_ERROR) {
+            return status;
+        }
+        if (cmdCode == EFFECT_CMD_ENABLE) {
+            android_atomic_or(1, &mEnabled);
+        } else {
+            android_atomic_and(~1, &mEnabled);
+        }
     }
 
-    if (cmdCode == EFFECT_CMD_ENABLE) {
-        android_atomic_or(1, &mEnabled);
-    }
-    if (cmdCode == EFFECT_CMD_DISABLE) {
-        android_atomic_and(~1, &mEnabled);
-    }
     return status;
 }
 
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
index 39552b6..68f2e9b 100644
--- a/media/libmedia/Visualizer.cpp
+++ b/media/libmedia/Visualizer.cpp
@@ -169,11 +169,13 @@
     status_t status = NO_ERROR;
     if (mEnabled) {
         uint32_t replySize = mCaptureSize;
-        status_t status = command(VISU_CMD_CAPTURE, 0, NULL, &replySize, waveform);
+        status = command(VISU_CMD_CAPTURE, 0, NULL, &replySize, waveform);
+        LOGV("getWaveForm() command returned %d", status);
         if (replySize == 0) {
             status = NOT_ENOUGH_DATA;
         }
     } else {
+        LOGV("getWaveForm() disabled");
         memset(waveform, 0x80, mCaptureSize);
     }
     return status;
@@ -191,7 +193,7 @@
     status_t status = NO_ERROR;
     if (mEnabled) {
         uint8_t buf[mCaptureSize];
-        status_t status = getWaveForm(buf);
+        status = getWaveForm(buf);
         if (status == NO_ERROR) {
             status = doFft(fft, buf);
         }
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index ba1e218..e6c2f7e 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -1541,20 +1541,52 @@
         int32_t isSync = false;
         meta_data->findInt32(kKeyIsSyncFrame, &isSync);
 
+        /*
+         * The original timestamp found in the data buffer will be modified as below:
+         *
+         * There is a playback offset into this track if the track's start time
+         * is not the same as the movie start time, which will be recorded in edst
+         * box of the output file. The playback offset is to make sure that the
+         * starting time of the audio/video tracks are synchronized. Although the
+         * track's media timestamp may be subject to various modifications
+         * as outlined below, the track's playback offset time remains unchanged
+         * once the first data buffer of the track is received.
+         *
+         * The media time stamp will be calculated by subtracting the playback offset
+         * (and potential pause durations) from the original timestamp in the buffer.
+         *
+         * If this track is a video track for a real-time recording application with
+         * both audio and video tracks, its media timestamp will subject to further
+         * modification based on the media clock of the audio track. This modification
+         * is needed for the purpose of maintaining good audio/video synchronization.
+         *
+         * If the recording session is paused and resumed multiple times, the track
+         * media timestamp will be modified as if the  recording session had never been
+         * paused at all during playback of the recorded output file. In other words,
+         * the output file will have no memory of pause/resume durations.
+         *
+         */
         CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
+        LOGV("%s timestampUs: %lld", mIsAudio? "Audio": "Video", timestampUs);
 
 ////////////////////////////////////////////////////////////////////////////////
         if (mSampleSizes.empty()) {
             mStartTimestampUs = timestampUs;
             mOwner->setStartTimestampUs(mStartTimestampUs);
+            previousPausedDurationUs = mStartTimestampUs;
         }
 
         if (mResumed) {
-            previousPausedDurationUs += (timestampUs - mTrackDurationUs - lastDurationUs);
+            int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
+            CHECK(durExcludingEarlierPausesUs >= 0);
+            int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
+            CHECK(pausedDurationUs >= lastDurationUs);
+            previousPausedDurationUs += pausedDurationUs - lastDurationUs;
             mResumed = false;
         }
 
         timestampUs -= previousPausedDurationUs;
+        CHECK(timestampUs >= 0);
         if (mIsRealTimeRecording && !mIsAudio) {
             // The minor adjustment on the timestamp is heuristic/experimental
             // We are adjusting the timestamp to reduce the fluctuation of the duration
@@ -1590,8 +1622,8 @@
             }
         }
 
-        LOGV("time stamp: %lld and previous paused duration %lld",
-                timestampUs, previousPausedDurationUs);
+        LOGV("%s media time stamp: %lld and previous paused duration %lld",
+                mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs);
         if (timestampUs > mTrackDurationUs) {
             mTrackDurationUs = timestampUs;
         }
@@ -1873,6 +1905,7 @@
 
             // First elst entry: specify the starting time offset
             int64_t offsetUs = mStartTimestampUs - moovStartTimeUs;
+            LOGV("OffsetUs: %lld", offsetUs);
             int32_t seg = (offsetUs * mvhdTimeScale + 5E5) / 1E6;
             mOwner->writeInt32(seg);         // in mvhd timecale
             mOwner->writeInt32(-1);          // starting time offset
diff --git a/media/libstagefright/NuHTTPDataSource.cpp b/media/libstagefright/NuHTTPDataSource.cpp
index 332bab3..2743b2f 100644
--- a/media/libstagefright/NuHTTPDataSource.cpp
+++ b/media/libstagefright/NuHTTPDataSource.cpp
@@ -96,6 +96,11 @@
     return connect(host, port, path, headers, offset);
 }
 
+static bool IsRedirectStatusCode(int httpStatus) {
+    return httpStatus == 301 || httpStatus == 302
+        || httpStatus == 303 || httpStatus == 307;
+}
+
 status_t NuHTTPDataSource::connect(
         const char *host, unsigned port, const char *path,
         const String8 &headers,
@@ -161,7 +166,7 @@
             return err;
         }
 
-        if (httpStatus == 302) {
+        if (IsRedirectStatusCode(httpStatus)) {
             string value;
             CHECK(mHTTP.find_header_value("Location", &value));
 
diff --git a/packages/SystemUI/res/anim/navigation_in.xml b/packages/SystemUI/res/anim/navigation_in.xml
new file mode 100644
index 0000000..630fd72
--- /dev/null
+++ b/packages/SystemUI/res/anim/navigation_in.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    >
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+        android:duration="@android:integer/config_longAnimTime" 
+        />
+</set>
diff --git a/packages/SystemUI/res/anim/navigation_out.xml b/packages/SystemUI/res/anim/navigation_out.xml
new file mode 100644
index 0000000..4717e47
--- /dev/null
+++ b/packages/SystemUI/res/anim/navigation_out.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    >
+    <alpha android:toAlpha="0.0" android:fromAlpha="1.0"
+        android:duration="@android:integer/config_longAnimTime" 
+        />
+</set>
diff --git a/packages/SystemUI/res/anim/system_in.xml b/packages/SystemUI/res/anim/system_in.xml
new file mode 100644
index 0000000..630fd72
--- /dev/null
+++ b/packages/SystemUI/res/anim/system_in.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    >
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+        android:duration="@android:integer/config_longAnimTime" 
+        />
+</set>
diff --git a/packages/SystemUI/res/anim/system_out.xml b/packages/SystemUI/res/anim/system_out.xml
new file mode 100644
index 0000000..4717e47
--- /dev/null
+++ b/packages/SystemUI/res/anim/system_out.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+    >
+    <alpha android:toAlpha="0.0" android:fromAlpha="1.0"
+        android:duration="@android:integer/config_longAnimTime" 
+        />
+</set>
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml
index 5741a66..6aee011 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml
@@ -119,46 +119,50 @@
             android:layout_centerInParent="true"
             />
 
-        <com.android.systemui.statusbar.KeyButtonView android:id="@+id/menu"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_toLeftOf="@+id/recent"
-            android:src="@drawable/ic_sysbar_menu"
-            android:background="@drawable/ic_sysbar_icon_bg"
-            android:paddingLeft="4dip"
-            android:paddingRight="4dip"
-            systemui:keyCode="82"
-            />
-        <ImageButton android:id="@+id/recent"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_toLeftOf="@+id/home"
-            android:src="@drawable/ic_sysbar_recent"
-            android:background="@drawable/ic_sysbar_icon_bg"
-            android:paddingLeft="4dip"
-            android:paddingRight="4dip"
-            android:onClick="recentButtonClicked"
-            />
-        <com.android.systemui.statusbar.KeyButtonView android:id="@+id/home"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_toLeftOf="@+id/back"
-            android:paddingLeft="4dip"
-            android:paddingRight="4dip"
-            android:src="@drawable/ic_sysbar_home"
-            android:background="@drawable/ic_sysbar_icon_bg"
-            systemui:keyCode="3"
-            />
-        <com.android.systemui.statusbar.KeyButtonView android:id="@+id/back"
+        <LinearLayout
+            android:id="@+id/navigationArea"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
             android:layout_alignParentRight="true"
-            android:paddingLeft="4dip"
-            android:paddingRight="4dip"
-            android:src="@drawable/ic_sysbar_back"
-            android:background="@drawable/ic_sysbar_icon_bg"
-            systemui:keyCode="4"
-            />
+            android:orientation="horizontal"
+            >
+            <com.android.systemui.statusbar.KeyButtonView android:id="@+id/menu"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:src="@drawable/ic_sysbar_menu"
+                android:background="@drawable/ic_sysbar_icon_bg"
+                android:paddingLeft="4dip"
+                android:paddingRight="4dip"
+                systemui:keyCode="82"
+                />
+            <ImageButton android:id="@+id/recent"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:src="@drawable/ic_sysbar_recent"
+                android:background="@drawable/ic_sysbar_icon_bg"
+                android:paddingLeft="4dip"
+                android:paddingRight="4dip"
+                android:onClick="recentButtonClicked"
+                />
+            <com.android.systemui.statusbar.KeyButtonView android:id="@+id/home"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:paddingLeft="4dip"
+                android:paddingRight="4dip"
+                android:src="@drawable/ic_sysbar_home"
+                android:background="@drawable/ic_sysbar_icon_bg"
+                systemui:keyCode="3"
+                />
+            <com.android.systemui.statusbar.KeyButtonView android:id="@+id/back"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:paddingLeft="4dip"
+                android:paddingRight="4dip"
+                android:src="@drawable/ic_sysbar_back"
+                android:background="@drawable/ic_sysbar_icon_bg"
+                systemui:keyCode="4"
+                />
+        </LinearLayout>
     </RelativeLayout>
 
     <!-- It's curtains for you. -->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
index 49337fde..ffa1690 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
@@ -78,6 +78,7 @@
     NotificationIconArea mNotificationIconArea;
     View mNotificationButtons;
     View mSystemInfo;
+    View mNavigationArea;
 
     NotificationPanel mNotificationPanel;
     SystemPanel mSystemPanel;
@@ -98,7 +99,6 @@
     TabletTicker mTicker;
     View mTickerView;
     boolean mTicking;
-    boolean mExpandedVisible;
 
     // for disabling the status bar
     int mDisabled = 0;
@@ -203,6 +203,9 @@
         mSignalMeter = (ImageView) sb.findViewById(R.id.signal);
         mSignalIcon = (ImageView) sb.findViewById(R.id.signal_icon);
 
+        // The navigation buttons
+        mNavigationArea = sb.findViewById(R.id.navigationArea);
+
         // Add the windows
         addPanelWindows();
 
@@ -224,24 +227,26 @@
             switch (m.what) {
                 case MSG_OPEN_NOTIFICATION_PANEL:
                     if (DEBUG) Slog.d(TAG, "opening notifications panel");
-                    mDoNotDisturbButton.setText(mNotificationsOn
-                            ? R.string.status_bar_do_not_disturb_button
-                            : R.string.status_bar_please_disturb_button);
-                    mNotificationPanel.setVisibility(View.VISIBLE);
-                    mNotificationIconArea.setAnimation(loadAnim(R.anim.notification_icons_out));
-                    mNotificationIconArea.setVisibility(View.GONE);
-                    mNotificationButtons.setAnimation(loadAnim(R.anim.notification_icons_in));
-                    mNotificationButtons.setVisibility(View.VISIBLE);
-                    mExpandedVisible = true;
+                    if (mNotificationPanel.getVisibility() == View.GONE) {
+                        mDoNotDisturbButton.setText(mNotificationsOn
+                                ? R.string.status_bar_do_not_disturb_button
+                                : R.string.status_bar_please_disturb_button);
+                        mNotificationPanel.setVisibility(View.VISIBLE);
+                        setViewVisibility(mNotificationIconArea, View.GONE,
+                                R.anim.notification_icons_out);
+                        setViewVisibility(mNotificationButtons, View.VISIBLE,
+                                R.anim.notification_buttons_in);
+                    }
                     break;
                 case MSG_CLOSE_NOTIFICATION_PANEL:
                     if (DEBUG) Slog.d(TAG, "closing notifications panel");
-                    mNotificationPanel.setVisibility(View.GONE);
-                    mNotificationIconArea.setAnimation(loadAnim(R.anim.notification_icons_in));
-                    mNotificationIconArea.setVisibility(View.VISIBLE);
-                    mNotificationButtons.setAnimation(loadAnim(R.anim.notification_buttons_out));
-                    mNotificationButtons.setVisibility(View.GONE);
-                    mExpandedVisible = false;
+                    if (mNotificationPanel.getVisibility() == View.VISIBLE) {
+                        mNotificationPanel.setVisibility(View.GONE);
+                        setViewVisibility(mNotificationIconArea, View.VISIBLE,
+                                R.anim.notification_icons_in);
+                        setViewVisibility(mNotificationButtons, View.GONE,
+                                R.anim.notification_buttons_out);
+                    }
                     break;
                 case MSG_OPEN_SYSTEM_PANEL:
                     if (DEBUG) Slog.d(TAG, "opening system panel");
@@ -390,11 +395,14 @@
     }
 
     public void disable(int state) {
-        /*
-        final int old = mDisabled;
-        final int diff = state ^ old;
+        int old = mDisabled;
+        int diff = state ^ old;
+        Slog.d(TAG, "disable... old=0x" + Integer.toHexString(old)
+                + " diff=0x" + Integer.toHexString(diff)
+                + " state=0x" + Integer.toHexString(state));
         mDisabled = state;
 
+        // act accordingly
         if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
             if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
                 Slog.d(TAG, "DISABLE_EXPAND: yes");
@@ -404,60 +412,41 @@
         if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
             if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
                 Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
-                if (mTicking) {
-                    mTicker.halt();
-                } else {
-                    mNotificationIconArea.setVisibility(View.INVISIBLE);
-                }
+                setViewVisibility(mNotificationTrigger, View.GONE,
+                        R.anim.notification_icons_out);
+                setViewVisibility(mNotificationIconArea, View.GONE,
+                        R.anim.notification_icons_out);
+                mTicker.halt();
             } else {
                 Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
-                if (!mExpandedVisible) {
-                    mNotificationIconArea.setVisibility(View.VISIBLE);
-                }
+                setViewVisibility(mNotificationTrigger, View.VISIBLE,
+                        R.anim.notification_icons_in);
+                setViewVisibility(mNotificationIconArea, View.VISIBLE,
+                        R.anim.notification_icons_in);
             }
         } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-            if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_TICKER: yes");
+            if ((state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
                 mTicker.halt();
             }
         }
-        */
-    }
-
-    void performDisableActions(int net) {
-        /*
-        int old = mDisabled;
-        int diff = net ^ old;
-        mDisabled = net;
-
-        // act accordingly
-        if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
-            if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
-                Slog.d(TAG, "DISABLE_EXPAND: yes");
-                animateCollapse();
-            }
-        }
-        if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-            if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
-                if (mTicking) {
-                    mNotificationIconArea.setVisibility(View.INVISIBLE);
-                    mTicker.halt();
-                } else {
-                    mNotificationIconArea.setVisibility(View.INVISIBLE);
-                }
+        if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
+            if ((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
+                Slog.d(TAG, "DISABLE_SYSTEM_INFO: yes");
+                setViewVisibility(mSystemInfo, View.GONE, R.anim.navigation_out);
             } else {
-                Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
-                if (!mExpandedVisible) {
-                    mNotificationIconArea.setVisibility(View.VISIBLE);
-                }
-            }
-        } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-            if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
-                mTicker.halt();
+                Slog.d(TAG, "DISABLE_SYSTEM_INFO: no");
+                setViewVisibility(mSystemInfo, View.VISIBLE, R.anim.navigation_in);
             }
         }
-        */
+        if ((diff & StatusBarManager.DISABLE_NAVIGATION) != 0) {
+            if ((state & StatusBarManager.DISABLE_NAVIGATION) != 0) {
+                Slog.d(TAG, "DISABLE_NAVIGATION: yes");
+                setViewVisibility(mNavigationArea, View.GONE, R.anim.navigation_out);
+            } else {
+                Slog.d(TAG, "DISABLE_NAVIGATION: no");
+                setViewVisibility(mNavigationArea, View.VISIBLE, R.anim.navigation_in);
+            }
+        }
     }
 
     private boolean hasTicker(Notification n) {
@@ -497,35 +486,35 @@
 
     public void setLightsOn(boolean on) {
         if (on) {
-            mCurtains.setAnimation(loadAnim(R.anim.lights_out_out));
-            mCurtains.setVisibility(View.GONE);
-            mBarContents.setAnimation(loadAnim(R.anim.status_bar_in));
-            mBarContents.setVisibility(View.VISIBLE);
+            setViewVisibility(mCurtains, View.GONE, R.anim.lights_out_out);
+            setViewVisibility(mBarContents, View.VISIBLE, R.anim.status_bar_in);
         } else {
             animateCollapse();
-            mCurtains.setAnimation(loadAnim(R.anim.lights_out_in));
-            mCurtains.setVisibility(View.VISIBLE);
-            mBarContents.setAnimation(loadAnim(R.anim.status_bar_out));
-            mBarContents.setVisibility(View.GONE);
+            setViewVisibility(mCurtains, View.VISIBLE, R.anim.lights_out_in);
+            setViewVisibility(mBarContents, View.GONE, R.anim.status_bar_out);
         }
     }
 
     public void notificationIconsClicked(View v) {
         if (DEBUG) Slog.d(TAG, "clicked notification icons");
-        int msg = (mNotificationPanel.getVisibility() == View.GONE) 
-            ? MSG_OPEN_NOTIFICATION_PANEL
-            : MSG_CLOSE_NOTIFICATION_PANEL;
-        mHandler.removeMessages(msg);
-        mHandler.sendEmptyMessage(msg);
+        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
+            int msg = (mNotificationPanel.getVisibility() == View.GONE) 
+                ? MSG_OPEN_NOTIFICATION_PANEL
+                : MSG_CLOSE_NOTIFICATION_PANEL;
+            mHandler.removeMessages(msg);
+            mHandler.sendEmptyMessage(msg);
+        }
     }
 
     public void systemInfoClicked(View v) {
         if (DEBUG) Slog.d(TAG, "clicked system info");
-        int msg = (mSystemPanel.getVisibility() == View.GONE) 
-            ? MSG_OPEN_SYSTEM_PANEL
-            : MSG_CLOSE_SYSTEM_PANEL;
-        mHandler.removeMessages(msg);
-        mHandler.sendEmptyMessage(msg);
+        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
+            int msg = (mSystemPanel.getVisibility() == View.GONE) 
+                ? MSG_OPEN_SYSTEM_PANEL
+                : MSG_CLOSE_SYSTEM_PANEL;
+            mHandler.removeMessages(msg);
+            mHandler.sendEmptyMessage(msg);
+        }
     }
 
     public void recentButtonClicked(View v) {
@@ -690,10 +679,6 @@
         }
     }
 
-    Animation loadAnim(int id) {
-        return AnimationUtils.loadAnimation((Context)this, id);
-    }
-
     private boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
         StatusBarNotification sbn = entry.notification;
         RemoteViews remoteViews = sbn.notification.contentView;
@@ -802,6 +787,13 @@
             return false;
         }
     }
+
+    private void setViewVisibility(View v, int vis, int anim) {
+        if (v.getVisibility() != vis) {
+            v.setAnimation(AnimationUtils.loadAnimation((Context)this, anim));
+            v.setVisibility(vis);
+        }
+    }
 }
 
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
index 7ac7919..3c3139f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
@@ -59,7 +59,6 @@
 
         // TODO: Make this a configuration value.
         // 3 is enough to let us see most cases, but not get so far behind that it's annoying.
-        int mQueuePos = 0;
         mQueue = new StatusBarNotification[3];
     }
 
@@ -80,6 +79,18 @@
         }
     }
 
+    public void halt() {
+        removeMessages(MSG_ADVANCE);
+        if (mCurrentView != null) {
+            final int N = mQueue.length;
+            for (int i=0; i<N; i++) {
+                mQueue[i] = null;
+            }
+            mQueuePos = 0;
+            sendEmptyMessage(MSG_ADVANCE);
+        }
+    }
+
     public void handleMessage(Message msg) {
         switch (msg.what) {
             case MSG_ADVANCE:
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index c82a085..8f90756 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -91,6 +91,7 @@
 import android.view.Display;
 import android.view.WindowManager;
 
+import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -8304,7 +8305,8 @@
             mPastSignatures.clear();
 
             try {
-                FileOutputStream str = new FileOutputStream(mSettingsFilename);
+                BufferedOutputStream str = new BufferedOutputStream(new FileOutputStream(
+                        mSettingsFilename));
 
                 //XmlSerializer serializer = XmlUtils.serializerInstance();
                 XmlSerializer serializer = new FastXmlSerializer();
@@ -8401,7 +8403,7 @@
                 File tempFile = new File(mPackageListFilename.toString() + ".tmp");
                 JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile);
 
-                str = new FileOutputStream(journal.chooseForWrite());
+                str = new BufferedOutputStream(new FileOutputStream(journal.chooseForWrite()));
                 try {
                     StringBuilder sb = new StringBuilder();
                     for (PackageSetting pkg : mPackages.values()) {
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index 08194d4..ed581df 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -636,6 +636,18 @@
             }
 
             @Override
+            public void onCallEstablished(SipAudioCall call) {
+                call.startAudio();
+                onChanged(call);
+            }
+
+            @Override
+            public void onCallHeld(SipAudioCall call) {
+                call.startAudio();
+                onChanged(call);
+            }
+
+            @Override
             public void onChanged(SipAudioCall call) {
                 synchronized (SipPhone.class) {
                     Call.State newState = getCallStateFrom(call);
@@ -655,7 +667,6 @@
                             }
                             foregroundCall.switchWith(ringingCall);
                         }
-                        if (newState == Call.State.ACTIVE) call.startAudio();
                         setState(newState);
                     }
                     mOwner.onConnectionStateChanged(SipConnection.this);
diff --git a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
index e31711e..ca438ec 100644
--- a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
@@ -147,6 +147,24 @@
                     }, 3000);
             }
         },
+        new Test("Disable Navigation") {
+            public void run() {
+                mStatusBarManager.disable(StatusBarManager.DISABLE_NAVIGATION);
+            }
+        },
+        new Test("Disable everything in 3 sec") {
+            public void run() {
+                mHandler.postDelayed(new Runnable() {
+                        public void run() {
+                            mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND
+                                    | StatusBarManager.DISABLE_NOTIFICATION_ICONS
+                                    | StatusBarManager.DISABLE_NOTIFICATION_ALERTS
+                                    | StatusBarManager.DISABLE_SYSTEM_INFO
+                                    | StatusBarManager.DISABLE_NAVIGATION);
+                        }
+                    }, 3000);
+            }
+        },
         new Test("Enable everything") {
             public void run() {
                 mStatusBarManager.disable(0);
diff --git a/voip/jni/rtp/AudioGroup.cpp b/voip/jni/rtp/AudioGroup.cpp
index 7cf06137..81d4dfc 100644
--- a/voip/jni/rtp/AudioGroup.cpp
+++ b/voip/jni/rtp/AudioGroup.cpp
@@ -86,6 +86,8 @@
     void decode(int tick);
 
 private:
+    bool isNatAddress(struct sockaddr_storage *addr);
+
     enum {
         NORMAL = 0,
         SEND_ONLY = 1,
@@ -316,6 +318,16 @@
         sizeof(mRemote));
 }
 
+bool AudioStream::isNatAddress(struct sockaddr_storage *addr) {
+    if (addr->ss_family != AF_INET) return false;
+    struct sockaddr_in *s4 = (struct sockaddr_in *)addr;
+    unsigned char *d = (unsigned char *) &s4->sin_addr;
+    if ((d[0] == 10)
+        || ((d[0] == 172) && (d[1] & 0x10))
+        || ((d[0] == 192) && (d[1] == 168))) return true;
+    return false;
+}
+
 void AudioStream::decode(int tick)
 {
     char c;
@@ -363,8 +375,21 @@
             MSG_TRUNC | MSG_DONTWAIT) >> 1;
     } else {
         __attribute__((aligned(4))) uint8_t buffer[2048];
-        length = recv(mSocket, buffer, sizeof(buffer),
-            MSG_TRUNC | MSG_DONTWAIT);
+        struct sockaddr_storage src_addr;
+        socklen_t addrlen;
+        length = recvfrom(mSocket, buffer, sizeof(buffer),
+            MSG_TRUNC|MSG_DONTWAIT, (sockaddr*)&src_addr, &addrlen);
+
+        // The following if clause is for fixing the target address if
+        // proxy server did not replace the NAT address with its media
+        // port in SDP. Although it is proxy server's responsibility for
+        // replacing the connection address with correct one, we will change
+        // the target address as we detect the difference for now until we
+        // know the best way to get rid of this issue.
+        if ((memcmp((void*)&src_addr, (void*)&mRemote, addrlen) != 0) &&
+            isNatAddress(&mRemote)) {
+            memcpy((void*)&mRemote, (void*)&src_addr, addrlen);
+        }
 
         // Do we need to check SSRC, sequence, and timestamp? They are not
         // reliable but at least they can be used to identify duplicates?