Merge "Fix flashing artifacts caused by invalidation bugs"
diff --git a/build/phone-hdpi-512-dalvik-heap.mk b/build/phone-hdpi-512-dalvik-heap.mk
index 788b686..16e0505 100644
--- a/build/phone-hdpi-512-dalvik-heap.mk
+++ b/build/phone-hdpi-512-dalvik-heap.mk
@@ -19,5 +19,5 @@
 
 PRODUCT_PROPERTY_OVERRIDES += \
     dalvik.vm.heapstartsize=5m \
-    dalvik.vm.heapgrowthlimit=32m \
+    dalvik.vm.heapgrowthlimit=48m \
     dalvik.vm.heapsize=128m
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 2b9c082..9bab797 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -82,11 +82,8 @@
     /* Clears default preferences and permissions for the package */
     void clearDefaults(String packageName);
 
-    /* Sets the current primary USB function. */
-    void setPrimaryFunction(String functions);
-
-    /* Sets the default primary USB function. */
-    void setDefaultFunction(String functions);
+    /* Sets the current USB function. */
+    void setCurrentFunction(String function, boolean makeDefault);
 
     /* Sets the file path for USB mass storage backing file. */
     void setMassStorageBackingFile(String path);
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index a828a23..67d200c 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -408,32 +408,18 @@
     }
 
     /**
-     * Sets the primary USB function.
+     * Sets the current USB function.
      *
      * @param function name of the USB function
+     * @param makeDefault true if this should be set as the default
      *
      * {@hide}
      */
-    public void setPrimaryFunction(String function) {
+    public void setCurrentFunction(String function, boolean makeDefault) {
         try {
-            mService.setPrimaryFunction(function);
+            mService.setCurrentFunction(function, makeDefault);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in setPrimaryFunction", e);
-        }
-    }
-
-    /**
-     * Sets the default primary USB function.
-     *
-     * @param function name of the USB function
-     *
-     * {@hide}
-     */
-    public void setDefaultFunction(String function) {
-        try {
-            mService.setDefaultFunction(function);
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in setDefaultFunction", e);
+            Log.e(TAG, "RemoteException in setCurrentFunction", e);
         }
     }
 
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 2242e9e..ce6f697 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -164,6 +164,12 @@
     public static final String EXTRA_ERRORED_TETHER = "erroredArray";
 
     /**
+     * The absence of APN..
+     * @hide
+     */
+    public static final int TYPE_NONE        = -1;
+
+    /**
      * The Default Mobile data connection.  When active, all data traffic
      * will use this connection by default.
      */
diff --git a/core/java/android/server/BluetoothBondState.java b/core/java/android/server/BluetoothBondState.java
index 39c3c88..5fa8836 100644
--- a/core/java/android/server/BluetoothBondState.java
+++ b/core/java/android/server/BluetoothBondState.java
@@ -79,7 +79,6 @@
         mService = service;
         mBluetoothInputProfileHandler =
             BluetoothInputProfileHandler.getInstance(mContext, mService);
-        getProfileProxy();
     }
 
     synchronized void setPendingOutgoingBonding(String address) {
@@ -109,6 +108,7 @@
             mState.put(mService.getAddressFromObjectPath(device).toUpperCase(),
                     BluetoothDevice.BOND_BONDED);
         }
+        getProfileProxy();
     }
 
     public synchronized void setBondState(String address, int state) {
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 0421205..2f598f4 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -96,12 +96,9 @@
     private SurfaceTexture mSurface;
     private SurfaceTextureListener mListener;
 
-    private final Runnable mUpdateLayerAction = new Runnable() {
-        @Override
-        public void run() {
-            updateLayer();
-        }
-    };
+    private final Object[] mLock = new Object[0];
+    private boolean mUpdateLayer;
+
     private SurfaceTexture.OnFrameAvailableListener mUpdateListener;
 
     /**
@@ -232,6 +229,8 @@
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
         if (mSurface != null) {
+            // No need to synchronize here, we set update layer to false only on the UI thread
+            mUpdateLayer = true;
             nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
             if (mListener != null) {
                 mListener.onSurfaceTextureSizeChanged(mSurface, getWidth(), getHeight());
@@ -255,7 +254,10 @@
                 public void onFrameAvailable(SurfaceTexture surfaceTexture) {
                     // Per SurfaceTexture's documentation, the callback may be invoked
                     // from an arbitrary thread
-                    post(mUpdateLayerAction);
+                    synchronized (mLock) {
+                        mUpdateLayer = true;
+                        postInvalidate();
+                    }
                 }
             };
             mSurface.setOnFrameAvailableListener(mUpdateListener);
@@ -265,6 +267,13 @@
             }
         }
 
+        synchronized (mLock) {
+            if (mUpdateLayer) {
+                mAttachInfo.mHardwareRenderer.updateTextureLayer(mLayer, getWidth(), getHeight());
+                mUpdateLayer = false;
+            }
+        }
+
         return mLayer;
     }
 
@@ -278,23 +287,15 @@
             // updates listener
             if (visibility == VISIBLE) {
                 mSurface.setOnFrameAvailableListener(mUpdateListener);
-                updateLayer();
+                // No need to synchronize here, we set update layer to false only on the UI thread
+                mUpdateLayer = true;
+                invalidate();
             } else {
                 mSurface.setOnFrameAvailableListener(null);
             }
         }
     }
 
-    private void updateLayer() {
-        if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
-            return;
-        }
-
-        mAttachInfo.mHardwareRenderer.updateTextureLayer(mLayer, getWidth(), getHeight());
-
-        invalidate();
-    }
-
     /**
      * <p>Returns a {@link android.graphics.Bitmap} representation of the content
      * of the associated surface texture. If the surface texture is not available,
diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewAncestor.java
index ca11c70..ad660c1 100644
--- a/core/java/android/view/ViewAncestor.java
+++ b/core/java/android/view/ViewAncestor.java
@@ -1005,8 +1005,7 @@
                     + "x" + desiredWindowHeight + "...");
 
             boolean goodMeasure = false;
-            if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
-                    || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
+            if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
                 // On large screens, we don't want to allow dialogs to just
                 // stretch to fill the entire width of the screen to display
                 // one line of text.  First try doing the layout at a smaller
diff --git a/core/java/android/webkit/JniUtil.java b/core/java/android/webkit/JniUtil.java
index b5d4933..bb4d192 100644
--- a/core/java/android/webkit/JniUtil.java
+++ b/core/java/android/webkit/JniUtil.java
@@ -23,6 +23,10 @@
 import java.io.InputStream;
 
 class JniUtil {
+
+    static {
+        System.loadLibrary("webcore");
+    }
     private static final String LOGTAG = "webkit";
     private JniUtil() {} // Utility class, do not instantiate.
 
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 0e52869..e88d257 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -535,7 +535,7 @@
         return result;
     }
 
-    private int getDefaultMargin(View c, boolean leading, boolean horizontal) {
+    private int getDefaultMargin(View c, boolean horizontal, boolean leading) {
         // In the absence of any other information, calculate a default gap such
         // that, in a grid of identical components, the heights and the vertical
         // gaps are in the proportion of the golden ratio.
@@ -544,12 +544,12 @@
         return (int) (c.getMeasuredHeight() / GOLDEN_RATIO / 2);
     }
 
-    private int getDefaultMargin(View c, boolean isAtEdge, boolean leading, boolean horizontal) {
+    private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) {
         // todo remove DEFAULT_CONTAINER_MARGIN. Use padding? Seek advice on Themes/Styles, etc.
-        return isAtEdge ? DEFAULT_CONTAINER_MARGIN : getDefaultMargin(c, leading, horizontal);
+        return isAtEdge ? DEFAULT_CONTAINER_MARGIN : getDefaultMargin(c, horizontal, leading);
     }
 
-    private int getDefaultMarginValue(View c, LayoutParams p, boolean leading, boolean horizontal) {
+    private int getDefaultMarginValue(View c, LayoutParams p, boolean horizontal, boolean leading) {
         if (!mUseDefaultMargins) {
             return 0;
         }
@@ -558,15 +558,19 @@
         Interval span = group.span;
         boolean isAtEdge = leading ? (span.min == 0) : (span.max == axis.getCount());
 
-        return getDefaultMargin(c, isAtEdge, leading, horizontal);
+        return getDefaultMargin(c, isAtEdge, horizontal, leading);
     }
 
-    private int getMargin(View view, boolean leading, boolean horizontal) {
+    private int getMargin(View view, boolean horizontal, boolean leading) {
         LayoutParams lp = getLayoutParams(view);
         int margin = horizontal ?
                 (leading ? lp.leftMargin : lp.rightMargin) :
                 (leading ? lp.topMargin : lp.bottomMargin);
-        return margin == UNDEFINED ? getDefaultMarginValue(view, lp, leading, horizontal) : margin;
+        return margin == UNDEFINED ? getDefaultMarginValue(view, lp, horizontal, leading) : margin;
+    }
+
+    private int getTotalMargin(View child, boolean horizontal) {
+        return getMargin(child, horizontal, true) + getMargin(child, horizontal, false);
     }
 
     private static int valueIfDefined(int value, int defaultValue) {
@@ -749,8 +753,8 @@
                 View c = getChildAt(i);
                 drawRectangle(canvas,
                         c.getLeft() - getMargin(c, true, true),
-                        c.getTop() - getMargin(c, true, false),
-                        c.getRight() + getMargin(c, false, true),
+                        c.getTop() - getMargin(c, false, true),
+                        c.getRight() + getMargin(c, true, false),
                         c.getBottom() + getMargin(c, false, false), paint);
             }
         }
@@ -794,17 +798,12 @@
         return c.getVisibility() == View.GONE;
     }
 
-    private void measureChildWithMargins(View child,
-            int parentWidthMeasureSpec, int parentHeightMeasureSpec) {
-
+    private void measureChildWithMargins(View child, int widthMeasureSpec, int heightMeasureSpec) {
         LayoutParams lp = getLayoutParams(child);
-        int hMargins = getMargin(child, true, true) + getMargin(child, false, true);
-        int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
-                mPaddingLeft + mPaddingRight + hMargins, lp.width);
-        int vMargins = getMargin(child, true, false) + getMargin(child, false, false);
-        int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
-                mPaddingTop + mPaddingBottom + vMargins, lp.height);
-
+        int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
+                mPaddingLeft + mPaddingRight + getTotalMargin(child, true), lp.width);
+        int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
+                mPaddingTop + mPaddingBottom + getTotalMargin(child, false), lp.height);
         child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
     }
 
@@ -842,9 +841,7 @@
     private int getMeasurementIncludingMargin(View c, boolean horizontal, int measurementType) {
         int result = getMeasurement(c, horizontal, measurementType);
         if (mAlignmentMode == ALIGN_MARGINS) {
-            int leadingMargin = getMargin(c, true, horizontal);
-            int trailingMargin = getMargin(c, false, horizontal);
-            return result + leadingMargin + trailingMargin;
+            return result + getTotalMargin(c, horizontal);
         }
         return result;
     }
@@ -919,8 +916,8 @@
 
             if (mAlignmentMode == ALIGN_MARGINS) {
                 int leftMargin = getMargin(c, true, true);
-                int topMargin = getMargin(c, true, false);
-                int rightMargin = getMargin(c, false, true);
+                int topMargin = getMargin(c, false, true);
+                int rightMargin = getMargin(c, true, false);
                 int bottomMargin = getMargin(c, false, false);
 
                 // Same calculation as getMeasurementIncludingMargin()
@@ -1387,7 +1384,7 @@
                 Group g = horizontal ? lp.columnGroup : lp.rowGroup;
                 Interval span = g.span;
                 int index = leading ? span.min : span.max;
-                margins[index] = max(margins[index], getMargin(c, leading, horizontal));
+                margins[index] = max(margins[index], getMargin(c, horizontal, leading));
             }
         }
 
@@ -1817,7 +1814,8 @@
         }
 
         private int getDefaultWeight(int size) {
-            return (size == MATCH_PARENT) ? DEFAULT_WEIGHT_1 : DEFAULT_WEIGHT_0;
+            //return (size == MATCH_PARENT) ? DEFAULT_WEIGHT_1 : DEFAULT_WEIGHT_0;
+            return DEFAULT_WEIGHT_0;
         }
 
         private void init(Context context, AttributeSet attrs, int defaultGravity) {
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index cbb110a..0c0205c 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -464,8 +464,7 @@
                 break;
             case MeasureSpec.EXACTLY:
             default:
-                // use the specified size, if non-zero
-                result = specSize != 0 ? specSize : desired;
+                result = specSize;
         }
         return result;
     }
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index e301e44..16992997 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -649,7 +649,9 @@
     float transform[16];
     sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
 
-    surfaceTexture->updateTexImage();
+    while (surfaceTexture->getQueuedCount() > 0) {
+        surfaceTexture->updateTexImage();
+    }
     surfaceTexture->getTransformMatrix(transform);
     GLenum renderTarget = surfaceTexture->getCurrentTextureTarget();
 
diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
index dd68d82..03c6022 100644
--- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
@@ -101,6 +101,10 @@
         android:visibility="gone"
         />
 
+    <!-- We need MATCH_PARENT here only to force the size of the parent to be passed to
+    the pattern view for it to compute its size. This is an unusual case, caused by
+    LockPatternView's requirement to maintain a square aspect ratio based on the width
+    of the screen. -->
     <com.android.internal.widget.LockPatternView
         android:id="@+id/lockPattern"
         android:layout_width="match_parent"
@@ -109,6 +113,8 @@
         android:layout_marginRight="8dip"
         android:layout_marginBottom="4dip"
         android:layout_marginLeft="8dip"
+        android:layout_gravity="center|bottom"
+        android:layout_rowWeight="1"
      />
 
     <TextView
@@ -123,8 +129,7 @@
     <!-- Footer: an emergency call button and an initially hidden "Forgot pattern" button -->
     <LinearLayout
         android:orientation="horizontal"
-        android:layout_width="match_parent"
-        android:layout_gravity="center">
+        android:layout_gravity="fill_horizontal">
 
         <Button android:id="@+id/emergencyCallButton"
             android:layout_width="wrap_content"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 52b00c6..a8b7b75 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -98,7 +98,7 @@
     <!-- This string array should be overridden by the device to present a list of network
          attributes.  This is used by the connectivity manager to decide which networks can coexist
          based on the hardware -->
-    <!-- An Array of "[Connection name],[ConnectivityManager connection type],
+    <!-- An Array of "[Connection name],[ConnectivityManager.TYPE_xxxx],
          [associated radio-type],[priority],[restoral-timer(ms)],[dependencyMet]  -->
     <!-- the 5th element "resore-time" indicates the number of milliseconds to delay
          before automatically restore the default connection.  Set -1 if the connection
@@ -154,20 +154,16 @@
     <string-array translatable="false" name="config_tether_dhcp_range">
     </string-array>
 
-    <!-- Regex array of allowable upstream ifaces for tethering - for example if you want
-         tethering on a new interface called "foo2" add <item>"foo\\d"</item> to the array -->
-    <!-- Interfaces will be prioritized according to the order listed -->
-    <string-array translatable="false" name="config_tether_upstream_regexs">
-    </string-array>
-
     <!-- Regex of wired ethernet ifaces -->
     <string translatable="false" name="config_ethernet_iface_regex">eth\\d</string>
 
-    <!-- Boolean indicating if we require the use of DUN on mobile for tethering.
-         Note that this defaults to false so that if you move to a carrier that
-         hasn't configured anything tethering will still work.  If you'd rather
-         make the device untetherable on unconfigured devices, set to true -->
-    <bool translatable="false" name="config_tether_dun_required">false</bool>
+    <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
+    <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
+    <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
+    <integer-array translatable="false" name="config_tether_upstream_types">
+        <item>1</item>
+        <item>4</item>
+    </integer-array>
 
     <!-- String containing the apn value for tethering.  May be overriden by secure settings
          TETHER_DUN_APN.  Value is a comma separated series of strings:
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index deade5e..99b72ad 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -118,6 +118,9 @@
 
     // The language code for this media
     kKeyMediaLanguage     = 'lang',  // cstring
+
+    // To store the timed text format data
+    kKeyTextFormatData    = 'text',  // raw data
 };
 
 enum {
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index afab26a..e43f6e5 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -101,8 +101,14 @@
     }
     mBitmapResources.clear();
 
+    for (size_t i = 0; i < mFilterResources.size(); i++) {
+        caches.resourceCache.decrementRefcount(mFilterResources.itemAt(i));
+    }
+    mFilterResources.clear();
+
     for (size_t i = 0; i < mShaders.size(); i++) {
         caches.resourceCache.decrementRefcount(mShaders.itemAt(i));
+        caches.resourceCache.destructor(mShaders.itemAt(i));
     }
     mShaders.clear();
 
@@ -151,11 +157,18 @@
         caches.resourceCache.incrementRefcount(resource);
     }
 
+    const Vector<SkiaColorFilter*> &filterResources = recorder.getFilterResources();
+    for (size_t i = 0; i < filterResources.size(); i++) {
+        SkiaColorFilter* resource = filterResources.itemAt(i);
+        mFilterResources.add(resource);
+        caches.resourceCache.incrementRefcount(resource);
+    }
+
     const Vector<SkiaShader*> &shaders = recorder.getShaders();
     for (size_t i = 0; i < shaders.size(); i++) {
-        SkiaShader* shader = shaders.itemAt(i);
-        mShaders.add(shader);
-        caches.resourceCache.incrementRefcount(shader);
+        SkiaShader* resource = shaders.itemAt(i);
+        mShaders.add(resource);
+        caches.resourceCache.incrementRefcount(resource);
     }
 
     const Vector<SkPaint*> &paints = recorder.getPaints();
@@ -873,21 +886,27 @@
 
     Caches& caches = Caches::getInstance();
     for (size_t i = 0; i < mBitmapResources.size(); i++) {
-        SkBitmap* resource = mBitmapResources.itemAt(i);
-        caches.resourceCache.decrementRefcount(resource);
+        caches.resourceCache.decrementRefcount(mBitmapResources.itemAt(i));
     }
     mBitmapResources.clear();
 
+    for (size_t i = 0; i < mFilterResources.size(); i++) {
+        caches.resourceCache.decrementRefcount(mFilterResources.itemAt(i));
+    }
+    mFilterResources.clear();
+
     for (size_t i = 0; i < mShaders.size(); i++) {
-       caches.resourceCache.decrementRefcount(mShaders.itemAt(i));
+        caches.resourceCache.decrementRefcount(mShaders.itemAt(i));
     }
     mShaders.clear();
     mShaderMap.clear();
 
     mPaints.clear();
     mPaintMap.clear();
+
     mPaths.clear();
     mPathMap.clear();
+
     mMatrices.clear();
 }
 
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index dcf2cf2..b83259f 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -292,6 +292,10 @@
         return mBitmapResources;
     }
 
+    const Vector<SkiaColorFilter*>& getFilterResources() const {
+        return mFilterResources;
+    }
+
     const Vector<SkiaShader*>& getShaders() const {
         return mShaders;
     }
@@ -308,10 +312,6 @@
         return mMatrices;
     }
 
-    const Vector<SkiaColorFilter*>& getFilterResources() const {
-        return mFilterResources;
-    }
-
 private:
     void insertRestoreToCount() {
         if (mRestoreSaveCount >= 0) {
@@ -419,7 +419,9 @@
     inline void addMatrix(SkMatrix* matrix) {
         // Copying the matrix is cheap and prevents against the user changing the original
         // matrix before the operation that uses it
-        addInt((int) new SkMatrix(*matrix));
+        SkMatrix* copy = new SkMatrix(*matrix);
+        addInt((int) copy);
+        mMatrices.add(copy);
     }
 
     inline void addBitmap(SkBitmap* bitmap) {
@@ -429,8 +431,7 @@
         // which doesn't seem worth the extra cycles for this unlikely case.
         addInt((int) bitmap);
         mBitmapResources.add(bitmap);
-        Caches& caches = Caches::getInstance();
-        caches.resourceCache.incrementRefcount(bitmap);
+        Caches::getInstance().resourceCache.incrementRefcount(bitmap);
     }
 
     inline void addShader(SkiaShader* shader) {
@@ -454,8 +455,7 @@
     inline void addColorFilter(SkiaColorFilter* colorFilter) {
         addInt((int) colorFilter);
         mFilterResources.add(colorFilter);
-        Caches& caches = Caches::getInstance();
-        caches.resourceCache.incrementRefcount(colorFilter);
+        Caches::getInstance().resourceCache.incrementRefcount(colorFilter);
     }
 
     Vector<SkBitmap*> mBitmapResources;
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index 9aade51..cd2c405 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -48,9 +48,6 @@
 
 void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) {
     Mutex::Autolock _l(mLock);
-    for (size_t i = 0; i < mCache->size(); ++i) {
-        void* ref = mCache->valueAt(i);
-    }
     ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
     if (ref == NULL || mCache->size() == 0) {
         ref = new ResourceReference(resourceType);
@@ -144,7 +141,6 @@
     ref->destroyed = true;
     if (ref->refCount == 0) {
         deleteResourceReference(resource, ref);
-        return;
     }
 }
 
@@ -162,7 +158,6 @@
     ref->destroyed = true;
     if (ref->refCount == 0) {
         deleteResourceReference(resource, ref);
-        return;
     }
 }
 
@@ -180,7 +175,6 @@
     ref->destroyed = true;
     if (ref->refCount == 0) {
         deleteResourceReference(resource, ref);
-        return;
     }
 }
 
@@ -195,7 +189,6 @@
     ref->destroyed = true;
     if (ref->refCount == 0) {
         deleteResourceReference(resource, ref);
-        return;
     }
 }
 
@@ -209,36 +202,32 @@
     }
     if (ref->destroyed) {
         switch (ref->resourceType) {
-            case kBitmap:
-            {
-                SkBitmap* bitmap = (SkBitmap*)resource;
+            case kBitmap: {
+                SkBitmap* bitmap = (SkBitmap*) resource;
                 if (Caches::hasInstance()) {
                     Caches::getInstance().textureCache.removeDeferred(bitmap);
                 }
                 delete bitmap;
             }
             break;
-            case kPath:
-            {
-                SkPath* path = (SkPath*)resource;
+            case kPath: {
+                SkPath* path = (SkPath*) resource;
                 if (Caches::hasInstance()) {
                     Caches::getInstance().pathCache.removeDeferred(path);
                 }
                 delete path;
             }
             break;
-            case kShader:
-            {
-                SkiaShader* shader = (SkiaShader*)resource;
+            case kShader: {
+                SkiaShader* shader = (SkiaShader*) resource;
                 if (Caches::hasInstance()) {
                     Caches::getInstance().gradientCache.removeDeferred(shader->getSkShader());
                 }
                 delete shader;
             }
             break;
-            case kColorFilter:
-            {
-                SkiaColorFilter* filter = (SkiaColorFilter*)resource;
+            case kColorFilter: {
+                SkiaColorFilter* filter = (SkiaColorFilter*) resource;
                 delete filter;
             }
             break;
diff --git a/libs/hwui/SkiaColorFilter.h b/libs/hwui/SkiaColorFilter.h
index bf45e13..1bf475c 100644
--- a/libs/hwui/SkiaColorFilter.h
+++ b/libs/hwui/SkiaColorFilter.h
@@ -59,7 +59,7 @@
         return mType;
     }
 
-    SkColorFilter *getSkColorFilter() {
+    SkColorFilter* getSkColorFilter() {
         return mSkFilter;
     }
 
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 2557730..33312d1 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1568,7 +1568,14 @@
                 return;
             case MEDIA_TIMED_TEXT:
                 if (mOnTimedTextListener != null) {
-                    mOnTimedTextListener.onTimedText(mMediaPlayer, (String)msg.obj);
+                    if (msg.obj == null) {
+                        mOnTimedTextListener.onTimedText(mMediaPlayer, null);
+                    } else {
+                        if (msg.obj instanceof byte[]) {
+                            TimedText text = new TimedText((byte[])(msg.obj));
+                            mOnTimedTextListener.onTimedText(mMediaPlayer, text);
+                        }
+                    }
                 }
                 return;
 
@@ -1755,14 +1762,14 @@
     public interface OnTimedTextListener
     {
         /**
-         * Called to indicate the video size
+         * Called to indicate an avaliable timed text
          *
          * @param mp             the MediaPlayer associated with this callback
-         * @param text           the timed text sample which contains the
-         *                       text needed to be displayed.
+         * @param text           the timed text sample which contains the text
+         *                       needed to be displayed and the display format.
          * {@hide}
          */
-        public void onTimedText(MediaPlayer mp, String text);
+        public void onTimedText(MediaPlayer mp, TimedText text);
     }
 
     /**
diff --git a/media/java/android/media/TimedText.java b/media/java/android/media/TimedText.java
new file mode 100644
index 0000000..a055c8b
--- /dev/null
+++ b/media/java/android/media/TimedText.java
@@ -0,0 +1,655 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.os.Parcel;
+import android.util.Log;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Class to hold the timed text's metadata.
+ *
+ * {@hide}
+ */
+public class TimedText
+{
+    private static final int FIRST_PUBLIC_KEY                 = 1;
+
+    // These keys must be in sync with the keys in TextDescription.h
+    public static final int KEY_DISPLAY_FLAGS                 = 1; // int
+    public static final int KEY_STYLE_FLAGS                   = 2; // int
+    public static final int KEY_BACKGROUND_COLOR_RGBA         = 3; // int
+    public static final int KEY_HIGHLIGHT_COLOR_RGBA          = 4; // int
+    public static final int KEY_SCROLL_DELAY                  = 5; // int
+    public static final int KEY_WRAP_TEXT                     = 6; // int
+    public static final int KEY_START_TIME                    = 7; // int
+    public static final int KEY_STRUCT_BLINKING_TEXT_LIST     = 8; // List<CharPos>
+    public static final int KEY_STRUCT_FONT_LIST              = 9; // List<Font>
+    public static final int KEY_STRUCT_HIGHLIGHT_LIST         = 10; // List<CharPos>
+    public static final int KEY_STRUCT_HYPER_TEXT_LIST        = 11; // List<HyperText>
+    public static final int KEY_STRUCT_KARAOKE_LIST           = 12; // List<Karaoke>
+    public static final int KEY_STRUCT_STYLE_LIST             = 13; // List<Style>
+    public static final int KEY_STRUCT_TEXT_POS               = 14; // TextPos
+    public static final int KEY_STRUCT_JUSTIFICATION          = 15; // Justification
+    public static final int KEY_STRUCT_TEXT                   = 16; // Text
+
+    private static final int LAST_PUBLIC_KEY                  = 16;
+
+    private static final int FIRST_PRIVATE_KEY                = 101;
+
+    // The following keys are used between TimedText.java and
+    // TextDescription.cpp in order to parce the Parcel.
+    private static final int KEY_GLOBAL_SETTING               = 101;
+    private static final int KEY_LOCAL_SETTING                = 102;
+    private static final int KEY_START_CHAR                   = 103;
+    private static final int KEY_END_CHAR                     = 104;
+    private static final int KEY_FONT_ID                      = 105;
+    private static final int KEY_FONT_SIZE                    = 106;
+    private static final int KEY_TEXT_COLOR_RGBA              = 107;
+
+    private static final int LAST_PRIVATE_KEY                 = 107;
+
+    private static final String TAG = "TimedText";
+
+    private Parcel mParcel = Parcel.obtain();
+    private final HashMap<Integer, Object> mKeyObjectMap =
+            new HashMap<Integer, Object>();
+
+    private int mDisplayFlags = -1;
+    private int mBackgroundColorRGBA = -1;
+    private int mHighlightColorRGBA = -1;
+    private int mScrollDelay = -1;
+    private int mWrapText = -1;
+
+    private List<CharPos> mBlinkingPosList = null;
+    private List<CharPos> mHighlightPosList = null;
+    private List<Karaoke> mKaraokeList = null;
+    private List<Font> mFontList = null;
+    private List<Style> mStyleList = null;
+    private List<HyperText> mHyperTextList = null;
+
+    private TextPos mTextPos;
+    private Justification mJustification;
+    private Text mTextStruct;
+
+    /**
+     * Helper class to hold the text length and text content of
+     * one text sample. The member variables in this class are
+     * read-only.
+     */
+    public class Text {
+        /**
+         * The byte-count of this text sample
+         */
+        public int textLen;
+
+        /**
+         * The text sample
+         */
+        public byte[] text;
+
+        public Text() { }
+    }
+
+    /**
+     * Helper class to hold the start char offset and end char offset
+     * for Blinking Text or Highlight Text. endChar is the end offset
+     * of the text (startChar + number of characters to be highlighted
+     * or blinked). The member variables in this class are read-only.
+     */
+    public class CharPos {
+        /**
+         * The offset of the start character
+         */
+        public int startChar = -1;
+
+        /**
+         * The offset of the end character
+         */
+        public int endChar = -1;
+
+        public CharPos() { }
+    }
+
+    /**
+     * Helper class to hold the box position to display the text sample.
+     * The member variables in this class are read-only.
+     */
+    public class TextPos {
+        /**
+         * The top position of the text
+         */
+        public int top = -1;
+
+        /**
+         * The left position of the text
+         */
+        public int left = -1;
+
+        /**
+         * The bottom position of the text
+         */
+        public int bottom = -1;
+
+        /**
+         * The right position of the text
+         */
+        public int right = -1;
+
+        public TextPos() { }
+    }
+
+    /**
+     * Helper class to hold the justification for text display in the text box.
+     * The member variables in this class are read-only.
+     */
+    public class Justification {
+        /**
+         * horizontalJustification  0: left, 1: centered, -1: right
+         */
+        public int horizontalJustification = -1;
+
+        /**
+         * verticalJustification  0: top, 1: centered, -1: bottom
+         */
+        public int verticalJustification = -1;
+
+        public Justification() { }
+    }
+
+    /**
+     * Helper class to hold the style information to display the text.
+     * The member variables in this class are read-only.
+     */
+    public class Style {
+        /**
+         * The offset of the start character which applys this style
+         */
+        public int startChar = -1;
+
+        /**
+         * The offset of the end character which applys this style
+         */
+        public int endChar = -1;
+
+        /**
+         * ID of the font. This ID will be used to choose the font
+         * to be used from the font list.
+         */
+        public int fontID = -1;
+
+        /**
+         * True if the characters should be bold
+         */
+        public boolean isBold = false;
+
+        /**
+         * True if the characters should be italic
+         */
+        public boolean isItalic = false;
+
+        /**
+         * True if the characters should be underlined
+         */
+        public boolean isUnderlined = false;
+
+        /**
+         * The size of the font
+         */
+        public int fontSize = -1;
+
+        /**
+         * To specify the RGBA color: 8 bits each of red, green, blue,
+         * and an alpha(transparency) value
+         */
+        public int colorRGBA = -1;
+
+        public Style() { }
+    }
+
+    /**
+     * Helper class to hold the font ID and name.
+     * The member variables in this class are read-only.
+     */
+    public class Font {
+        /**
+         * The font ID
+         */
+        public int ID = -1;
+
+        /**
+         * The font name
+         */
+        public String name;
+
+        public Font() { }
+    }
+
+    /**
+     * Helper class to hold the karaoke information.
+     * The member variables in this class are read-only.
+     */
+    public class Karaoke {
+        /**
+         * The start time (in milliseconds) to highlight the characters
+         * specified by startChar and endChar.
+         */
+        public int startTimeMs = -1;
+
+        /**
+         * The end time (in milliseconds) to highlight the characters
+         * specified by startChar and endChar.
+         */
+        public int endTimeMs = -1;
+
+        /**
+         * The offset of the start character to be highlighted
+         */
+        public int startChar = -1;
+
+        /**
+         * The offset of the end character to be highlighted
+         */
+        public int endChar = -1;
+
+        public Karaoke() { }
+    }
+
+    /**
+     * Helper class to hold the hyper text information.
+     * The member variables in this class are read-only.
+     */
+    public class HyperText {
+        /**
+         * The offset of the start character
+         */
+        public int startChar = -1;
+
+        /**
+         * The offset of the end character
+         */
+        public int endChar = -1;
+
+        /**
+         * The linked-to URL
+         */
+        public String URL;
+
+        /**
+         * The "alt" string for user display
+         */
+        public String altString;
+
+        public HyperText() { }
+    }
+
+    /**
+     * @param obj the byte array which contains the timed text.
+     * @throws IllegalArgumentExcept if parseParcel() fails.
+     * {@hide}
+     */
+    public TimedText(byte[] obj) {
+        mParcel.unmarshall(obj, 0, obj.length);
+
+        if (!parseParcel()) {
+            mKeyObjectMap.clear();
+            throw new IllegalArgumentException("parseParcel() fails");
+        }
+    }
+
+    /**
+     * Go over all the records, collecting metadata keys and fields in the
+     * Parcel. These are stored in mKeyObjectMap for application to retrieve.
+     * @return false if an error occurred during parsing. Otherwise, true.
+     */
+    private boolean parseParcel() {
+        mParcel.setDataPosition(0);
+        if (mParcel.dataAvail() == 0) {
+            return false;
+        }
+
+        int type = mParcel.readInt();
+        if (type == KEY_LOCAL_SETTING) {
+            type = mParcel.readInt();
+            if (type != KEY_START_TIME) {
+                return false;
+            }
+            int mStartTimeMs = mParcel.readInt();
+            mKeyObjectMap.put(type, mStartTimeMs);
+
+            type = mParcel.readInt();
+            if (type != KEY_STRUCT_TEXT) {
+                return false;
+            }
+
+            mTextStruct = new Text();
+            mTextStruct.textLen = mParcel.readInt();
+
+            mTextStruct.text = mParcel.createByteArray();
+            mKeyObjectMap.put(type, mTextStruct);
+
+        } else if (type != KEY_GLOBAL_SETTING) {
+            Log.w(TAG, "Invalid timed text key found: " + type);
+            return false;
+        }
+
+        while (mParcel.dataAvail() > 0) {
+            int key = mParcel.readInt();
+            if (!isValidKey(key)) {
+                Log.w(TAG, "Invalid timed text key found: " + key);
+                return false;
+            }
+
+            Object object = null;
+
+            switch (key) {
+                case KEY_STRUCT_STYLE_LIST: {
+                    readStyle();
+                    object = mStyleList;
+                    break;
+                }
+                case KEY_STRUCT_FONT_LIST: {
+                    readFont();
+                    object = mFontList;
+                    break;
+                }
+                case KEY_STRUCT_HIGHLIGHT_LIST: {
+                    readHighlight();
+                    object = mHighlightPosList;
+                    break;
+                }
+                case KEY_STRUCT_KARAOKE_LIST: {
+                    readKaraoke();
+                    object = mKaraokeList;
+                    break;
+                }
+                case KEY_STRUCT_HYPER_TEXT_LIST: {
+                    readHyperText();
+                    object = mHyperTextList;
+
+                    break;
+                }
+                case KEY_STRUCT_BLINKING_TEXT_LIST: {
+                    readBlinkingText();
+                    object = mBlinkingPosList;
+
+                    break;
+                }
+                case KEY_WRAP_TEXT: {
+                    mWrapText = mParcel.readInt();
+                    object = mWrapText;
+                    break;
+                }
+                case KEY_HIGHLIGHT_COLOR_RGBA: {
+                    mHighlightColorRGBA = mParcel.readInt();
+                    object = mHighlightColorRGBA;
+                    break;
+                }
+                case KEY_DISPLAY_FLAGS: {
+                    mDisplayFlags = mParcel.readInt();
+                    object = mDisplayFlags;
+                    break;
+                }
+                case KEY_STRUCT_JUSTIFICATION: {
+                    mJustification = new Justification();
+
+                    mJustification.horizontalJustification = mParcel.readInt();
+                    mJustification.verticalJustification = mParcel.readInt();
+
+                    object = mJustification;
+                    break;
+                }
+                case KEY_BACKGROUND_COLOR_RGBA: {
+                    mBackgroundColorRGBA = mParcel.readInt();
+                    object = mBackgroundColorRGBA;
+                    break;
+                }
+                case KEY_STRUCT_TEXT_POS: {
+                    mTextPos = new TextPos();
+
+                    mTextPos.top = mParcel.readInt();
+                    mTextPos.left = mParcel.readInt();
+                    mTextPos.bottom = mParcel.readInt();
+                    mTextPos.right = mParcel.readInt();
+
+                    object = mTextPos;
+                    break;
+                }
+                case KEY_SCROLL_DELAY: {
+                    mScrollDelay = mParcel.readInt();
+                    object = mScrollDelay;
+                    break;
+                }
+                default: {
+                    break;
+                }
+            }
+
+            if (object != null) {
+                if (mKeyObjectMap.containsKey(key)) {
+                    mKeyObjectMap.remove(key);
+                }
+                mKeyObjectMap.put(key, object);
+            }
+        }
+
+        mParcel.recycle();
+        return true;
+    }
+
+    /**
+     * To parse and store the Style list.
+     */
+    private void readStyle() {
+        Style style = new Style();
+        boolean endOfStyle = false;
+
+        while (!endOfStyle && (mParcel.dataAvail() > 0)) {
+            int key = mParcel.readInt();
+            switch (key) {
+                case KEY_START_CHAR: {
+                    style.startChar = mParcel.readInt();
+                    break;
+                }
+                case KEY_END_CHAR: {
+                    style.endChar = mParcel.readInt();
+                    break;
+                }
+                case KEY_FONT_ID: {
+                    style.fontID = mParcel.readInt();
+                    break;
+                }
+                case KEY_STYLE_FLAGS: {
+                    int flags = mParcel.readInt();
+                    // In the absence of any bits set in flags, the text
+                    // is plain. Otherwise, 1: bold, 2: italic, 4: underline
+                    style.isBold = ((flags % 2) == 1);
+                    style.isItalic = ((flags % 4) >= 2);
+                    style.isUnderlined = ((flags / 4) == 1);
+                    break;
+                }
+                case KEY_FONT_SIZE: {
+                    style.fontSize = mParcel.readInt();
+                    break;
+                }
+                case KEY_TEXT_COLOR_RGBA: {
+                    style.colorRGBA = mParcel.readInt();
+                    break;
+                }
+                default: {
+                    // End of the Style parsing. Reset the data position back
+                    // to the position before the last mParcel.readInt() call.
+                    mParcel.setDataPosition(mParcel.dataPosition() - 4);
+                    endOfStyle = true;
+                    break;
+                }
+            }
+        }
+
+        if (mStyleList == null) {
+            mStyleList = new ArrayList<Style>();
+        }
+        mStyleList.add(style);
+    }
+
+    /**
+     * To parse and store the Font list
+     */
+    private void readFont() {
+        int entryCount = mParcel.readInt();
+
+        for (int i = 0; i < entryCount; i++) {
+            Font font = new Font();
+
+            font.ID = mParcel.readInt();
+            int nameLen = mParcel.readInt();
+
+            byte[] text = mParcel.createByteArray();
+            font.name = new String(text, 0, nameLen);
+
+            if (mFontList == null) {
+                mFontList = new ArrayList<Font>();
+            }
+            mFontList.add(font);
+        }
+    }
+
+    /**
+     * To parse and store the Highlight list
+     */
+    private void readHighlight() {
+        CharPos pos = new CharPos();
+
+        pos.startChar = mParcel.readInt();
+        pos.endChar = mParcel.readInt();
+
+        if (mHighlightPosList == null) {
+            mHighlightPosList = new ArrayList<CharPos>();
+        }
+        mHighlightPosList.add(pos);
+    }
+
+    /**
+     * To parse and store the Karaoke list
+     */
+    private void readKaraoke() {
+        int entryCount = mParcel.readInt();
+
+        for (int i = 0; i < entryCount; i++) {
+            Karaoke kara = new Karaoke();
+
+            kara.startTimeMs = mParcel.readInt();
+            kara.endTimeMs = mParcel.readInt();
+            kara.startChar = mParcel.readInt();
+            kara.endChar = mParcel.readInt();
+
+            if (mKaraokeList == null) {
+                mKaraokeList = new ArrayList<Karaoke>();
+            }
+            mKaraokeList.add(kara);
+        }
+    }
+
+    /**
+     * To parse and store HyperText list
+     */
+    private void readHyperText() {
+        HyperText hyperText = new HyperText();
+
+        hyperText.startChar = mParcel.readInt();
+        hyperText.endChar = mParcel.readInt();
+
+        int len = mParcel.readInt();
+        byte[] url = mParcel.createByteArray();
+        hyperText.URL = new String(url, 0, len);
+
+        len = mParcel.readInt();
+        byte[] alt = mParcel.createByteArray();
+        hyperText.altString = new String(alt, 0, len);
+
+        if (mHyperTextList == null) {
+            mHyperTextList = new ArrayList<HyperText>();
+        }
+        mHyperTextList.add(hyperText);
+    }
+
+    /**
+     * To parse and store blinking text list
+     */
+    private void readBlinkingText() {
+        CharPos blinkingPos = new CharPos();
+
+        blinkingPos.startChar = mParcel.readInt();
+        blinkingPos.endChar = mParcel.readInt();
+
+        if (mBlinkingPosList == null) {
+            mBlinkingPosList = new ArrayList<CharPos>();
+        }
+        mBlinkingPosList.add(blinkingPos);
+    }
+
+    /**
+     * To check whether the given key is valid.
+     * @param key the key to be checked.
+     * @return true if the key is a valid one. Otherwise, false.
+     */
+    public boolean isValidKey(final int key) {
+        if (!((key >= FIRST_PUBLIC_KEY) && (key <= LAST_PUBLIC_KEY))
+                && !((key >= FIRST_PRIVATE_KEY) && (key <= LAST_PRIVATE_KEY))) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * To check whether the given key is contained in this TimedText object.
+     * @param key the key to be checked.
+     * @return true if the key is contained in this TimedText object.
+     *         Otherwise, false.
+     */
+    public boolean containsKey(final int key) {
+        if (isValidKey(key) && mKeyObjectMap.containsKey(key)) {
+            return true;
+        }
+        return false;
+    }
+    /**
+     * @return a set of the keys contained in this TimedText object.
+     */
+    public Set keySet() {
+        return mKeyObjectMap.keySet();
+    }
+
+    /**
+     * To retrieve the object associated with the key. Caller must make sure
+     * the key is present using the containsKey method otherwise a
+     * RuntimeException will occur.
+     * @param key the key used to retrieve the object.
+     * @return an object. The object could be an instanceof Integer, List, or
+     * any of the helper classes such as TextPos, Justification, and Text.
+     */
+    public Object getObject(final int key) {
+        if (containsKey(key)) {
+            return mKeyObjectMap.get(key);
+        } else {
+            throw new IllegalArgumentException("Invalid key: " + key);
+        }
+    }
+}
diff --git a/media/java/android/media/videoeditor/VideoEditorImpl.java b/media/java/android/media/videoeditor/VideoEditorImpl.java
index 2105deb..649b98a 100755
--- a/media/java/android/media/videoeditor/VideoEditorImpl.java
+++ b/media/java/android/media/videoeditor/VideoEditorImpl.java
@@ -38,6 +38,7 @@
 import android.graphics.Rect;
 import android.media.videoeditor.MediaImageItem;
 import android.media.videoeditor.MediaItem;
+import android.media.MediaMetadataRetriever;
 import android.util.Log;
 import android.util.Xml;
 import android.view.Surface;
@@ -1833,12 +1834,32 @@
             }
 
             Bitmap projectBitmap = null;
-            try {
-                projectBitmap = mI.getThumbnail(width, height, 500);
-            } catch (IllegalArgumentException e) {
-                throw new IllegalArgumentException ("Illegal argument error creating project thumbnail");
-            } catch (IOException e) {
-                throw new IllegalArgumentException ("IO Error creating project thumbnail");
+            String filename = mI.getFilename();
+            if (mI instanceof MediaVideoItem) {
+                MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+                retriever.setDataSource(filename);
+                Bitmap bitmap = retriever.getFrameAtTime();
+                retriever.release();
+                retriever = null;
+                if (bitmap == null) {
+                    String msg = "Thumbnail extraction from " +
+                                    filename + " failed";
+                    throw new IllegalArgumentException(msg);
+                }
+                // Resize the thumbnail to the target size
+                projectBitmap =
+                    Bitmap.createScaledBitmap(bitmap, width, height, true);
+            } else {
+                try {
+                    projectBitmap = mI.getThumbnail(width, height, 500);
+                } catch (IllegalArgumentException e) {
+                    String msg = "Project thumbnail extraction from " +
+                                    filename + " failed";
+                    throw new IllegalArgumentException(msg);
+                } catch (IOException e) {
+                    String msg = "IO Error creating project thumbnail";
+                    throw new IllegalArgumentException(msg);
+                }
             }
 
             try {
diff --git a/media/jni/mediaeditor/VideoEditorClasses.cpp b/media/jni/mediaeditor/VideoEditorClasses.cpp
index 5696433..d43a562 100755
--- a/media/jni/mediaeditor/VideoEditorClasses.cpp
+++ b/media/jni/mediaeditor/VideoEditorClasses.cpp
@@ -144,6 +144,7 @@
     VIDEOEDIT_JAVA_CONSTANT_INIT("MP3",         M4VIDEOEDITING_kFileType_MP3),
     VIDEOEDIT_JAVA_CONSTANT_INIT("PCM",         M4VIDEOEDITING_kFileType_PCM),
     VIDEOEDIT_JAVA_CONSTANT_INIT("JPG",         M4VIDEOEDITING_kFileType_JPG),
+    VIDEOEDIT_JAVA_CONSTANT_INIT("PNG",         M4VIDEOEDITING_kFileType_PNG),
     VIDEOEDIT_JAVA_CONSTANT_INIT("M4V",         M4VIDEOEDITING_kFileType_M4V),
     VIDEOEDIT_JAVA_CONSTANT_INIT("UNSUPPORTED", M4VIDEOEDITING_kFileType_Unsupported)
 };
@@ -1394,8 +1395,8 @@
             pSettings->FileType = (M4VIDEOEDITING_FileType)videoEditJava_getClipTypeJavaToC(
                                         &converted, pEnv->GetIntField(object, fieldIds.fileType));
 
-            if ( pSettings->FileType == M4VIDEOEDITING_kFileType_JPG)
-            {
+            if (( pSettings->FileType == M4VIDEOEDITING_kFileType_JPG) ||
+                 ( pSettings->FileType == M4VIDEOEDITING_kFileType_PNG)) {
                  pSettings->FileType = M4VIDEOEDITING_kFileType_ARGB8888;
             }
 
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 5fe511f..5582f92 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -889,11 +889,17 @@
             uint32_t entry_count = U32_AT(&buffer[4]);
 
             if (entry_count > 1) {
-                // For now we only support a single type of media per track.
-
-                mLastTrack->skipTrack = true;
-                *offset += chunk_size;
-                break;
+                // For 3GPP timed text, there could be multiple tx3g boxes contain
+                // multiple text display formats. These formats will be used to
+                // display the timed text.
+                const char *mime;
+                CHECK(mLastTrack->meta->findCString(kKeyMIMEType, &mime));
+                if (strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
+                    // For now we only support a single type of media per track.
+                    mLastTrack->skipTrack = true;
+                    *offset += chunk_size;
+                    break;
+                }
             }
 
             off64_t stop_offset = *offset + chunk_size;
@@ -1324,9 +1330,53 @@
             return parseDrmSINF(offset, data_offset);
         }
 
+        case FOURCC('h', 'd', 'l', 'r'):
+        {
+            uint32_t buffer;
+            if (mDataSource->readAt(
+                        data_offset + 8, &buffer, 4) < 4) {
+                return ERROR_IO;
+            }
+
+            uint32_t type = ntohl(buffer);
+            // For the 3GPP file format, the handler-type within the 'hdlr' box
+            // shall be 'text'
+            if (type == FOURCC('t', 'e', 'x', 't')) {
+                mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP);
+            }
+
+            *offset += chunk_size;
+            break;
+        }
+
         case FOURCC('t', 'x', '3', 'g'):
         {
-            mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP);
+            uint32_t type;
+            const void *data;
+            size_t size = 0;
+            if (!mLastTrack->meta->findData(
+                    kKeyTextFormatData, &type, &data, &size)) {
+                size = 0;
+            }
+
+            uint8_t *buffer = new uint8_t[size + chunk_size];
+
+            if (size > 0) {
+                memcpy(buffer, data, size);
+            }
+
+            if ((size_t)(mDataSource->readAt(*offset, buffer + size, chunk_size))
+                    < chunk_size) {
+                delete[] buffer;
+                buffer = NULL;
+
+                return ERROR_IO;
+            }
+
+            mLastTrack->meta->setData(
+                    kKeyTextFormatData, 0, buffer, size + chunk_size);
+
+            delete[] buffer;
 
             *offset += chunk_size;
             break;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index ea9911c..f075699d 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -205,6 +205,8 @@
     // Duration is time scale based
     void addOneSttsTableEntry(size_t sampleCount, int32_t timescaledDur);
     void addOneCttsTableEntry(size_t sampleCount, int32_t timescaledDur);
+
+    bool isTrackMalFormed() const;
     void sendTrackSummary(bool hasMultipleTracks);
 
     // Write the boxes
@@ -1975,7 +1977,6 @@
         }
 
         CHECK(timestampUs >= 0);
-
         LOGV("%s media time stamp: %lld and previous paused duration %lld",
                 mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs);
         if (timestampUs > mTrackDurationUs) {
@@ -2082,11 +2083,10 @@
 
     }
 
-    if (mSampleSizes.empty() ||                      // no samples written
-        (!mIsAudio && mNumStssTableEntries == 0) ||  // no sync frames for video
-        (OK != checkCodecSpecificData())) {          // no codec specific data
+    if (isTrackMalFormed()) {
         err = ERROR_MALFORMED;
     }
+
     mOwner->trackProgressStatus(mTrackId, -1, err);
 
     // Last chunk
@@ -2136,6 +2136,24 @@
     return err;
 }
 
+bool MPEG4Writer::Track::isTrackMalFormed() const {
+    if (mSampleSizes.empty()) {                      // no samples written
+        LOGE("The number of recorded samples is 0");
+        return true;
+    }
+
+    if (!mIsAudio && mNumStssTableEntries == 0) {  // no sync frames for video
+        LOGE("There are no sync frames for video track");
+        return true;
+    }
+
+    if (OK != checkCodecSpecificData()) {         // no codec specific data
+        return true;
+    }
+
+    return false;
+}
+
 void MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) {
 
     // Send track summary only if test mode is enabled.
diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk
index 9a6062c..59d0e15 100644
--- a/media/libstagefright/timedtext/Android.mk
+++ b/media/libstagefright/timedtext/Android.mk
@@ -2,6 +2,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=                 \
+        TextDescriptions.cpp      \
         TimedTextParser.cpp       \
         TimedTextPlayer.cpp
 
diff --git a/media/libstagefright/timedtext/TextDescriptions.cpp b/media/libstagefright/timedtext/TextDescriptions.cpp
new file mode 100644
index 0000000..f9c1fe0
--- /dev/null
+++ b/media/libstagefright/timedtext/TextDescriptions.cpp
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2011 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 "TextDescriptions.h"
+#include <media/stagefright/Utils.h>
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+TextDescriptions::TextDescriptions() {
+}
+
+status_t TextDescriptions::getParcelOfDescriptions(
+        const uint8_t *data, ssize_t size,
+        uint32_t flags, int timeMs, Parcel *parcel) {
+    parcel->freeData();
+
+    if (flags & IN_BAND_TEXT_3GPP) {
+        if (flags & GLOBAL_DESCRIPTIONS) {
+            return extract3GPPGlobalDescriptions(data, size, parcel, 0);
+        } else if (flags & LOCAL_DESCRIPTIONS) {
+            return extract3GPPLocalDescriptions(data, size, timeMs, parcel, 0);
+        }
+    } else if (flags & OUT_OF_BAND_TEXT_SRT) {
+        if (flags & LOCAL_DESCRIPTIONS) {
+            return extractSRTLocalDescriptions(data, size, timeMs, parcel);
+        }
+    }
+
+    return ERROR_UNSUPPORTED;
+}
+
+// Parse the SRT text sample, and store the timing and text sample in a Parcel.
+// The Parcel will be sent to MediaPlayer.java through event, and will be
+// parsed in TimedText.java.
+status_t TextDescriptions::extractSRTLocalDescriptions(
+        const uint8_t *data, ssize_t size, int timeMs, Parcel *parcel) {
+    parcel->writeInt32(KEY_LOCAL_SETTING);
+    parcel->writeInt32(KEY_START_TIME);
+    parcel->writeInt32(timeMs);
+
+    parcel->writeInt32(KEY_STRUCT_TEXT);
+    // write the size of the text sample
+    parcel->writeInt32(size);
+    // write the text sample as a byte array
+    parcel->writeInt32(size);
+    parcel->write(data, size);
+
+    return OK;
+}
+
+// Extract the local 3GPP display descriptions. 3GPP local descriptions
+// are appended to the text sample if any. The descriptions could include
+// information such as text styles, highlights, karaoke and so on. They
+// are contained in different boxes, such as 'styl' box contains text
+// styles, and 'krok' box contains karaoke timing and positions.
+status_t TextDescriptions::extract3GPPLocalDescriptions(
+        const uint8_t *data, ssize_t size,
+        int timeMs, Parcel *parcel, int depth) {
+    if (depth == 0) {
+        parcel->writeInt32(KEY_LOCAL_SETTING);
+
+        // write start time to display this text sample
+        parcel->writeInt32(KEY_START_TIME);
+        parcel->writeInt32(timeMs);
+
+        ssize_t textLen = (*data) << 8 | (*(data + 1));
+
+        // write text sample length and text sample itself
+        parcel->writeInt32(KEY_STRUCT_TEXT);
+        parcel->writeInt32(textLen);
+        parcel->writeInt32(textLen);
+        parcel->write(data + 2, textLen);
+
+        if (size > textLen) {
+            data += (textLen + 2);
+            size -= (textLen + 2);
+        } else {
+            return OK;
+        }
+    }
+
+    const uint8_t *tmpData = data;
+    ssize_t chunkSize = U32_AT(tmpData);
+    uint32_t chunkType = U32_AT(tmpData + 4);
+
+    if (chunkSize <= 0) {
+        return OK;
+    }
+
+    tmpData += 8;
+
+    switch(chunkType) {
+        // 'styl' box specifies the style of the text.
+        case FOURCC('s', 't', 'y', 'l'):
+        {
+            uint16_t count = U16_AT(tmpData);
+
+            tmpData += 2;
+
+            for (int i = 0; i < count; i++) {
+                parcel->writeInt32(KEY_STRUCT_STYLE_LIST);
+                parcel->writeInt32(KEY_START_CHAR);
+                parcel->writeInt32(U16_AT(tmpData));
+
+                parcel->writeInt32(KEY_END_CHAR);
+                parcel->writeInt32(U16_AT(tmpData + 2));
+
+                parcel->writeInt32(KEY_FONT_ID);
+                parcel->writeInt32(U16_AT(tmpData + 4));
+
+                parcel->writeInt32(KEY_STYLE_FLAGS);
+                parcel->writeInt32(*(tmpData + 6));
+
+                parcel->writeInt32(KEY_FONT_SIZE);
+                parcel->writeInt32(*(tmpData + 7));
+
+                parcel->writeInt32(KEY_TEXT_COLOR_RGBA);
+                uint32_t rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16
+                    | *(tmpData + 10) << 8 | *(tmpData + 11);
+                parcel->writeInt32(rgba);
+
+                tmpData += 12;
+            }
+
+            break;
+        }
+        // 'krok' box. The number of highlight events is specified, and each
+        // event is specified by a starting and ending char offset and an end
+        // time for the event.
+        case FOURCC('k', 'r', 'o', 'k'):
+        {
+
+            parcel->writeInt32(KEY_STRUCT_KARAOKE_LIST);
+
+            int startTime = U32_AT(tmpData);
+            uint16_t count = U16_AT(tmpData + 4);
+            parcel->writeInt32(count);
+
+            tmpData += 6;
+            int lastEndTime = 0;
+
+            for (int i = 0; i < count; i++) {
+                parcel->writeInt32(startTime + lastEndTime);
+
+                lastEndTime = U32_AT(tmpData);
+                parcel->writeInt32(lastEndTime);
+
+                parcel->writeInt32(U16_AT(tmpData + 4));
+                parcel->writeInt32(U16_AT(tmpData + 6));
+
+                tmpData += 8;
+            }
+
+            break;
+        }
+        // 'hlit' box specifies highlighted text
+        case FOURCC('h', 'l', 'i', 't'):
+        {
+            parcel->writeInt32(KEY_STRUCT_HIGHLIGHT_LIST);
+
+            // the start char offset to highlight
+            parcel->writeInt32(U16_AT(tmpData));
+            // the last char offset to highlight
+            parcel->writeInt32(U16_AT(tmpData + 2));
+
+            break;
+        }
+        // 'hclr' box specifies the RGBA color: 8 bits each of
+        // red, green, blue, and an alpha(transparency) value
+        case FOURCC('h', 'c', 'l', 'r'):
+        {
+            parcel->writeInt32(KEY_HIGHLIGHT_COLOR_RGBA);
+
+            uint32_t rgba = *(tmpData) << 24 | *(tmpData + 1) << 16
+                | *(tmpData + 2) << 8 | *(tmpData + 3);
+            parcel->writeInt32(rgba);
+
+            break;
+        }
+        // 'dlay' box specifies a delay after a scroll in and/or
+        // before scroll out.
+        case FOURCC('d', 'l', 'a', 'y'):
+        {
+            parcel->writeInt32(KEY_SCROLL_DELAY);
+
+            uint32_t delay = *(tmpData) << 24 | *(tmpData + 1) << 16
+                | *(tmpData + 2) << 8 | *(tmpData + 3);
+            parcel->writeInt32(delay);
+
+            break;
+        }
+        // 'href' box for hyper text link
+        case FOURCC('h', 'r', 'e', 'f'):
+        {
+            parcel->writeInt32(KEY_STRUCT_HYPER_TEXT_LIST);
+
+            // the start offset of the text to be linked
+            parcel->writeInt32(U16_AT(tmpData));
+            // the end offset of the text
+            parcel->writeInt32(U16_AT(tmpData + 2));
+
+            // the number of bytes in the following URL
+            int len = *(tmpData + 4);
+            parcel->writeInt32(len);
+
+            // the linked-to URL
+            parcel->writeInt32(len);
+            parcel->write(tmpData + 5, len);
+
+            tmpData += (5 + len);
+
+            // the number of bytes in the following "alt" string
+            len = *tmpData;
+            parcel->writeInt32(len);
+
+            // an "alt" string for user display
+            parcel->writeInt32(len);
+            parcel->write(tmpData + 1, len);
+
+            break;
+        }
+        // 'tbox' box to indicate the position of the text with values
+        // of top, left, bottom and right
+        case FOURCC('t', 'b', 'o', 'x'):
+        {
+            parcel->writeInt32(KEY_STRUCT_TEXT_POS);
+            parcel->writeInt32(U16_AT(tmpData));
+            parcel->writeInt32(U16_AT(tmpData + 2));
+            parcel->writeInt32(U16_AT(tmpData + 4));
+            parcel->writeInt32(U16_AT(tmpData + 6));
+
+            break;
+        }
+        // 'blnk' to specify the char range to be blinked
+        case FOURCC('b', 'l', 'n', 'k'):
+        {
+            parcel->writeInt32(KEY_STRUCT_BLINKING_TEXT_LIST);
+
+            // start char offset
+            parcel->writeInt32(U16_AT(tmpData));
+            // end char offset
+            parcel->writeInt32(U16_AT(tmpData + 2));
+
+            break;
+        }
+        // 'twrp' box specifies text wrap behavior. If the value if 0x00,
+        // then no wrap. If it's 0x01, then automatic 'soft' wrap is enabled.
+        // 0x02-0xff are reserved.
+        case FOURCC('t', 'w', 'r', 'p'):
+        {
+            parcel->writeInt32(KEY_WRAP_TEXT);
+            parcel->writeInt32(*tmpData);
+
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+
+    if (size > chunkSize) {
+        data += chunkSize;
+        size -= chunkSize;
+        // continue to parse next box
+        return extract3GPPLocalDescriptions(data, size, 0, parcel, 1);
+    }
+
+    return OK;
+}
+
+// To extract box 'tx3g' defined in 3GPP TS 26.245, and store it in a Parcel
+status_t TextDescriptions::extract3GPPGlobalDescriptions(
+        const uint8_t *data, ssize_t size, Parcel *parcel, int depth) {
+
+    ssize_t chunkSize = U32_AT(data);
+    uint32_t chunkType = U32_AT(data + 4);
+    const uint8_t *tmpData = data;
+    tmpData += 8;
+
+    if (size < chunkSize) {
+        return OK;
+    }
+
+    if (depth == 0) {
+        parcel->writeInt32(KEY_GLOBAL_SETTING);
+    }
+    switch(chunkType) {
+        case FOURCC('t', 'x', '3', 'g'):
+        {
+            tmpData += 8; // skip the first 8 bytes
+            parcel->writeInt32(KEY_DISPLAY_FLAGS);
+            parcel->writeInt32(U32_AT(tmpData));
+
+            parcel->writeInt32(KEY_STRUCT_JUSTIFICATION);
+            parcel->writeInt32(tmpData[4]);
+            parcel->writeInt32(tmpData[5]);
+
+            parcel->writeInt32(KEY_BACKGROUND_COLOR_RGBA);
+            uint32_t rgba = *(tmpData + 6) << 24 | *(tmpData + 7) << 16
+                | *(tmpData + 8) << 8 | *(tmpData + 9);
+            parcel->writeInt32(rgba);
+
+            tmpData += 10;
+            parcel->writeInt32(KEY_STRUCT_TEXT_POS);
+            parcel->writeInt32(U16_AT(tmpData));
+            parcel->writeInt32(U16_AT(tmpData + 2));
+            parcel->writeInt32(U16_AT(tmpData + 4));
+            parcel->writeInt32(U16_AT(tmpData + 6));
+
+            tmpData += 8;
+            parcel->writeInt32(KEY_STRUCT_STYLE_LIST);
+            parcel->writeInt32(KEY_START_CHAR);
+            parcel->writeInt32(U16_AT(tmpData));
+
+            parcel->writeInt32(KEY_END_CHAR);
+            parcel->writeInt32(U16_AT(tmpData + 2));
+
+            parcel->writeInt32(KEY_FONT_ID);
+            parcel->writeInt32(U16_AT(tmpData + 4));
+
+            parcel->writeInt32(KEY_STYLE_FLAGS);
+            parcel->writeInt32(*(tmpData + 6));
+
+            parcel->writeInt32(KEY_FONT_SIZE);
+            parcel->writeInt32(*(tmpData + 7));
+
+            parcel->writeInt32(KEY_TEXT_COLOR_RGBA);
+            rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16
+                | *(tmpData + 10) << 8 | *(tmpData + 11);
+            parcel->writeInt32(rgba);
+
+            tmpData += 12;
+            parcel->writeInt32(KEY_STRUCT_FONT_LIST);
+            uint16_t count = U16_AT(tmpData);
+            parcel->writeInt32(count);
+
+            tmpData += 2;
+            for (int i = 0; i < count; i++) {
+                // font ID
+                parcel->writeInt32(U16_AT(tmpData));
+
+                // font name length
+                parcel->writeInt32(*(tmpData + 2));
+
+                int len = *(tmpData + 2);
+
+                parcel->write(tmpData + 3, len);
+                tmpData += 3 + len;
+            }
+
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+
+    data += chunkSize;
+    size -= chunkSize;
+
+    if (size > 0) {
+        // continue to extract next 'tx3g'
+        return extract3GPPGlobalDescriptions(data, size, parcel, 1);
+    }
+
+    return OK;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/timedtext/TextDescriptions.h b/media/libstagefright/timedtext/TextDescriptions.h
new file mode 100644
index 0000000..01449175
--- /dev/null
+++ b/media/libstagefright/timedtext/TextDescriptions.h
@@ -0,0 +1,84 @@
+ /*
+ * Copyright (C) 2011 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 TEXT_DESCRIPTIONS_H_
+
+#define TEXT_DESCRIPTIONS_H_
+
+#include <binder/Parcel.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+class TextDescriptions {
+public:
+    enum {
+        IN_BAND_TEXT_3GPP             = 0x01,
+        OUT_OF_BAND_TEXT_SRT          = 0x02,
+
+        GLOBAL_DESCRIPTIONS           = 0x100,
+        LOCAL_DESCRIPTIONS            = 0x200,
+    };
+
+    static status_t getParcelOfDescriptions(
+            const uint8_t *data, ssize_t size,
+            uint32_t flags, int timeMs, Parcel *parcel);
+private:
+    TextDescriptions();
+
+    enum {
+        // These keys must be in sync with the keys in TimedText.java
+        KEY_DISPLAY_FLAGS                 = 1, // int
+        KEY_STYLE_FLAGS                   = 2, // int
+        KEY_BACKGROUND_COLOR_RGBA         = 3, // int
+        KEY_HIGHLIGHT_COLOR_RGBA          = 4, // int
+        KEY_SCROLL_DELAY                  = 5, // int
+        KEY_WRAP_TEXT                     = 6, // int
+        KEY_START_TIME                    = 7, // int
+        KEY_STRUCT_BLINKING_TEXT_LIST     = 8, // List<CharPos>
+        KEY_STRUCT_FONT_LIST              = 9, // List<Font>
+        KEY_STRUCT_HIGHLIGHT_LIST         = 10, // List<CharPos>
+        KEY_STRUCT_HYPER_TEXT_LIST        = 11, // List<HyperText>
+        KEY_STRUCT_KARAOKE_LIST           = 12, // List<Karaoke>
+        KEY_STRUCT_STYLE_LIST             = 13, // List<Style>
+        KEY_STRUCT_TEXT_POS               = 14, // TextPos
+        KEY_STRUCT_JUSTIFICATION          = 15, // Justification
+        KEY_STRUCT_TEXT                   = 16, // Text
+
+        KEY_GLOBAL_SETTING                = 101,
+        KEY_LOCAL_SETTING                 = 102,
+        KEY_START_CHAR                    = 103,
+        KEY_END_CHAR                      = 104,
+        KEY_FONT_ID                       = 105,
+        KEY_FONT_SIZE                     = 106,
+        KEY_TEXT_COLOR_RGBA               = 107,
+    };
+
+    static status_t extractSRTLocalDescriptions(
+            const uint8_t *data, ssize_t size,
+            int timeMs, Parcel *parcel);
+    static status_t extract3GPPGlobalDescriptions(
+            const uint8_t *data, ssize_t size,
+            Parcel *parcel, int depth);
+    static status_t extract3GPPLocalDescriptions(
+            const uint8_t *data, ssize_t size,
+            int timeMs, Parcel *parcel, int depth);
+
+    DISALLOW_EVIL_CONSTRUCTORS(TextDescriptions);
+};
+
+}  // namespace android
+#endif  // TEXT_DESCRIPTIONS_H_
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp
index 50bb16d..7c8a747 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.cpp
+++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp
@@ -19,6 +19,7 @@
 #include <utils/Log.h>
 
 #include <binder/IPCThreadState.h>
+
 #include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
@@ -27,9 +28,11 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/Utils.h>
+
 #include "include/AwesomePlayer.h"
 #include "TimedTextPlayer.h"
 #include "TimedTextParser.h"
+#include "TextDescriptions.h"
 
 namespace android {
 
@@ -92,10 +95,11 @@
         return BAD_VALUE;
     }
 
+    status_t err;
     if (index < mTextTrackVector.size()) { // start an in-band text
         mSource = mTextTrackVector.itemAt(index);
 
-        status_t err = mSource->start();
+        err = mSource->start();
 
         if (err != OK) {
             return err;
@@ -112,13 +116,17 @@
             mTextParser = new TimedTextParser();
         }
 
-        status_t err;
         if ((err = mTextParser->init(mOutOfBandSource, fileType)) != OK) {
             return err;
         }
         mTextType = kOutOfBandText;
     }
 
+    // send sample description format
+    if ((err = extractAndSendGlobalDescriptions()) != OK) {
+        return err;
+    }
+
     int64_t positionUs;
     mObserver->getPosition(&positionUs);
     seekTo(positionUs);
@@ -211,21 +219,17 @@
     }
     mTextEventPending = false;
 
+    if (mData.dataSize() > 0) {
+        notifyListener(MEDIA_TIMED_TEXT, &mData);
+        mData.freeData();
+    }
+
     MediaSource::ReadOptions options;
     if (mSeeking) {
         options.setSeekTo(mSeekTimeUs,
                 MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
         mSeeking = false;
 
-        if (mTextType == kInBandText) {
-            if (mTextBuffer != NULL) {
-                mTextBuffer->release();
-                mTextBuffer = NULL;
-            }
-        } else {
-            mText.clear();
-        }
-
         notifyListener(MEDIA_TIMED_TEXT); //empty text to clear the screen
     }
 
@@ -233,32 +237,12 @@
     mObserver->getPosition(&positionUs);
 
     if (mTextType == kInBandText) {
-        if (mTextBuffer != NULL) {
-            uint8_t *tmp = (uint8_t *)(mTextBuffer->data());
-            size_t len = (*tmp) << 8 | (*(tmp + 1));
-
-            notifyListener(MEDIA_TIMED_TEXT,
-                           tmp + 2,
-                           len);
-
-            mTextBuffer->release();
-            mTextBuffer = NULL;
-
-        }
-
         if (mSource->read(&mTextBuffer, &options) != OK) {
             return;
         }
 
         mTextBuffer->meta_data()->findInt64(kKeyTime, &timeUs);
     } else {
-        if (mText.size() > 0) {
-            notifyListener(MEDIA_TIMED_TEXT,
-                           mText.c_str(),
-                           mText.size());
-            mText.clear();
-        }
-
         int64_t endTimeUs;
         if (mTextParser->getText(
                     &mText, &timeUs, &endTimeUs, &options) != OK) {
@@ -266,6 +250,19 @@
         }
     }
 
+    if (timeUs > 0) {
+        extractAndAppendLocalDescriptions(timeUs);
+    }
+
+    if (mTextType == kInBandText) {
+        if (mTextBuffer != NULL) {
+            mTextBuffer->release();
+            mTextBuffer = NULL;
+        }
+    } else {
+        mText.clear();
+    }
+
     //send the text now
     if (timeUs <= positionUs + 100000ll) {
         postTextEvent();
@@ -297,7 +294,8 @@
     Mutex::Autolock autoLock(mLock);
 
     if (key == KEY_PARAMETER_TIMED_TEXT_ADD_OUT_OF_BAND_SOURCE) {
-        String8 uri = request.readString8();
+        const String16 uri16 = request.readString16();
+        String8 uri = String8(uri16);
         KeyedVector<String8, String8> headers;
 
         // To support local subtitle file only for now
@@ -327,21 +325,92 @@
     return INVALID_OPERATION;
 }
 
-void TimedTextPlayer::notifyListener(
-        int msg, const void *data, size_t size) {
+void TimedTextPlayer::notifyListener(int msg, const Parcel *parcel) {
     if (mListener != NULL) {
         sp<MediaPlayerBase> listener = mListener.promote();
 
         if (listener != NULL) {
-            if (size > 0) {
-                mData.freeData();
-                mData.write(data, size);
-
-                listener->sendEvent(msg, 0, 0, &mData);
+            if (parcel && (parcel->dataSize() > 0)) {
+                listener->sendEvent(msg, 0, 0, parcel);
             } else { // send an empty timed text to clear the screen
                 listener->sendEvent(msg);
             }
         }
     }
 }
+
+// Each text sample consists of a string of text, optionally with sample
+// modifier description. The modifier description could specify a new
+// text style for the string of text. These descriptions are present only
+// if they are needed. This method is used to extract the modifier
+// description and append it at the end of the text.
+status_t TimedTextPlayer::extractAndAppendLocalDescriptions(int64_t timeUs) {
+    const void *data;
+    size_t size = 0;
+    int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS;
+
+    if (mTextType == kInBandText) {
+        const char *mime;
+        CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
+
+        if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
+            flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
+            data = mTextBuffer->data();
+            size = mTextBuffer->size();
+        } else {
+            // support 3GPP only for now
+            return ERROR_UNSUPPORTED;
+        }
+    } else {
+        data = mText.c_str();
+        size = mText.size();
+        flag |= TextDescriptions::OUT_OF_BAND_TEXT_SRT;
+    }
+
+    if ((size > 0) && (flag != TextDescriptions::LOCAL_DESCRIPTIONS)) {
+        mData.freeData();
+        return TextDescriptions::getParcelOfDescriptions(
+                (const uint8_t *)data, size, flag, timeUs / 1000, &mData);
+    }
+
+    return OK;
+}
+
+// To extract and send the global text descriptions for all the text samples
+// in the text track or text file.
+status_t TimedTextPlayer::extractAndSendGlobalDescriptions() {
+    const void *data;
+    size_t size = 0;
+    int32_t flag = TextDescriptions::GLOBAL_DESCRIPTIONS;
+
+    if (mTextType == kInBandText) {
+        const char *mime;
+        CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
+
+        // support 3GPP only for now
+        if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
+            uint32_t type;
+            // get the 'tx3g' box content. This box contains the text descriptions
+            // used to render the text track
+            if (!mSource->getFormat()->findData(
+                        kKeyTextFormatData, &type, &data, &size)) {
+                return ERROR_MALFORMED;
+            }
+
+            flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
+        }
+    }
+
+    if ((size > 0) && (flag != TextDescriptions::GLOBAL_DESCRIPTIONS)) {
+        Parcel parcel;
+        if (TextDescriptions::getParcelOfDescriptions(
+                (const uint8_t *)data, size, flag, 0, &parcel) == OK) {
+            if (parcel.dataSize() > 0) {
+                notifyListener(MEDIA_TIMED_TEXT, &parcel);
+            }
+        }
+    }
+
+    return OK;
+}
 }
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.h b/media/libstagefright/timedtext/TimedTextPlayer.h
index 590760b..a744db5 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.h
+++ b/media/libstagefright/timedtext/TimedTextPlayer.h
@@ -103,8 +103,10 @@
     void postTextEvent(int64_t delayUs = -1);
     void cancelTextEvent();
 
-    void notifyListener(
-            int msg, const void *data = NULL, size_t size = 0);
+    void notifyListener(int msg, const Parcel *parcel = NULL);
+
+    status_t extractAndAppendLocalDescriptions(int64_t timeUs);
+    status_t extractAndSendGlobalDescriptions();
 
     DISALLOW_EVIL_CONSTRUCTORS(TimedTextPlayer);
 };
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java
index 187a486..60906a1 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java
@@ -1,93 +1,96 @@
-/*

- * Copyright (C) 2011 The Android Open Source Project

- *

- * Licensed under the Apache License, Version 2.0 (the "License");

- * you may not use this file except in compliance with the License.

- * You may obtain a copy of the License at

- *

- *      http://www.apache.org/licenses/LICENSE-2.0

- *

- * Unless required by applicable law or agreed to in writing, software

- * distributed under the License is distributed on an "AS IS" BASIS,

- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

- * See the License for the specific language governing permissions and

- * limitations under the License.

- */

-

-package com.android.systemui.usb;

-

-import android.app.Activity;

-import android.app.AlertDialog;

-import android.content.Context;

-import android.content.DialogInterface;

-import android.hardware.usb.UsbManager;

-import android.os.Bundle;

-import android.view.LayoutInflater;

-import android.view.View;

-import android.util.Log;

-import android.widget.Button;

-

-import java.io.File;

-

-import com.android.systemui.R;

-

-public class UsbPreferenceActivity extends Activity implements View.OnClickListener  {

-

-    private static final String TAG = "UsbPreferenceActivity";

-

-    private UsbManager mUsbManager;

-    private String mCurrentFunction;

-    private String[] mFunctions;

-    private String mInstallerImagePath;

-    private Button mMtpPtpButton;

-    private Button mInstallerCdButton;

-    private boolean mPtpActive;

-

-    @Override

-    public void onCreate(Bundle icicle) {

-        super.onCreate(icicle);

-

-        mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);

-

-        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);

-        dialogBuilder.setTitle(getString(R.string.usb_preference_title));

-

-        LayoutInflater inflater = (LayoutInflater)getSystemService(

-                Context.LAYOUT_INFLATER_SERVICE);

-        View buttonView = inflater.inflate(R.layout.usb_preference_buttons, null);

-        dialogBuilder.setView(buttonView);

-        mMtpPtpButton = (Button)buttonView.findViewById(R.id.mtp_ptp_button);

-        mInstallerCdButton = (Button)buttonView.findViewById(R.id.installer_cd_button);

-        mMtpPtpButton.setOnClickListener(this);

-        mInstallerCdButton.setOnClickListener(this);

-

-        mPtpActive = mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_PTP);

-        if (mPtpActive) {

-            mMtpPtpButton.setText(R.string.use_mtp_button_title);

-        }

-

-        mInstallerImagePath = getString(com.android.internal.R.string.config_isoImagePath);

-        if (!(new File(mInstallerImagePath)).exists()) {

-            mInstallerCdButton.setVisibility(View.GONE);

-        }

-

-        dialogBuilder.show();

-    }

-

-    public void onClick(View v) {

-        if (v.equals(mMtpPtpButton)) {

-            if (mPtpActive) {

-                mUsbManager.setPrimaryFunction(UsbManager.USB_FUNCTION_MTP);

-                mUsbManager.setDefaultFunction(UsbManager.USB_FUNCTION_MTP);

-            } else {

-                mUsbManager.setPrimaryFunction(UsbManager.USB_FUNCTION_PTP);

-                mUsbManager.setDefaultFunction(UsbManager.USB_FUNCTION_PTP);

-            }

-        } else if (v.equals(mInstallerCdButton)) {

-            mUsbManager.setPrimaryFunction(UsbManager.USB_FUNCTION_MASS_STORAGE);

-            mUsbManager.setMassStorageBackingFile(mInstallerImagePath);

-        }

-

+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.usb;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.util.Log;
+import android.widget.Button;
+
+import java.io.File;
+
+import com.android.systemui.R;
+
+public class UsbPreferenceActivity extends Activity implements View.OnClickListener  {
+
+    private static final String TAG = "UsbPreferenceActivity";
+
+    private UsbManager mUsbManager;
+    private String mCurrentFunction;
+    private String[] mFunctions;
+    private String mInstallerImagePath;
+    private AlertDialog mDialog;
+    private Button mMtpPtpButton;
+    private Button mInstallerCdButton;
+    private boolean mPtpActive;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
+
+        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
+        dialogBuilder.setTitle(getString(R.string.usb_preference_title));
+
+        LayoutInflater inflater = (LayoutInflater)getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+        View buttonView = inflater.inflate(R.layout.usb_preference_buttons, null);
+        dialogBuilder.setView(buttonView);
+        mMtpPtpButton = (Button)buttonView.findViewById(R.id.mtp_ptp_button);
+        mInstallerCdButton = (Button)buttonView.findViewById(R.id.installer_cd_button);
+        mMtpPtpButton.setOnClickListener(this);
+        mInstallerCdButton.setOnClickListener(this);
+
+        mPtpActive = mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_PTP);
+        if (mPtpActive) {
+            mMtpPtpButton.setText(R.string.use_mtp_button_title);
+        }
+
+        mInstallerImagePath = getString(com.android.internal.R.string.config_isoImagePath);
+        if (!(new File(mInstallerImagePath)).exists()) {
+            mInstallerCdButton.setVisibility(View.GONE);
+        }
+
+        mDialog = dialogBuilder.show();
+    }
+
+    public void onClick(View v) {
+        if (v.equals(mMtpPtpButton)) {
+            if (mPtpActive) {
+                mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MTP, true);
+            } else {
+                mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_PTP, true);
+            }
+        } else if (v.equals(mInstallerCdButton)) {
+            // installer CD is never default
+            mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MASS_STORAGE, false);
+            mUsbManager.setMassStorageBackingFile(mInstallerImagePath);
+        }
+
+        if (mDialog != null) {
+            mDialog.dismiss();
+        }
         finish();

-    }

-}

+    }
+}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 75f466a..baa4ec3 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -498,6 +498,7 @@
             return;
         }
 
+        int width = WRAP_CONTENT;
         if (st.decorView == null || st.refreshDecorView) {
             if (st.decorView == null) {
                 // Initialize the panel decor, this will populate st.decorView
@@ -523,6 +524,7 @@
                 // If the contents is fill parent for the width, set the
                 // corresponding background
                 backgroundResId = st.fullBackground;
+                width = MATCH_PARENT;
             } else {
                 // Otherwise, set the normal panel background
                 backgroundResId = st.background;
@@ -546,7 +548,7 @@
         st.isHandled = false;
 
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                WRAP_CONTENT, WRAP_CONTENT,
+                width, WRAP_CONTENT,
                 st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG,
                 WindowManager.LayoutParams.FLAG_DITHER
                 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index aa3dfa6..e6f443a 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -466,12 +466,10 @@
         INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b);
 
         mTethering = new Tethering(mContext, nmService, mHandler.getLooper());
-        mTetheringConfigValid = (((mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] != null) ||
-                                  !mTethering.isDunRequired()) &&
-                                 (mTethering.getTetherableUsbRegexs().length != 0 ||
+        mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 ||
                                   mTethering.getTetherableWifiRegexs().length != 0 ||
                                   mTethering.getTetherableBluetoothRegexs().length != 0) &&
-                                 mTethering.getUpstreamIfaceRegexs().length != 0);
+                                 mTethering.getUpstreamIfaceTypes().length != 0);
 
         mVpn = new Vpn(mContext, new VpnCallback());
 
@@ -1576,12 +1574,6 @@
                 }
                 addPrivateDnsRoutes(mNetTrackers[netType]);
             }
-
-            /** Notify TetheringService if interface name has been changed. */
-            if (TextUtils.equals(mNetTrackers[netType].getNetworkInfo().getReason(),
-                                 Phone.REASON_LINK_PROPERTIES_CHANGED)) {
-                handleTetherIfaceChange(netType);
-            }
         } else {
             if (mNetConfigs[netType].isDefault()) {
                 removeDefaultRoute(mNetTrackers[netType]);
@@ -2412,14 +2404,6 @@
         }
     }
 
-    private void handleTetherIfaceChange(int type) {
-        String iface = mNetTrackers[type].getLinkProperties().getInterfaceName();
-
-        if (isTetheringSupported()) {
-            mTethering.handleTetherIfaceChange(iface);
-        }
-    }
-
     private void log(String s) {
         Slog.d(TAG, s);
     }
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index a9dfb22..f6dd43a 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -32,6 +32,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.database.ContentObserver;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Handler;
@@ -814,6 +815,8 @@
 
         final AtomicInteger mInteractionIdCounter = new AtomicInteger();
 
+        final Rect mTempBounds = new Rect();
+
         // the events pending events to be dispatched to this service
         final SparseArray<AccessibilityEvent> mPendingEvents =
             new SparseArray<AccessibilityEvent>();
@@ -932,9 +935,10 @@
                 AccessibilityNodeInfo info = mCallback.getFindAccessibilityNodeInfoResultAndClear(
                         interactionId);
                 if (info != null) {
+                    applyCompatibilityScaleIfNeeded(info);
                     info.setConnection(this);
+                    info.setSealed(true);
                 }
-                info.setSealed(true);
                 return info;
             } catch (RemoteException re) {
                 if (DEBUG) {
@@ -979,6 +983,7 @@
                     final int infoCount = infos.size();
                     for (int i = 0; i < infoCount; i++) {
                         AccessibilityNodeInfo info = infos.get(i);
+                        applyCompatibilityScaleIfNeeded(info);
                         info.setConnection(this);
                         info.setSealed(true);
                     }
@@ -1019,6 +1024,7 @@
                 AccessibilityNodeInfo info =
                      mCallback.getFindAccessibilityNodeInfoResultAndClear(interactionId);
                 if (info != null) {
+                    applyCompatibilityScaleIfNeeded(info);
                     info.setConnection(this);
                     info.setSealed(true);
                 }
@@ -1093,6 +1099,24 @@
             }
             return mWindowIdToInteractionConnectionMap.get(windowId);
         }
+
+        private void applyCompatibilityScaleIfNeeded(AccessibilityNodeInfo info) {
+            IBinder windowToken = mWindowIdToWindowTokenMap.get(info.getWindowId());
+            final float scale = mWindowManagerService.getWindowCompatibilityScale(windowToken);
+
+            if (scale == 1.0f) {
+                return;
+            }
+
+            Rect bounds = mTempBounds;
+            info.getBoundsInParent(bounds);
+            bounds.scale(scale);
+            info.setBoundsInParent(bounds);
+
+            info.getBoundsInScreen(bounds);
+            bounds.scale(scale);
+            info.setBoundsInScreen(bounds);
+        }
     }
 
     final class SecurityPolicy {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index d8772b8..b94ee58 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -73,7 +73,7 @@
  */
 final class ActivityStack {
     static final String TAG = ActivityManagerService.TAG;
-    static final boolean localLOGV = ActivityManagerService.localLOGV || true;
+    static final boolean localLOGV = ActivityManagerService.localLOGV;
     static final boolean DEBUG_SWITCH = ActivityManagerService.DEBUG_SWITCH;
     static final boolean DEBUG_PAUSE = ActivityManagerService.DEBUG_PAUSE;
     static final boolean DEBUG_VISBILITY = ActivityManagerService.DEBUG_VISBILITY;
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 15e67d0..911cac2 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -57,7 +57,9 @@
 import java.io.PrintWriter;
 import java.net.InetAddress;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.Set;
 /**
@@ -82,7 +84,15 @@
     private String[] mTetherableUsbRegexs;
     private String[] mTetherableWifiRegexs;
     private String[] mTetherableBluetoothRegexs;
-    private String[] mUpstreamIfaceRegexs;
+    private Collection<Integer> mUpstreamIfaceTypes;
+
+    private static final Integer MOBILE_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE);
+    private static final Integer HIPRI_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_HIPRI);
+    private static final Integer DUN_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_DUN);
+
+    // if we have to connect to mobile, what APN type should we use?  Calculated by examining the
+    // upstream type list and the DUN_REQUIRED secure-setting
+    private int mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_NONE;
 
     private INetworkManagementService mNMService;
     private Looper mLooper;
@@ -112,9 +122,6 @@
     private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
     private static final String DNS_DEFAULT_SERVER2 = "8.8.4.4";
 
-    // resampled each time we turn on tethering - used as cache for settings/config-val
-    private boolean mDunRequired;  // configuration info - must use DUN apn on 3g
-
     private StateMachine mTetherMasterSM;
 
     private Notification mTetheredNotification;
@@ -159,7 +166,6 @@
         if ((mDhcpRange.length == 0) || (mDhcpRange.length % 2 ==1)) {
             mDhcpRange = DHCP_DEFAULT_RANGE;
         }
-        mDunRequired = false; // resample when we turn on
 
         mTetherableUsbRegexs = context.getResources().getStringArray(
                 com.android.internal.R.array.config_tether_usb_regexs);
@@ -167,8 +173,15 @@
                 com.android.internal.R.array.config_tether_wifi_regexs);
         mTetherableBluetoothRegexs = context.getResources().getStringArray(
                 com.android.internal.R.array.config_tether_bluetooth_regexs);
-        mUpstreamIfaceRegexs = context.getResources().getStringArray(
-                com.android.internal.R.array.config_tether_upstream_regexs);
+        int ifaceTypes[] = context.getResources().getIntArray(
+                com.android.internal.R.array.config_tether_upstream_types);
+        mUpstreamIfaceTypes = new ArrayList();
+        for (int i : ifaceTypes) {
+            mUpstreamIfaceTypes.add(new Integer(i));
+        }
+
+        // check if the upstream type list needs to be modified due to secure-settings
+        checkDunRequired();
 
         // TODO - remove and rely on real notifications of the current iface
         mDnsServers = new String[2];
@@ -509,9 +522,9 @@
         }
         try {
             if (enabled) {
-                usbManager.setPrimaryFunction(UsbManager.USB_FUNCTION_RNDIS);
+                usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false);
             } else {
-                usbManager.setPrimaryFunction(null);
+                usbManager.setCurrentFunction(null, false);
             }
         } catch (Exception e) {
             Log.e(TAG, "Error toggling usb RNDIS", e);
@@ -582,16 +595,44 @@
         return mTetherableBluetoothRegexs;
     }
 
-    public String[] getUpstreamIfaceRegexs() {
-        return mUpstreamIfaceRegexs;
+    public int[] getUpstreamIfaceTypes() {
+        int values[] = new int[mUpstreamIfaceTypes.size()];
+        Iterator<Integer> iterator = mUpstreamIfaceTypes.iterator();
+        for (int i=0; i < mUpstreamIfaceTypes.size(); i++) {
+            values[i] = iterator.next();
+        }
+        return values;
     }
 
-    public boolean isDunRequired() {
-        boolean defaultVal = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_tether_dun_required);
-        boolean result = (Settings.Secure.getInt(mContext.getContentResolver(),
-                Settings.Secure.TETHER_DUN_REQUIRED, (defaultVal ? 1 : 0)) == 1);
-        return result;
+    public void checkDunRequired() {
+        int requiredApn = ((Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.TETHER_DUN_REQUIRED, 0) == 1) ?
+                ConnectivityManager.TYPE_MOBILE_DUN :
+                ConnectivityManager.TYPE_MOBILE_HIPRI);
+        if (mPreferredUpstreamMobileApn != requiredApn) {
+            if (requiredApn == ConnectivityManager.TYPE_MOBILE_DUN) {
+                while (mUpstreamIfaceTypes.contains(MOBILE_TYPE)) {
+                    mUpstreamIfaceTypes.remove(MOBILE_TYPE);
+                }
+                while (mUpstreamIfaceTypes.contains(HIPRI_TYPE)) {
+                    mUpstreamIfaceTypes.remove(HIPRI_TYPE);
+                }
+                if (mUpstreamIfaceTypes.contains(DUN_TYPE) == false) {
+                    mUpstreamIfaceTypes.add(DUN_TYPE);
+                }
+            } else {
+                while (mUpstreamIfaceTypes.contains(DUN_TYPE)) {
+                    mUpstreamIfaceTypes.remove(DUN_TYPE);
+                }
+                if (mUpstreamIfaceTypes.contains(MOBILE_TYPE) == false) {
+                    mUpstreamIfaceTypes.add(MOBILE_TYPE);
+                }
+                if (mUpstreamIfaceTypes.contains(HIPRI_TYPE) == false) {
+                    mUpstreamIfaceTypes.add(HIPRI_TYPE);
+                }
+            }
+            mPreferredUpstreamMobileApn = requiredApn;
+        }
     }
 
     public String[] getTetheredIfaces() {
@@ -648,17 +689,6 @@
         return retVal;
     }
 
-    public void handleTetherIfaceChange(String iface) {
-        // check if iface is white listed
-        for (String regex : mUpstreamIfaceRegexs) {
-            if (iface.matches(regex)) {
-                if (DEBUG) Log.d(TAG, "Tethering got Interface Change");
-                mTetherMasterSM.sendMessage(TetherMasterSM.CMD_IFACE_CHANGED, iface);
-                break;
-            }
-        }
-    }
-
     class TetherInterfaceSM extends StateMachine {
         // notification from the master SM that it's not in tether mode
         static final int CMD_TETHER_MODE_DEAD            =  1;
@@ -1051,8 +1081,6 @@
         static final int CMD_CELL_CONNECTION_RENEW   = 4;
         // we don't have a valid upstream conn, check again after a delay
         static final int CMD_RETRY_UPSTREAM          = 5;
-        // received an indication that upstream interface has changed
-        static final int CMD_IFACE_CHANGED           = 6;
 
         // This indicates what a timeout event relates to.  A state that
         // sends itself a delayed timeout event and handles incoming timeout events
@@ -1072,7 +1100,7 @@
         private ArrayList mNotifyList;
 
         private int mCurrentConnectionSequence;
-        private boolean mMobileReserved = false;
+        private int mMobileApnReserved = ConnectivityManager.TYPE_NONE;
 
         private String mUpstreamIfaceName = null;
 
@@ -1111,22 +1139,34 @@
             public boolean processMessage(Message m) {
                 return false;
             }
-            protected boolean turnOnMobileConnection() {
+            protected String enableString(int apnType) {
+                switch (apnType) {
+                case ConnectivityManager.TYPE_MOBILE_DUN:
+                    return Phone.FEATURE_ENABLE_DUN_ALWAYS;
+                case ConnectivityManager.TYPE_MOBILE:
+                case ConnectivityManager.TYPE_MOBILE_HIPRI:
+                    return Phone.FEATURE_ENABLE_HIPRI;
+                }
+                return null;
+            }
+            protected boolean turnOnUpstreamMobileConnection(int apnType) {
                 boolean retValue = true;
-                if (mMobileReserved) return retValue;
+                if (apnType == ConnectivityManager.TYPE_NONE) return false;
+                if (apnType != mMobileApnReserved) turnOffUpstreamMobileConnection();
                 IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
                 IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
                 int result = Phone.APN_REQUEST_FAILED;
+                String enableString = enableString(apnType);
+                if (enableString == null) return false;
                 try {
                     result = cm.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
-                            (mDunRequired ? Phone.FEATURE_ENABLE_DUN_ALWAYS :
-                            Phone.FEATURE_ENABLE_HIPRI), new Binder());
+                            enableString, new Binder());
                 } catch (Exception e) {
                 }
                 switch (result) {
                 case Phone.APN_ALREADY_ACTIVE:
                 case Phone.APN_REQUEST_STARTED:
-                    mMobileReserved = true;
+                    mMobileApnReserved = apnType;
                     Message m = obtainMessage(CMD_CELL_CONNECTION_RENEW);
                     m.arg1 = ++mCurrentConnectionSequence;
                     sendMessageDelayed(m, CELL_CONNECTION_RENEW_MS);
@@ -1139,18 +1179,17 @@
 
                 return retValue;
             }
-            protected boolean turnOffMobileConnection() {
-                if (mMobileReserved) {
+            protected boolean turnOffUpstreamMobileConnection() {
+                if (mMobileApnReserved != ConnectivityManager.TYPE_NONE) {
                     IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
                     IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
                     try {
                         cm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
-                                (mDunRequired? Phone.FEATURE_ENABLE_DUN_ALWAYS :
-                                             Phone.FEATURE_ENABLE_HIPRI));
+                                enableString(mMobileApnReserved));
                     } catch (Exception e) {
                         return false;
                     }
-                    mMobileReserved = false;
+                    mMobileApnReserved = ConnectivityManager.TYPE_NONE;
                 }
                 return true;
             }
@@ -1196,108 +1235,55 @@
                 transitionTo(mInitialState);
                 return true;
             }
-            protected String findActiveUpstreamIface() {
-                // check for what iface we can use - if none found switch to error.
-                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
-                IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
-
-                try {
-                    LinkProperties defaultProp = cm.getActiveLinkProperties();
-                    if (defaultProp != null) {
-                        String iface = defaultProp.getInterfaceName();
-                        for(String regex : mUpstreamIfaceRegexs) {
-                            if (iface.matches(regex)) return iface;
-                        }
-                    }
-                } catch (RemoteException e) { }
-
-                String[] ifaces = new String[0];
-                try {
-                    ifaces = mNMService.listInterfaces();
-                } catch (Exception e) {
-                    Log.e(TAG, "Error listing Interfaces", e);
-                    return null;
-                }
-
-                for (String regex : mUpstreamIfaceRegexs) {
-                    for (String iface : ifaces) {
-                        if (iface.matches(regex)) {
-                            // verify it is active
-                            InterfaceConfiguration ifcg = null;
-                            try {
-                                ifcg = mNMService.getInterfaceConfig(iface);
-                                if (ifcg.isActive()) {
-                                    return iface;
-                                }
-                            } catch (Exception e) {
-                                Log.e(TAG, "Error getting iface config", e);
-                                // ignore - try next
-                                continue;
-                            }
-                        }
-                    }
-                }
-                return null;
-            }
 
             protected void chooseUpstreamType(boolean tryCell) {
-                // decide if the current upstream is good or not and if not
-                // do something about it (start up DUN if required or HiPri if not)
-                String iface = findActiveUpstreamIface();
                 IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
                 IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
-                mMobileReserved = false;
-                if (DEBUG) {
-                    Log.d(TAG, "chooseUpstreamType(" + tryCell + "),  dunRequired ="
-                            + mDunRequired + ", iface=" + iface);
-                }
-                if (iface != null) {
+                int upType = ConnectivityManager.TYPE_NONE;
+                String iface = null;
+
+                for (Integer netType : mUpstreamIfaceTypes) {
+                    NetworkInfo info = null;
                     try {
-                        if (mDunRequired) {
-                            // check if Dun is on - we can use that
-                            NetworkInfo info = cm.getNetworkInfo(
-                                    ConnectivityManager.TYPE_MOBILE_DUN);
-                            if (info.isConnected()) {
-                                if (DEBUG) Log.d(TAG, "setting dun ifacename =" + iface);
-                                // even if we're already connected - it may be somebody else's
-                                // refcount, so add our own
-                                turnOnMobileConnection();
-                            } else {
-                                // verify the iface is not the default mobile - can't use that!
-                                info = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
-                                if (info.isConnected()) {
-                                    iface = null; // can't accept this one
-                                }
-                            }
-                        } else {
-                            if (DEBUG) Log.d(TAG, "checking if hipri brought us this connection");
-                            NetworkInfo info = cm.getNetworkInfo(
-                                    ConnectivityManager.TYPE_MOBILE_HIPRI);
-                            if (info.isConnected()) {
-                                if (DEBUG) Log.d(TAG, "yes - hipri in use");
-                                // even if we're already connected - it may be sombody else's
-                                // refcount, so add our own
-                                turnOnMobileConnection();
-                            }
-                        }
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "RemoteException calling ConnectivityManager", e);
-                        iface = null;
+                        info = cm.getNetworkInfo(netType.intValue());
+                    } catch (RemoteException e) { }
+                    if ((info != null) && info.isConnected()) {
+                        upType = netType.intValue();
+                        break;
                     }
                 }
-                // may have been set to null in the if above
-                if (iface == null ) {
-                    boolean success = false;
-                    if (tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) {
-                        success = turnOnMobileConnection();
+
+                if (DEBUG) {
+                    Log.d(TAG, "chooseUpstreamType(" + tryCell + "), preferredApn ="
+                            + mPreferredUpstreamMobileApn + ", got type=" + upType);
+                }
+
+                // if we're on DUN, put our own grab on it
+                if (upType == ConnectivityManager.TYPE_MOBILE_DUN ||
+                        upType == ConnectivityManager.TYPE_MOBILE_HIPRI) {
+                    turnOnUpstreamMobileConnection(upType);
+                }
+
+                if (upType == ConnectivityManager.TYPE_NONE) {
+                    boolean tryAgainLater = true;
+                    if ((tryCell == TRY_TO_SETUP_MOBILE_CONNECTION) &&
+                            (turnOnUpstreamMobileConnection(mPreferredUpstreamMobileApn) == true)) {
+                        // we think mobile should be coming up - don't set a retry
+                        tryAgainLater = false;
                     }
-                    if (!success) {
-                        // wait for things to settle and retry
+                    if (tryAgainLater) {
                         sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
                     }
+                } else {
+                    LinkProperties linkProperties = null;
+                    try {
+                        linkProperties = cm.getLinkProperties(upType);
+                    } catch (RemoteException e) { }
+                    if (linkProperties != null) iface = linkProperties.getInterfaceName();
                 }
                 notifyTetheredOfNewUpstreamIface(iface);
             }
+
             protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
                 if (DEBUG) Log.d(TAG, "notifying tethered with iface =" + ifaceName);
                 mUpstreamIfaceName = ifaceName;
@@ -1312,7 +1298,6 @@
         class InitialState extends TetherMasterUtilState {
             @Override
             public void enter() {
-                mMobileReserved = false;
             }
             @Override
             public boolean processMessage(Message message) {
@@ -1320,7 +1305,7 @@
                 boolean retValue = true;
                 switch (message.what) {
                     case CMD_TETHER_MODE_REQUESTED:
-                        mDunRequired = isDunRequired();
+                        checkDunRequired();
                         TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
                         if (DEBUG) Log.d(TAG, "Tether Mode requested by " + who.toString());
                         mNotifyList.add(who);
@@ -1354,7 +1339,7 @@
             }
             @Override
             public void exit() {
-                turnOffMobileConnection();
+                turnOffUpstreamMobileConnection();
                 notifyTetheredOfNewUpstreamIface(null);
             }
             @Override
@@ -1392,19 +1377,13 @@
                                 Log.d(TAG, "renewing mobile connection - requeuing for another " +
                                         CELL_CONNECTION_RENEW_MS + "ms");
                             }
-                            mMobileReserved = false; // need to renew it
-                            turnOnMobileConnection();
+                            turnOnUpstreamMobileConnection(mMobileApnReserved);
                         }
                         break;
                     case CMD_RETRY_UPSTREAM:
                         chooseUpstreamType(mTryCell);
                         mTryCell = !mTryCell;
                         break;
-                    case CMD_IFACE_CHANGED:
-                        String iface = (String)message.obj;
-                        if (DEBUG) Log.d(TAG, "Activie upstream interface changed: " + iface);
-                        notifyTetheredOfNewUpstreamIface(iface);
-                        break;
                     default:
                         retValue = false;
                         break;
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index b7f9d5c..918f1b6 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -77,9 +77,8 @@
 
     private static final int MSG_UPDATE_STATE = 0;
     private static final int MSG_ENABLE_ADB = 1;
-    private static final int MSG_SET_PRIMARY_FUNCTION = 2;
-    private static final int MSG_SET_DEFAULT_FUNCTION = 3;
-    private static final int MSG_SYSTEM_READY = 4;
+    private static final int MSG_SET_CURRENT_FUNCTION = 2;
+    private static final int MSG_SYSTEM_READY = 3;
 
     // Delay for debouncing USB disconnects.
     // We often get rapid connect/disconnect events when enabling USB functions,
@@ -227,7 +226,7 @@
                 mHandler.updateState(state);
             } else if ("START".equals(accessory)) {
                 Slog.d(TAG, "got accessory start");
-                setPrimaryFunction(UsbManager.USB_FUNCTION_ACCESSORY);
+                setCurrentFunction(UsbManager.USB_FUNCTION_ACCESSORY, false);
             }
         }
     };
@@ -371,6 +370,14 @@
             sendMessage(m);
         }
 
+        public void sendMessage(int what, Object arg0, boolean arg1) {
+            removeMessages(what);
+            Message m = Message.obtain(this, what);
+            m.obj = arg0;
+            m.arg1 = (arg1 ? 1 : 0);
+            sendMessage(m);
+        }
+
         public void updateState(String state) {
             int connected, configured;
 
@@ -395,24 +402,30 @@
             sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
         }
 
-        private boolean setUsbConfig(String config) {
-            // set the new configuration
-            SystemProperties.set("sys.usb.config", config);
+        private boolean waitForState(String state) {
             // wait for the transition to complete.
             // give up after 1 second.
             for (int i = 0; i < 20; i++) {
                 // State transition is done when sys.usb.conf.done is set to the new configuration
-                if (config.equals(SystemProperties.get("sys.usb.state"))) return true;
+                if (state.equals(SystemProperties.get("sys.usb.state"))) return true;
                 try {
                     // try again in 50ms
                     Thread.sleep(50);
                 } catch (InterruptedException e) {
                 }
             }
+            Log.e(TAG, "waitForState(" + state + ") FAILED");
             return false;
         }
 
-        private void setCurrentFunctions(String functions) {
+        private boolean setUsbConfig(String config) {
+            Log.d(TAG, "setUsbConfig(" + config + ")");
+            // set the new configuration
+            SystemProperties.set("sys.usb.config", config);
+            return waitForState(config);
+        }
+
+        private void doSetCurrentFunctions(String functions) {
             if (!mCurrentFunctions.equals(functions)) {
                 if (!setUsbConfig("none") || !setUsbConfig(functions)) {
                     Log.e(TAG, "Failed to switch USB configuration to " + functions);
@@ -428,17 +441,14 @@
             if (enable != mAdbEnabled) {
                 mAdbEnabled = enable;
                 String functions;
+                // Due to the persist.sys.usb.config property trigger, changing adb state requires
+                // switching to default function
                 if (enable) {
-                    functions = addFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
-                    mDefaultFunctions = addFunction(mDefaultFunctions,
-                            UsbManager.USB_FUNCTION_ADB);
+                    functions = addFunction(mDefaultFunctions, UsbManager.USB_FUNCTION_ADB);
                 } else {
-                    functions = removeFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
-                    mDefaultFunctions = removeFunction(mDefaultFunctions,
-                            UsbManager.USB_FUNCTION_ADB);
+                    functions = removeFunction(mDefaultFunctions, UsbManager.USB_FUNCTION_ADB);
                 }
-                SystemProperties.set("persist.sys.usb.config", mDefaultFunctions);
-                setCurrentFunctions(functions);
+                setCurrentFunction(functions, true);
                 updateAdbNotification(mAdbEnabled && mConnected);
             }
         }
@@ -449,7 +459,7 @@
             } else {
                 functionList = removeFunction(functionList, UsbManager.USB_FUNCTION_ADB);
             }
-            setCurrentFunctions(functionList);
+            doSetCurrentFunctions(functionList);
         }
 
         private void updateCurrentAccessory() {
@@ -503,8 +513,6 @@
 
         @Override
         public void handleMessage(Message msg) {
-            String function;
-
             switch (msg.what) {
                 case MSG_UPDATE_STATE:
                     mConnected = (msg.arg1 == 1);
@@ -518,7 +526,7 @@
 
                     if (!mConnected) {
                         // restore defaults when USB is disconnected
-                        setCurrentFunctions(mDefaultFunctions);
+                        doSetCurrentFunctions(mDefaultFunctions);
                     }
                     if (mSystemReady) {
                         updateUsbState();
@@ -527,20 +535,31 @@
                 case MSG_ENABLE_ADB:
                     setAdbEnabled(msg.arg1 == 1);
                     break;
-                case MSG_SET_PRIMARY_FUNCTION:
-                    function = (String)msg.obj;
-                    if (function == null) {
-                        function = mDefaultFunctions;
+                case MSG_SET_CURRENT_FUNCTION:
+                    String function = (String)msg.obj;
+                    boolean makeDefault = (msg.arg1 == 1);
+                    if (makeDefault) {
+                        if (function == null) {
+                            throw new NullPointerException();
+                        }
+                        if (mAdbEnabled) {
+                            function = addFunction(function, UsbManager.USB_FUNCTION_ADB);
+                        }
+
+                        setUsbConfig("none");
+                        // setting this property will change the current USB state
+                        // via a property trigger
+                        SystemProperties.set("persist.sys.usb.config", function);
+                        if (waitForState(function)) {
+                            mCurrentFunctions = function;
+                            mDefaultFunctions = function;
+                        }
+                    } else {
+                        if (function == null) {
+                            function = mDefaultFunctions;
+                        }
+                        setEnabledFunctions(function);
                     }
-                    setEnabledFunctions(function);
-                    break;
-                case MSG_SET_DEFAULT_FUNCTION:
-                    function = (String)msg.obj;
-                    if (mAdbEnabled) {
-                        function = addFunction(function, UsbManager.USB_FUNCTION_ADB);
-                    }
-                    SystemProperties.set("persist.sys.usb.config", function);
-                    mDefaultFunctions = function;
                     break;
                 case MSG_SYSTEM_READY:
                     updateUsbNotification(mConnected);
@@ -588,15 +607,8 @@
             return nativeOpenAccessory();
         }
 
-    public void setPrimaryFunction(String function) {
-        mHandler.sendMessage(MSG_SET_PRIMARY_FUNCTION, function);
-    }
-
-    public void setDefaultFunction(String function) {
-        if (function == null) {
-            throw new NullPointerException();
-        }
-        mHandler.sendMessage(MSG_SET_DEFAULT_FUNCTION, function);
+    public void setCurrentFunction(String function, boolean makeDefault) {
+        mHandler.sendMessage(MSG_SET_CURRENT_FUNCTION, function, makeDefault);
     }
 
     public void setMassStorageBackingFile(String path) {
diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java
index 193638f..9f2c17a 100644
--- a/services/java/com/android/server/usb/UsbService.java
+++ b/services/java/com/android/server/usb/UsbService.java
@@ -146,19 +146,10 @@
         mSettingsManager.clearDefaults(packageName);
     }
 
-    public void setPrimaryFunction(String function) {
+    public void setCurrentFunction(String function, boolean makeDefault) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
         if (mDeviceManager != null) {
-            mDeviceManager.setPrimaryFunction(function);
-        } else {
-            throw new IllegalStateException("USB device mode not supported");
-        }
-    }
-
-    public void setDefaultFunction(String function) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
-        if (mDeviceManager != null) {
-            mDeviceManager.setDefaultFunction(function);
+            mDeviceManager.setCurrentFunction(function, makeDefault);
         } else {
             throw new IllegalStateException("USB device mode not supported");
         }
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index 3be8af6..6806634 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import android.graphics.Rect;
+import android.os.Binder;
 import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
@@ -152,6 +153,8 @@
         }
         mUpdateInputWindowsNeeded = false;
 
+        if (false) Slog.d(WindowManagerService.TAG, ">>>>>> ENTERED updateInputWindowsLw");
+        
         // Populate the input window list with information about all of the windows that
         // could potentially receive input.
         // As an optimization, we could try to prune the list of windows but this turns
@@ -232,6 +235,8 @@
         // Clear the list in preparation for the next round.
         // Also avoids keeping InputChannel objects referenced unnecessarily.
         mTempInputWindows.clear();
+        
+        if (false) Slog.d(WindowManagerService.TAG, "<<<<<<< EXITED updateInputWindowsLw");
     }
 
     /* Notifies that the input device configuration has changed. */
diff --git a/services/java/com/android/server/wm/Session.java b/services/java/com/android/server/wm/Session.java
index 0f09356..50b251f 100644
--- a/services/java/com/android/server/wm/Session.java
+++ b/services/java/com/android/server/wm/Session.java
@@ -153,11 +153,13 @@
             int requestedWidth, int requestedHeight, int viewFlags,
             boolean insetsPending, Rect outFrame, Rect outContentInsets,
             Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
-        //Log.d(TAG, ">>>>>> ENTERED relayout from " + Binder.getCallingPid());
+        if (false) Slog.d(WindowManagerService.TAG, ">>>>>> ENTERED relayout from "
+                + Binder.getCallingPid());
         int res = mService.relayoutWindow(this, window, attrs,
                 requestedWidth, requestedHeight, viewFlags, insetsPending,
                 outFrame, outContentInsets, outVisibleInsets, outConfig, outSurface);
-        //Log.d(TAG, "<<<<<< EXITING relayout to " + Binder.getCallingPid());
+        if (false) Slog.d(WindowManagerService.TAG, "<<<<<< EXITING relayout to "
+                + Binder.getCallingPid());
         return res;
     }
 
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 1c87f5b..d62c031 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -2776,6 +2776,13 @@
         Binder.restoreCallingIdentity(origId);
     }
 
+    public float getWindowCompatibilityScale(IBinder windowToken) {
+        synchronized (mWindowMap) {
+            WindowState windowState = mWindowMap.get(windowToken);
+            return (windowState != null) ? windowState.mGlobalScale : 1.0f;
+        }
+    }
+
     private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
         if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
                 + (lp != null ? lp.packageName : null)
@@ -7817,18 +7824,30 @@
                             TAG, "Placing surface #" + i + " " + w.mSurface
                             + ": new=" + w.mShownFrame);
 
-                    int width, height;
-                    if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
-                        // for a scaled surface, we just want to use
-                        // the requested size.
-                        width  = w.mRequestedWidth;
-                        height = w.mRequestedHeight;
-                    } else {
-                        width = w.mCompatFrame.width();
-                        height = w.mCompatFrame.height();
-                    }
-
                     if (w.mSurface != null) {
+                        int width, height;
+                        if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
+                            // for a scaled surface, we just want to use
+                            // the requested size.
+                            width  = w.mRequestedWidth;
+                            height = w.mRequestedHeight;
+                        } else {
+                            width = w.mCompatFrame.width();
+                            height = w.mCompatFrame.height();
+                        }
+
+                        if (width < 1) {
+                            width = 1;
+                        }
+                        if (height < 1) {
+                            height = 1;
+                        }
+                        final boolean surfaceResized = w.mSurfaceW != width || w.mSurfaceH != height;
+                        if (surfaceResized) {
+                            w.mSurfaceW = width;
+                            w.mSurfaceH = height;
+                        }
+
                         if (w.mSurfaceX != w.mShownFrame.left
                                 || w.mSurfaceY != w.mShownFrame.top) {
                             try {
@@ -7848,21 +7867,11 @@
                             }
                         }
 
-                        if (width < 1) {
-                            width = 1;
-                        }
-                        if (height < 1) {
-                            height = 1;
-                        }
-
-                        if (w.mSurfaceW != width || w.mSurfaceH != height) {
+                        if (surfaceResized) {
                             try {
                                 if (SHOW_TRANSACTIONS) logSurface(w,
-                                        "SIZE " + w.mShownFrame.width() + "x"
-                                        + w.mShownFrame.height(), null);
+                                        "SIZE " + width + "x" + height, null);
                                 w.mSurfaceResized = true;
-                                w.mSurfaceW = width;
-                                w.mSurfaceH = height;
                                 w.mSurface.setSize(width, height);
                             } catch (RuntimeException e) {
                                 // If something goes wrong with the surface (such
@@ -7878,9 +7887,9 @@
                     }
 
                     if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
-                        w.mContentInsetsChanged =
+                        w.mContentInsetsChanged |=
                             !w.mLastContentInsets.equals(w.mContentInsets);
-                        w.mVisibleInsetsChanged =
+                        w.mVisibleInsetsChanged |=
                             !w.mLastVisibleInsets.equals(w.mVisibleInsets);
                         boolean configChanged =
                             w.mConfiguration != mCurConfiguration
@@ -7892,24 +7901,20 @@
                         }
                         if (localLOGV) Slog.v(TAG, "Resizing " + w
                                 + ": configChanged=" + configChanged
-                                + " last=" + w.mLastCompatFrame + " frame=" + w.mCompatFrame);
-                        boolean frameChanged = !w.mLastCompatFrame.equals(w.mCompatFrame);
-                        if (frameChanged
-                                || w.mContentInsetsChanged
+                                + " last=" + w.mLastFrame + " frame=" + w.mFrame);
+                        w.mLastFrame.set(w.mFrame);
+                        if (w.mContentInsetsChanged
                                 || w.mVisibleInsetsChanged
                                 || w.mSurfaceResized
                                 || configChanged) {
                             if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
                                 Slog.v(TAG, "Resize reasons: "
-                                        + "frameChanged=" + frameChanged
                                         + " contentInsetsChanged=" + w.mContentInsetsChanged
                                         + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
                                         + " surfaceResized=" + w.mSurfaceResized
                                         + " configChanged=" + configChanged);
                             }
 
-                            w.mLastFrame.set(w.mFrame);
-                            w.mLastCompatFrame.set(w.mCompatFrame);
                             w.mLastContentInsets.set(w.mContentInsets);
                             w.mLastVisibleInsets.set(w.mVisibleInsets);
                             // If the screen is currently frozen, then keep
@@ -7944,9 +7949,12 @@
                                     w.mAppToken.allDrawn = false;
                                 }
                             }
-                            if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
-                                    "Resizing window " + w + " to " + w.mCompatFrame);
-                            mResizingWindows.add(w);
+                            if (!mResizingWindows.contains(w)) {
+                                if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
+                                        "Resizing window " + w + " to " + w.mSurfaceW
+                                        + "x" + w.mSurfaceH);
+                                mResizingWindows.add(w);
+                            }
                         } else if (w.mOrientationChanging) {
                             if (!w.mDrawPending && !w.mCommitDrawPending) {
                                 if (DEBUG_ORIENTATION) Slog.v(TAG,
@@ -8241,13 +8249,12 @@
                     if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
                             && configChanged) {
                         Slog.i(TAG, "Sending new config to window " + win + ": "
-                                + win.mCompatFrame.width() + "x" + win.mCompatFrame.height()
+                                + win.mSurfaceW + "x" + win.mSurfaceH
                                 + " / " + mCurConfiguration + " / 0x"
                                 + Integer.toHexString(diff));
                     }
                     win.mConfiguration = mCurConfiguration;
-                    win.mClient.resized(win.mCompatFrame.width(),
-                            win.mCompatFrame.height(), win.mLastContentInsets,
+                    win.mClient.resized(win.mSurfaceW, win.mSurfaceH, win.mLastContentInsets,
                             win.mLastVisibleInsets, win.mDrawPending,
                             configChanged ? win.mConfiguration : null);
                     win.mContentInsetsChanged = false;
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 587685e..b370ec9 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -111,7 +111,6 @@
      * applied).
      */
     final Rect mShownFrame = new Rect();
-    final Rect mLastShownFrame = new Rect();
 
     /**
      * Set when we have changed the size of the surface, to know that
@@ -182,7 +181,6 @@
     // Frame that is scaled to the application's coordinate space when in
     // screen size compatibility mode.
     final Rect mCompatFrame = new Rect();
-    final Rect mLastCompatFrame = new Rect();
 
     final Rect mContainingFrame = new Rect();
     final Rect mDisplayFrame = new Rect();
@@ -1584,15 +1582,12 @@
         }
         pw.print(prefix); pw.print("mConfiguration="); pw.println(mConfiguration);
         pw.print(prefix); pw.print("mShownFrame=");
-                mShownFrame.printShortString(pw);
-                pw.print(" last="); mLastShownFrame.printShortString(pw);
-                pw.println();
+                mShownFrame.printShortString(pw); pw.println();
         pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
                 pw.print(" last="); mLastFrame.printShortString(pw);
                 pw.println();
         if (mEnforceSizeCompat) {
             pw.print(prefix); pw.print("mCompatFrame="); mCompatFrame.printShortString(pw);
-                    pw.print(" last="); mLastCompatFrame.printShortString(pw);
                     pw.println();
         }
         pw.print(prefix); pw.print("mContainingFrame=");
diff --git a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
index a45e879..fb2fc85 100644
--- a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
+++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
@@ -190,7 +190,6 @@
 
         // Used by DecimalFormatSymbols.
         result.zeroDigit = '0';
-        result.digit = '0';
         result.decimalSeparator = '.';
         result.groupingSeparator = ',';
         result.patternSeparator = ' ';