Merge "Use new nativeLibraryPath field for NativeActivity" into gingerbread
diff --git a/api/current.xml b/api/current.xml
index f7a5954..8ed7d93 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -21704,17 +21704,6 @@
  visibility="public"
 >
 </field>
-<field name="FLAG_HEAVY_WEIGHT"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="IMPORTANCE_BACKGROUND"
  type="int"
  transient="false"
@@ -21825,16 +21814,6 @@
  visibility="public"
 >
 </field>
-<field name="flags"
- type="int"
- transient="false"
- volatile="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="importance"
  type="int"
  transient="false"
@@ -46525,17 +46504,6 @@
  visibility="public"
 >
 </field>
-<field name="FLAG_SUPPORTS_XLARGE_SCREENS"
- type="int"
- transient="false"
- volatile="false"
- value="524288"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="FLAG_SYSTEM"
  type="int"
  transient="false"
@@ -49185,6 +49153,17 @@
  visibility="public"
 >
 </field>
+<field name="FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.hardware.touchscreen.multitouch.jazzhand&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FEATURE_WIFI"
  type="java.lang.String"
  transient="false"
@@ -51717,17 +51696,6 @@
  visibility="public"
 >
 </field>
-<field name="SCREENLAYOUT_SIZE_XLARGE"
- type="int"
- transient="false"
- volatile="false"
- value="4"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="TOUCHSCREEN_FINGER"
  type="int"
  transient="false"
@@ -265272,21 +265240,6 @@
  visibility="protected"
 >
 </method>
-<method name="getOption"
- return="java.lang.Object"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="optID" type="int">
-</parameter>
-<exception name="SocketException" type="java.net.SocketException">
-</exception>
-</method>
 <method name="getOutputStream"
  return="java.io.OutputStream"
  abstract="true"
@@ -265341,23 +265294,6 @@
 <exception name="IOException" type="java.io.IOException">
 </exception>
 </method>
-<method name="setOption"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="optID" type="int">
-</parameter>
-<parameter name="val" type="java.lang.Object">
-</parameter>
-<exception name="SocketException" type="java.net.SocketException">
-</exception>
-</method>
 <method name="setPerformancePreferences"
  return="void"
  abstract="false"
@@ -265736,19 +265672,6 @@
 <parameter name="p" type="java.security.Permission">
 </parameter>
 </method>
-<method name="isValidIP6Address"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="ipAddress" type="java.lang.String">
-</parameter>
-</method>
 </class>
 <class name="SocketTimeoutException"
  extends="java.io.InterruptedIOException"
@@ -279483,9 +279406,77 @@
  visibility="public"
 >
 </constructor>
+<method name="getInstance"
+ return="java.security.Policy"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="java.lang.String">
+</parameter>
+<parameter name="params" type="java.security.Policy.Parameters">
+</parameter>
+<exception name="NoSuchAlgorithmException" type="java.security.NoSuchAlgorithmException">
+</exception>
+</method>
+<method name="getInstance"
+ return="java.security.Policy"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="java.lang.String">
+</parameter>
+<parameter name="params" type="java.security.Policy.Parameters">
+</parameter>
+<parameter name="provider" type="java.lang.String">
+</parameter>
+<exception name="NoSuchAlgorithmException" type="java.security.NoSuchAlgorithmException">
+</exception>
+<exception name="NoSuchProviderException" type="java.security.NoSuchProviderException">
+</exception>
+</method>
+<method name="getInstance"
+ return="java.security.Policy"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="type" type="java.lang.String">
+</parameter>
+<parameter name="params" type="java.security.Policy.Parameters">
+</parameter>
+<parameter name="provider" type="java.security.Provider">
+</parameter>
+<exception name="NoSuchAlgorithmException" type="java.security.NoSuchAlgorithmException">
+</exception>
+</method>
+<method name="getParameters"
+ return="java.security.Policy.Parameters"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getPermissions"
  return="java.security.PermissionCollection"
- abstract="true"
+ abstract="false"
  native="false"
  synchronized="false"
  static="false"
@@ -279520,6 +279511,28 @@
  visibility="public"
 >
 </method>
+<method name="getProvider"
+ return="java.security.Provider"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getType"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="implies"
  return="boolean"
  abstract="false"
@@ -279537,7 +279550,7 @@
 </method>
 <method name="refresh"
  return="void"
- abstract="true"
+ abstract="false"
  native="false"
  synchronized="false"
  static="false"
@@ -279559,6 +279572,93 @@
 <parameter name="policy" type="java.security.Policy">
 </parameter>
 </method>
+<field name="UNSUPPORTED_EMPTY_COLLECTION"
+ type="java.security.PermissionCollection"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<interface name="Policy.Parameters"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</interface>
+<class name="PolicySpi"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="PolicySpi"
+ type="java.security.PolicySpi"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="engineGetPermissions"
+ return="java.security.PermissionCollection"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="codesource" type="java.security.CodeSource">
+</parameter>
+</method>
+<method name="engineGetPermissions"
+ return="java.security.PermissionCollection"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="domain" type="java.security.ProtectionDomain">
+</parameter>
+</method>
+<method name="engineImplies"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="domain" type="java.security.ProtectionDomain">
+</parameter>
+<parameter name="permission" type="java.security.Permission">
+</parameter>
+</method>
+<method name="engineRefresh"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
 </class>
 <interface name="Principal"
  abstract="true"
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d5741fc..4736404 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -755,14 +755,17 @@
         public String pkgList[];
         
         /**
-         * Constant for {@link #flags}: this is a heavy-weight process,
-         * meaning it will not be killed while in the background.
+         * Constant for {@link #flags}: this is an app that is unable to
+         * correctly save its state when going to the background,
+         * so it can not be killed while in the background.
+         * @hide
          */
-        public static final int FLAG_HEAVY_WEIGHT = 1<<0;
+        public static final int FLAG_CANT_SAVE_STATE = 1<<0;
         
         /**
          * Flags of information.  May be any of
-         * {@link #FLAG_HEAVY_WEIGHT}.
+         * {@link #FLAG_CANT_SAVE_STATE}.
+         * @hide
          */
         public int flags;
         
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 5525ce3..63ad92a 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -109,9 +109,14 @@
     public PendingIntent deleteIntent;
 
     /**
-     * An intent to launch instead of posting the notification to the status bar. Only for use with
-     * extremely high-priority notifications demanding the user's attention, such as an incoming
+     * An intent to launch instead of posting the notification to the status bar.
+     * Only for use with extremely high-priority notifications demanding the user's
+     * <strong>immediate</strong>attention, such as an incoming phone call or
+     * alarm clock that the user has explicitly set to a particular time.
      * call (handled in the core Android Phone app with a full-screen Activity).
+     * If this facility is used for something else, please give the user an option
+     * to turn it off and use a normal notification, as this can be extremely
+     * disruptive.
      */
     public PendingIntent fullScreenIntent;
 
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index ae6a311..cf24433 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -269,6 +269,7 @@
      * increased in size for extra large screens.  Corresponds to
      * {@link android.R.styleable#AndroidManifestSupportsScreens_xlargeScreens
      * android:xlargeScreens}.
+     * @hide
      */
     public static final int FLAG_SUPPORTS_XLARGE_SCREENS = 1<<19;
     
@@ -311,7 +312,7 @@
      * {@link #FLAG_ALLOW_CLEAR_USER_DATA}, {@link #FLAG_UPDATED_SYSTEM_APP},
      * {@link #FLAG_TEST_ONLY}, {@link #FLAG_SUPPORTS_SMALL_SCREENS},
      * {@link #FLAG_SUPPORTS_NORMAL_SCREENS},
-     * {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_SUPPORTS_XLARGE_SCREENS},
+     * {@link #FLAG_SUPPORTS_LARGE_SCREENS},
      * {@link #FLAG_RESIZEABLE_FOR_SCREENS},
      * {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}, {@link #FLAG_VM_SAFE_MODE}
      */
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 33a1db8..ef72013 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -801,6 +801,15 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device's touch screen is capable of
+     * tracking a full hand of fingers fully independently -- that is, 5 or
+     * more simultaneous independent pointers.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND = "android.hardware.touchscreen.multitouch.jazzhand";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device supports live wallpapers.
      */
     @SdkConstant(SdkConstantType.FEATURE)
diff --git a/core/java/android/content/pm/Signature.java b/core/java/android/content/pm/Signature.java
index 1bb3857..d4e5cc1 100644
--- a/core/java/android/content/pm/Signature.java
+++ b/core/java/android/content/pm/Signature.java
@@ -20,6 +20,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.ref.SoftReference;
 import java.util.Arrays;
 
 /**
@@ -30,7 +31,7 @@
     private final byte[] mSignature;
     private int mHashCode;
     private boolean mHaveHashCode;
-    private String mString;
+    private SoftReference<String> mStringRef;
 
     /**
      * Create Signature from an existing raw byte array.
@@ -96,10 +97,13 @@
      * cached so future calls will return the same String.
      */
     public String toCharsString() {
-        if (mString != null) return mString;
-        String str = new String(toChars());
-        mString = str;
-        return mString;
+        String str = mStringRef == null ? null : mStringRef.get();
+        if (str != null) {
+            return str;
+        }
+        str = new String(toChars());
+        mStringRef = new SoftReference<String>(str);
+        return str;
     }
 
     /**
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 02956ba..5a3dd41 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -62,6 +62,7 @@
     public static final int SCREENLAYOUT_SIZE_SMALL = 0x01;
     public static final int SCREENLAYOUT_SIZE_NORMAL = 0x02;
     public static final int SCREENLAYOUT_SIZE_LARGE = 0x03;
+    /** @hide */
     public static final int SCREENLAYOUT_SIZE_XLARGE = 0x04;
     
     public static final int SCREENLAYOUT_LONG_MASK = 0x30;
@@ -83,7 +84,7 @@
      * <p>The {@link #SCREENLAYOUT_SIZE_MASK} bits define the overall size
      * of the screen.  They may be one of
      * {@link #SCREENLAYOUT_SIZE_SMALL}, {@link #SCREENLAYOUT_SIZE_NORMAL},
-     * {@link #SCREENLAYOUT_SIZE_LARGE}, or {@link #SCREENLAYOUT_SIZE_XLARGE}.
+     * {@link #SCREENLAYOUT_SIZE_LARGE}.
      * 
      * <p>The {@link #SCREENLAYOUT_LONG_MASK} defines whether the screen
      * is wider/taller than normal.  They may be one of
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 6212e1b..2c5c909 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -84,14 +84,14 @@
      * sensor itself (<b>Fs</b>) using the relation:
      * </p>
      * 
-     * <b><center>Ad = - ·Fs / mass</center></b>
+     * <b><center>Ad = - &#8721;Fs / mass</center></b>
      * 
      * <p>
      * In particular, the force of gravity is always influencing the measured
      * acceleration:
      * </p>
      * 
-     * <b><center>Ad = -g - ·F / mass</center></b>
+     * <b><center>Ad = -g - &#8721;F / mass</center></b>
      * 
      * <p>
      * For this reason, when the device is sitting on a table (and obviously not
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index 2b20946..fa83897 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -443,7 +443,7 @@
             pm.setSharedPreferencesMode(sharedPreferencesMode);
             pm.inflateFromResource(context, resId, null);
 
-            defaultValueSp.edit().putBoolean(KEY_HAS_SET_DEFAULT_VALUES, true).commit();
+            defaultValueSp.edit().putBoolean(KEY_HAS_SET_DEFAULT_VALUES, true).apply();
         }
     }
     
@@ -481,7 +481,7 @@
     
     private void setNoCommit(boolean noCommit) {
         if (!noCommit && mEditor != null) {
-            mEditor.commit();
+            mEditor.apply();
         }
         
         mNoCommit = noCommit;
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 4d2ba71..924c9d4 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -143,7 +143,7 @@
     /**
      * Max distance to overscroll for edge effects
      */
-    private static final int OVERSCROLL_DISTANCE = 2;
+    private static final int OVERSCROLL_DISTANCE = 0;
 
     /**
      * Max distance to overfling for edge effects
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index fe2a43b..8f5c35e 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -659,6 +659,18 @@
     }
 
     /**
+     * @return true if all list content currently fits within the view boundaries
+     */
+    private boolean contentFits() {
+        final int childCount = getChildCount();
+        if (childCount != mItemCount) {
+            return false;
+        }
+
+        return getChildAt(0).getTop() >= 0 && getChildAt(childCount - 1).getBottom() <= mBottom;
+    }
+
+    /**
      * Enables fast scrolling by letting the user quickly scroll through lists by
      * dragging the fast scroll thumb. The adapter attached to the list may want
      * to implement {@link SectionIndexer} if it wishes to display alphabet preview and
@@ -2221,8 +2233,12 @@
                                 // Don't allow overfling if we're at the edge.
                                 mVelocityTracker.clear();
                             }
-                            mTouchMode = TOUCH_MODE_OVERSCROLL;
-                            if (mEdgeGlowTop != null) {
+
+                            final int overscrollMode = getOverscrollMode();
+                            if (overscrollMode == OVERSCROLL_ALWAYS ||
+                                    (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS &&
+                                            !contentFits())) {
+                                mTouchMode = TOUCH_MODE_OVERSCROLL;
                                 if (rawDeltaY > 0) {
                                     mEdgeGlowTop.onPull((float) overscroll / getHeight());
                                 } else if (rawDeltaY < 0) {
@@ -2275,7 +2291,10 @@
                     } else {
                         overscrollBy(0, -incrementalDeltaY, 0, mScrollY, 0, 0,
                                 0, mOverscrollDistance, true);
-                        if (mEdgeGlowTop != null) {
+                        final int overscrollMode = getOverscrollMode();
+                        if (overscrollMode == OVERSCROLL_ALWAYS ||
+                                (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS &&
+                                        !contentFits())) {
                             if (rawDeltaY > 0) {
                                 mEdgeGlowTop.onPull((float) -incrementalDeltaY / getHeight());
                             } else if (rawDeltaY < 0) {
@@ -2757,8 +2776,10 @@
 
         void edgeReached(int delta) {
             mScroller.notifyVerticalEdgeReached(mScrollY, 0, mOverflingDistance);
-            mTouchMode = TOUCH_MODE_OVERFLING;
-            if (mEdgeGlowTop != null) {
+            final int overscrollMode = getOverscrollMode();
+            if (overscrollMode == OVERSCROLL_ALWAYS ||
+                    (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS && !contentFits())) {
+                mTouchMode = TOUCH_MODE_OVERFLING;
                 final int vel = (int) mScroller.getCurrVelocity();
                 if (delta > 0) {
                     mEdgeGlowTop.onAbsorb(vel);
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 129ad8a..0bb97dd 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -538,11 +538,15 @@
                     }
                     onScrollChanged(mScrollX, mScrollY, oldX, oldY);
 
-                    final int pulledToX = oldX + deltaX;
-                    if (pulledToX < 0) {
-                        mEdgeGlowLeft.onPull((float) deltaX / getWidth());
-                    } else if (pulledToX > range) {
-                        mEdgeGlowRight.onPull((float) deltaX / getWidth());
+                    final int overscrollMode = getOverscrollMode();
+                    if (overscrollMode == OVERSCROLL_ALWAYS ||
+                            (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS && range > 0)) {
+                        final int pulledToX = oldX + deltaX;
+                        if (pulledToX < 0) {
+                            mEdgeGlowLeft.onPull((float) deltaX / getWidth());
+                        } else if (pulledToX > range) {
+                            mEdgeGlowRight.onPull((float) deltaX / getWidth());
+                        }
                     }
                 }
                 break;
@@ -1091,10 +1095,14 @@
                 onScrollChanged(mScrollX, mScrollY, oldX, oldY);
 
                 final int range = getScrollRange();
-                if (x < 0 && oldX >= 0) {
-                    mEdgeGlowLeft.onAbsorb((int) mScroller.getCurrVelocity());
-                } else if (x > range && oldX <= range) {
-                    mEdgeGlowRight.onAbsorb((int) mScroller.getCurrVelocity());
+                final int overscrollMode = getOverscrollMode();
+                if (overscrollMode == OVERSCROLL_ALWAYS ||
+                        (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS && range > 0)) {
+                    if (x < 0 && oldX >= 0) {
+                        mEdgeGlowLeft.onAbsorb((int) mScroller.getCurrVelocity());
+                    } else if (x > range && oldX <= range) {
+                        mEdgeGlowRight.onAbsorb((int) mScroller.getCurrVelocity());
+                    }
                 }
             }
             awakenScrollBars();
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 7b5e412..2ba1c47 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -533,11 +533,15 @@
                     }
                     onScrollChanged(mScrollX, mScrollY, oldX, oldY);
 
-                    final int pulledToY = oldY + deltaY;
-                    if (pulledToY < 0) {
-                        mEdgeGlowTop.onPull((float) deltaY / getHeight());
-                    } else if (pulledToY > range) {
-                        mEdgeGlowBottom.onPull((float) deltaY / getHeight());
+                    final int overscrollMode = getOverscrollMode();
+                    if (overscrollMode == OVERSCROLL_ALWAYS ||
+                            (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS && range > 0)) {
+                        final int pulledToY = oldY + deltaY;
+                        if (pulledToY < 0) {
+                            mEdgeGlowTop.onPull((float) deltaY / getHeight());
+                        } else if (pulledToY > range) {
+                            mEdgeGlowBottom.onPull((float) deltaY / getHeight());
+                        }
                     }
                 }
                 break;
@@ -1090,10 +1094,14 @@
                 onScrollChanged(mScrollX, mScrollY, oldX, oldY);
 
                 final int range = getScrollRange();
-                if (y < 0 && oldY >= 0) {
-                    mEdgeGlowTop.onAbsorb((int) mScroller.getCurrVelocity());
-                } else if (y > range && oldY <= range) {
-                    mEdgeGlowBottom.onAbsorb((int) mScroller.getCurrVelocity());
+                final int overscrollMode = getOverscrollMode();
+                if (overscrollMode == OVERSCROLL_ALWAYS ||
+                        (overscrollMode == OVERSCROLL_IF_CONTENT_SCROLLS && range > 0)) {
+                    if (y < 0 && oldY >= 0) {
+                        mEdgeGlowTop.onAbsorb((int) mScroller.getCurrVelocity());
+                    } else if (y > range && oldY <= range) {
+                        mEdgeGlowBottom.onAbsorb((int) mScroller.getCurrVelocity());
+                    }
                 }
             }
             awakenScrollBars();
diff --git a/data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml b/data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml
new file mode 100644
index 0000000..80bf859
--- /dev/null
+++ b/data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This is the standard set of features for a touchscreen that supports
+     independently-trackable multiple-finger multitouch. -->
+<permissions>
+    <feature name="android.hardware.touchscreen" />
+    <feature name="android.hardware.touchscreen.multitouch" />
+    <feature name="android.hardware.touchscreen.multitouch.distinct" />
+    <feature name="android.hardware.touchscreen.multitouch.jazzhand" />
+</permissions>
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index efca4c2..a3c9f6d 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -38,10 +38,19 @@
     <!-- devices with a front facing camera must include
          android.hardware.camera.front.xml -->
     <!-- devices with WiFi must also include android.hardware.wifi.xml -->
-    <!-- devices with limited/gestural multitouch must also include
-         android.hardware.touchscreen.multitouch.xml -->
-    <!-- devices with full multitouch must also include
-         android.hardware.touchscreen.multitouch.distinct.xml -->
+    <!-- devices that support multitouch must include the most appropriate one
+         of these files:
+
+         If only partial (non-independent) pointers are supported:
+         android.hardware.touchscreen.multitouch.xml
+
+         If up to 4 independently tracked pointers are supported:
+         include android.hardware.touchscreen.multitouch.distinct.xml
+
+         If 5 or more independently tracked pointers are supported:
+         include android.hardware.touchscreen.multitouch.jazzhand.xml
+
+         ONLY ONE of the above should be included. -->
     <!-- devices with an ambient light sensor must also include
          android.hardware.sensor.light.xml -->
     <!-- devices with a proximity sensor must also include
diff --git a/docs/html/guide/topics/data/data-storage.jd b/docs/html/guide/topics/data/data-storage.jd
index 293a057..e20d1ed 100644
--- a/docs/html/guide/topics/data/data-storage.jd
+++ b/docs/html/guide/topics/data/data-storage.jd
@@ -115,7 +115,7 @@
     public static final String PREFS_NAME = "MyPrefsFile";
 
     &#64;Override
-    protected void onCreate(Bundle state){         
+    protected void onCreate(Bundle state){
        super.onCreate(state);
        . . .
 
@@ -374,7 +374,7 @@
 can execute a SQLite command to create tables in the database. For example:</p>
 
 <pre>
-public class MyDbOpenHelper extends SQLiteOpenHelper {
+public class DictionaryOpenHelper extends SQLiteOpenHelper {
 
     private static final int DATABASE_VERSION = 2;
     private static final String DICTIONARY_TABLE_NAME = "dictionary";
diff --git a/docs/html/guide/topics/resources/more-resources.jd b/docs/html/guide/topics/resources/more-resources.jd
index a647571..6cae1eb 100644
--- a/docs/html/guide/topics/resources/more-resources.jd
+++ b/docs/html/guide/topics/resources/more-resources.jd
@@ -216,10 +216,13 @@
 For example: 10px, 2in, 5sp. The following units of measure are supported by Android:</p>
 <dl>
   <dt>{@code dp}</dt>
-    <dd>Density-independent Pixels - an abstract unit that is based on the physical density of the screen.
-    These units are relative to a 160 dpi screen, so one dp is one pixel on a 160 dpi screen. The ratio of
-    dp-to-pixel will change with the screen density, but not necessarily in direct proportion. The
-      compiler accepts both "dip" and "dp", though "dp" is more consistent with "sp".</dd>
+    <dd>Density-independent Pixels - an abstract unit that is based on the physical density of the
+screen. These units are relative to a 160 dpi (dots per inch) screen, so <em>{@code 160dp} is
+always one inch</em> regardless of the screen density. The ratio of dp-to-pixel will change with the
+screen density, but not necessarily in direct proportion. You should use these units when specifying
+view dimensions in your layout, so the UI properly scales to render at the same actual size on
+different screens. (The compiler accepts both "dip" and "dp", though "dp" is more consistent with
+"sp".)</dd>
   <dt>{@code sp}</dt>
     <dd>Scale-independent Pixels - this is like the dp unit, but it is also scaled by the user's font
     size preference. It is recommend you use this unit when specifying font sizes, so they will be adjusted
diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h
index 1af4254..a5cec78 100644
--- a/include/media/stagefright/AudioSource.h
+++ b/include/media/stagefright/AudioSource.h
@@ -72,6 +72,7 @@
     int64_t mPrevSampleTimeUs;
     int64_t mTotalLostFrames;
     int64_t mPrevLostBytes;
+    int64_t mInitialReadTimeUs;
 
     MediaBufferGroup *mGroup;
 
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 2412f6a..70bd8e8 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -62,6 +62,7 @@
     class Track;
 
     FILE *mFile;
+    bool mUse4ByteNalLength;
     bool mUse32BitOffset;
     bool mPaused;
     bool mStarted;
@@ -132,9 +133,13 @@
     // Adjust other track media clock (presumably wall clock)
     // based on audio track media clock with the drift time.
     int64_t mDriftTimeUs;
-    void addDriftTimeUs(int64_t driftTimeUs);
+    void setDriftTimeUs(int64_t driftTimeUs);
     int64_t getDriftTimeUs();
 
+    // Return whether the nal length is 4 bytes or 2 bytes
+    // Only makes sense for H.264/AVC
+    bool useNalLengthFour();
+
     void lock();
     void unlock();
 
@@ -144,6 +149,7 @@
 
     inline size_t write(const void *ptr, size_t size, size_t nmemb, FILE* stream);
     bool exceedsFileSizeLimit();
+    bool use32BitFileOffset() const;
     bool exceedsFileDurationLimit();
     void trackProgressStatus(const Track* track, int64_t timeUs, status_t err = OK);
 
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 43354c2..1e447f1 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -48,6 +48,7 @@
     kKeyTime              = 'time',  // int64_t (usecs)
     kKeyNTPTime           = 'ntpT',  // uint64_t (ntp-timestamp)
     kKeyTargetTime        = 'tarT',  // int64_t (usecs)
+    kKeyDriftTime         = 'dftT',  // int64_t (usecs)
     kKeyDuration          = 'dura',  // int64_t (usecs)
     kKeyColorFormat       = 'colf',
     kKeyPlatformPrivate   = 'priv',  // pointer
@@ -78,6 +79,7 @@
 
     // Set this key to enable authoring files in 64-bit offset
     kKey64BitFileOffset   = 'fobt',  // int32_t (bool)
+    kKey2ByteNalLength    = '2NAL',  // int32_t (bool)
 
     // Identify the file output format for authoring
     // Please see <media/mediarecorder.h> for the supported
@@ -90,6 +92,8 @@
 
     kKeyNotRealTime       = 'ntrt',  // bool (int32_t)
 
+    // Ogg files can be tagged to be automatically looping...
+    kKeyAutoLoop          = 'autL',  // bool (int32_t)
 };
 
 enum {
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.c
index 6a8b39b..9a40f68 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.c
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.c
@@ -526,7 +526,7 @@
         (pPrivate->NewParams.OperatingMode == LVM_MODE_ON))
     {
         pPrivate->BypassMixer.Target2 = ((LVM_INT32)(pPrivate->NewParams.Level * 32767)/100)<<16;
-        pPrivate->BypassMixer.Target1 = LVREV_HEADROOM << 16;
+        pPrivate->BypassMixer.Target1 = 0x00000000;
         if ((pPrivate->NewParams.Level == 0) && (pPrivate->bFirstControl == LVM_FALSE))
         {
             pPrivate->BypassMixer.CallbackSet2 = LVM_TRUE;
@@ -542,7 +542,7 @@
         if(pPrivate->NewParams.OperatingMode == LVM_MODE_ON)
         {
             pPrivate->BypassMixer.Target2 = ((LVM_INT32)(pPrivate->NewParams.Level * 32767)/100)<<16;
-            pPrivate->BypassMixer.Target1 = LVREV_HEADROOM << 16;
+            pPrivate->BypassMixer.Target1 = 0x00000000;
 
             pPrivate->BypassMixer.CallbackSet2 = LVM_FALSE;
             OperatingMode                      = LVM_MODE_ON;
@@ -558,7 +558,7 @@
         else if (pPrivate->bFirstControl == LVM_FALSE)
         {
             pPrivate->BypassMixer.Target2 = 0x00000000;
-            pPrivate->BypassMixer.Target1 = 0x7FFFFFFF;
+            pPrivate->BypassMixer.Target1 = 0x00000000;
             pPrivate->BypassMixer.CallbackSet2 = LVM_TRUE;
             pPrivate->GainMixer.Target    = 0x03FFFFFF;
             OperatingMode = LVM_MODE_ON;
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetInstanceHandle.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_GetInstanceHandle.c
index c2b266a..ffa5138 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetInstanceHandle.c
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_GetInstanceHandle.c
@@ -238,8 +238,8 @@
     pLVREV_Private->BypassMixer.pGeneralPurpose1    = LVM_NULL;
     pLVREV_Private->BypassMixer.pCallBack1          = LVM_NULL;
     pLVREV_Private->BypassMixer.CallbackSet1        = LVM_FALSE;
-    pLVREV_Private->BypassMixer.Current1            = 0x7fffffff;
-    pLVREV_Private->BypassMixer.Target1             = 0x7fffffff;
+    pLVREV_Private->BypassMixer.Current1            = 0x00000000;
+    pLVREV_Private->BypassMixer.Target1             = 0x00000000;
 
     pLVREV_Private->RoomSizeInms                    = 100;  // 100 msec
 
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Control.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Control.c
index a3ba42b..ce6d410 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Control.c
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Control.c
@@ -202,7 +202,9 @@
         /* Set the reverb delay timeout */
         if(pInstance->bInOperatingModeTransition != LVM_TRUE){
             pInstance->bTimerDone = LVM_FALSE;
-            pInstance->TimerParams.TimeInMs = (LVM_INT16)(((pInstance->Reverberation.DelaySize << 2)/pInstance->TimerParams.SamplingRate) + 1);
+            pInstance->TimerParams.TimeInMs =
+            (LVM_INT16)(((pInstance->Reverberation.DelaySize << 2)
+            /pInstance->TimerParams.SamplingRate) + 1);
             LVM_Timer_Init ( &pInstance->TimerInstance,
                              &pInstance->TimerParams);
         }
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 7297811..e86ed99 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -275,7 +275,6 @@
            pContext->pBundledContext->PcmInPtr = NULL;
            return -EINVAL;
         }
-
         #endif
 
         /* Saved strength is used to return the exact strength that was used in the set to the get
@@ -565,9 +564,6 @@
     params.SpeakerType            = LVM_HEADPHONES;
 
     pContext->pBundledContext->SampleRate = LVM_FS_44100;
-    pContext->pBundledContext->SamplesToExitCountEq   = 44100*2*2; // 2 secs Stereo
-    pContext->pBundledContext->SamplesToExitCountBb   = 44100*2*2; // 2 secs Stereo
-    pContext->pBundledContext->SamplesToExitCountVirt = 44100*2*2; // 2 secs Stereo
 
     /* Concert Sound parameters */
     params.VirtualizerOperatingMode   = LVM_MODE_OFF;
@@ -2431,7 +2427,7 @@
         if(pContext->pBundledContext->SamplesToExitCountBb > 0){
             status2Sec = -ENODATA;
             pContext->pBundledContext->SamplesToExitCountBb -= outBuffer->frameCount * 2; // STEREO
-            //LOGV("\tEffect_process: Waiting for 2 secs to turn off BASS_BOOST, %d samples left",
+            //LOGV("\tEffect_process: Waiting to turn off BASS_BOOST, %d samples left",
             //    pContext->pBundledContext->SamplesToExitCountBb);
         } else {
         status = -ENODATA;
@@ -2897,11 +2893,11 @@
             pContext->pBundledContext->NumberEffectsEnabled++;
             android::LvmEffect_enable(pContext);
             pContext->pBundledContext->SamplesToExitCountEq =
-                 (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*1); // 0.1 secs Stereo
+                 (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1); // 0.1 secs Stereo
             pContext->pBundledContext->SamplesToExitCountBb =
-                 (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*6); // 2 secs Stereo
+                 (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1); // 0.1 secs Stereo
             pContext->pBundledContext->SamplesToExitCountVirt =
-                 (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*1); // 2 secs Stereo
+                 (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1); // 0.1 secs Stereo
             LOGV("\tEffect_command cmdCode Case: EFFECT_CMD_ENABLE Samples to Exit = %d",
                 pContext->pBundledContext->SamplesToExitCountBb);
             //LOGV("\tEffect_command cmdCode Case: EFFECT_CMD_ENABLE NumberEffectsEnabled = %d",
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 10c3e92..45ef416 100755
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -152,6 +152,7 @@
     bool                            preset;
     uint16_t                        curPreset;
     uint16_t                        nextPreset;
+    int                             SamplesToExitCount;
 };
 
 #define REVERB_DEFAULT_PRESET REVERB_PRESET_MEDIUMROOM
@@ -212,6 +213,7 @@
         desc = gDescriptors[i];
         if (memcmp(uuid, &desc->uuid, sizeof(effect_uuid_t))
                 == 0) {
+            LOGV("\tEffectCreate - UUID matched Reverb type %d, UUID = %x", i, desc->uuid.timeLow);
             break;
         }
     }
@@ -228,6 +230,9 @@
     pContext->auxiliary = false;
     if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY){
         pContext->auxiliary = true;
+        LOGV("\tEffectCreate - AUX");
+    }else{
+        LOGV("\tEffectCreate - INS");
     }
 
     pContext->preset = false;
@@ -236,6 +241,9 @@
         // force reloading preset at first call to process()
         pContext->curPreset = REVERB_PRESET_LAST + 1;
         pContext->nextPreset = REVERB_DEFAULT_PRESET;
+        LOGV("\tEffectCreate - PRESET");
+    }else{
+        LOGV("\tEffectCreate - ENVIRONMENTAL");
     }
 
     LOGV("\tEffectCreate - Calling Reverb_init");
@@ -389,22 +397,19 @@
              int           frameCount,
              ReverbContext *pContext){
 
-    LVM_INT16               samplesPerFrame = 0;
+    LVM_INT16               samplesPerFrame = 1;
     LVREV_ReturnStatus_en   LvmStatus = LVREV_SUCCESS;              /* Function call status */
     LVM_INT16 *OutFrames16;
 
 
     // Check that the input is either mono or stereo
-    if(pContext->config.inputCfg.channels == CHANNEL_STEREO){
+    if (pContext->config.inputCfg.channels == CHANNEL_STEREO) {
         samplesPerFrame = 2;
-    } else if (pContext->config.inputCfg.channels == CHANNEL_MONO){
-        samplesPerFrame = 1;
-    } else {
+    } else if (pContext->config.inputCfg.channels != CHANNEL_MONO) {
         LOGV("\tLVREV_ERROR : process invalid PCM format");
         return -EINVAL;
     }
 
-
     OutFrames16 = (LVM_INT16 *)pContext->OutFrames32;
 
     // Check for NULL pointers
@@ -437,43 +442,49 @@
     //pContext->config.outputCfg.channels, CHANNEL_STEREO);
 
     if (pContext->preset && pContext->curPreset == REVERB_PRESET_NONE) {
-        memset(pContext->OutFrames32, 0, frameCount * sizeof(LVM_INT32) * 2);
+        memset(pContext->OutFrames32, 0, frameCount * sizeof(LVM_INT32) * 2); //always stereo here
     } else {
-    /* Process the samples */
-    LvmStatus = LVREV_Process(pContext->hInstance,      /* Instance handle */
-                              pContext->InFrames32,     /* Input buffer */
-                              pContext->OutFrames32,    /* Output buffer */
-                              frameCount);              /* Number of samples to read */
-    }
-
-    if (!pContext->auxiliary) {
-        for (int i=0; i<frameCount*2; i++){
-            pContext->OutFrames32[i] += pContext->InFrames32[i];
+        if(pContext->bEnabled == LVM_FALSE && pContext->SamplesToExitCount > 0) {
+            memset(pContext->InFrames32,
+                   0,
+                   frameCount * sizeof(LVM_INT32) * 2); //always stereo here
         }
+
+        /* Process the samples */
+        LvmStatus = LVREV_Process(pContext->hInstance,      /* Instance handle */
+                                  pContext->InFrames32,     /* Input buffer */
+                                  pContext->OutFrames32,    /* Output buffer */
+                                  frameCount);              /* Number of samples to read */
     }
 
     LVM_ERROR_CHECK(LvmStatus, "LVREV_Process", "process")
     if(LvmStatus != LVREV_SUCCESS) return -EINVAL;
 
     // Convert to 16 bits
-    for(int i=0; i<frameCount*2; i++){  // Always stereo
-        OutFrames16[i] = clamp16(pContext->OutFrames32[i]>>8);
+    if (pContext->auxiliary) {
+        for (int i=0; i < frameCount*2; i++) { //always stereo here
+            OutFrames16[i] = clamp16(pContext->OutFrames32[i]>>8);
+        }
+    } else {
+        for (int i=0; i < frameCount*2; i++) { //always stereo here
+            OutFrames16[i] = clamp16((pContext->OutFrames32[i]>>8) + (LVM_INT32)pIn[i]);
+        }
     }
 
     #ifdef LVM_PCM
-    fwrite(OutFrames16, frameCount*sizeof(LVM_INT16)*samplesPerFrame, 1, pContext->PcmOutPtr);
+    fwrite(OutFrames16, frameCount*sizeof(LVM_INT16)*2, 1, pContext->PcmOutPtr);
     fflush(pContext->PcmOutPtr);
     #endif
 
     // Accumulate if required
     if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
         //LOGV("\tBuffer access is ACCUMULATE");
-        for (int i=0; i<frameCount*2; i++){
+        for (int i=0; i<frameCount*2; i++){ //always stereo here
             pOut[i] = clamp16((int32_t)pOut[i] + (int32_t)OutFrames16[i]);
         }
     }else{
         //LOGV("\tBuffer access is WRITE");
-        memcpy(pOut, OutFrames16, frameCount*sizeof(LVM_INT16)*2); // 2 is for stereo output
+        memcpy(pOut, OutFrames16, frameCount*sizeof(LVM_INT16)*2);
     }
 
     return 0;
@@ -560,6 +571,7 @@
     //LOGV("\tReverb_configure calling memcpy");
     memcpy(&pContext->config, pConfig, sizeof(effect_config_t));
 
+
     switch (pConfig->inputCfg.samplingRate) {
     case 8000:
         SampleRate = LVM_FS_8000;
@@ -741,6 +753,8 @@
     params.Damping        = 21;
     params.RoomSize       = 100;
 
+    pContext->SamplesToExitCount = (params.T60 * pContext->config.inputCfg.samplingRate)/1000;
+
     /* Saved strength is used to return the exact strength that was used in the set to the get
      * because we map the original strength range of 0:1000 to 1:15, and this will avoid
      * quantisation like effect when returning
@@ -1082,7 +1096,8 @@
 
     //LOGV("\tReverbGetRoomLevel, Level = %d, pContext->SavedRoomLevel = %d, "
     //     "pContext->SavedReverbLevel = %d, CombinedLevel = %d, level = %d",
-    //ActiveParams.Level, pContext->SavedRoomLevel, pContext->SavedReverbLevel, CombinedLevel, level);
+    //     ActiveParams.Level, pContext->SavedRoomLevel,
+    //     pContext->SavedReverbLevel, CombinedLevel, level);
 
     if(ActiveParams.Level != level){
         LOGV("\tLVM_ERROR : (ignore at start up) ReverbGetRoomLevel() has wrong level -> %d %d\n",
@@ -1129,6 +1144,8 @@
     LVM_ERROR_CHECK(LvmStatus, "LVREV_SetControlParameters", "ReverbSetDecayTime")
     //LOGV("\tReverbSetDecayTime() just Set -> %d\n", ActiveParams.T60);
 
+    pContext->SamplesToExitCount = (ActiveParams.T60 * pContext->config.inputCfg.samplingRate)/1000;
+    //LOGV("\tReverbSetDecayTime() just Set SamplesToExitCount-> %d\n",pContext->SamplesToExitCount);
     pContext->SavedDecayTime = time;
     //LOGV("\tReverbSetDecayTime end");
     return;
@@ -1769,8 +1786,12 @@
         return -EINVAL;
     }
     if (pContext->bEnabled == LVM_FALSE){
-        LOGV("\tReverb_process() ERROR Effect is not enabled");
-        return -ENODATA;
+        if( pContext->SamplesToExitCount > 0){
+            pContext->SamplesToExitCount -= outBuffer->frameCount;
+        }else{
+            LOGV("\tReverb_process() ERROR Effect is not enabled %d", pContext->SamplesToExitCount);
+            return -ENODATA;
+        }
     }
     //LOGV("\tReverb_process() Calling process with %d frames", outBuffer->frameCount);
     /* Process all the available frames, block processing is handled internalLY by the LVM bundle */
@@ -1791,6 +1812,9 @@
                               void                *pReplyData){
     android::ReverbContext * pContext = (android::ReverbContext *) self;
     int retsize;
+    LVREV_ControlParams_st    ActiveParams;              /* Current control Parameters */
+    LVREV_ReturnStatus_en     LvmStatus=LVREV_SUCCESS;     /* Function call status */
+
 
     if (pContext == NULL){
         LOGV("\tLVM_ERROR : Reverb_command ERROR pContext == NULL");
@@ -1917,6 +1941,12 @@
              }
             *(int *)pReplyData = 0;
             pContext->bEnabled = LVM_TRUE;
+            /* Get the current settings */
+            LvmStatus = LVREV_GetControlParameters(pContext->hInstance, &ActiveParams);
+            LVM_ERROR_CHECK(LvmStatus, "LVREV_GetControlParameters", "EFFECT_CMD_ENABLE")
+            pContext->SamplesToExitCount =
+                    (ActiveParams.T60 * pContext->config.inputCfg.samplingRate)/1000;
+            //LOGV("\tEFFECT_CMD_ENABLE SamplesToExitCount = %d", pContext->SamplesToExitCount);
             break;
         case EFFECT_CMD_DISABLE:
             //LOGV("\tReverb_command cmdCode Case: "
@@ -1939,8 +1969,8 @@
         case EFFECT_CMD_SET_DEVICE:
         case EFFECT_CMD_SET_VOLUME:
         case EFFECT_CMD_SET_AUDIO_MODE:
-            //LOGV("\tReverb_command cmdCode Case: "
-            //        "EFFECT_CMD_SET_DEVICE/EFFECT_CMD_SET_VOLUME/EFFECT_CMD_SET_AUDIO_MODE start");
+        //LOGV("\tReverb_command cmdCode Case: "
+        //        "EFFECT_CMD_SET_DEVICE/EFFECT_CMD_SET_VOLUME/EFFECT_CMD_SET_AUDIO_MODE start");
             break;
 
         default:
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index bcae913..c2f79e8 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -84,6 +84,7 @@
 
     mTrackMaxAmplitude = false;
     mMaxAmplitude = 0;
+    mInitialReadTimeUs = 0;
     mStartTimeUs = 0;
     int64_t startTimeUs;
     if (params && params->findInt64(kKeyTime, &startTimeUs)) {
@@ -210,6 +211,7 @@
         return NO_INIT;
     }
 
+    int64_t readTimeUs = systemTime() / 1000;
     *out = NULL;
 
     MediaBuffer *buffer;
@@ -223,9 +225,10 @@
 
 
         if (numFramesRecorded == 0 && mPrevSampleTimeUs == 0) {
+            mInitialReadTimeUs = readTimeUs;
             // Initial delay
             if (mStartTimeUs > 0) {
-                mStartTimeUs = systemTime() / 1000 - mStartTimeUs;
+                mStartTimeUs = readTimeUs - mStartTimeUs;
             } else {
                 // Assume latency is constant.
                 mStartTimeUs += mRecord->latency() * 1000;
@@ -271,7 +274,10 @@
             }
             memset(buffer->data(), 0, numLostBytes);
             buffer->set_range(0, numLostBytes);
-            buffer->meta_data()->setInt64(kKeyTime, mPrevSampleTimeUs);
+            if (numFramesRecorded == 0) {
+                buffer->meta_data()->setInt64(kKeyTime, mStartTimeUs);
+            }
+            buffer->meta_data()->setInt64(kKeyDriftTime, readTimeUs - mInitialReadTimeUs);
             mPrevSampleTimeUs = timestampUs;
             *out = buffer;
             return OK;
@@ -309,7 +315,10 @@
             trackMaxAmplitude((int16_t *) buffer->data(), n >> 1);
         }
 
-        buffer->meta_data()->setInt64(kKeyTime, mPrevSampleTimeUs);
+        if (numFramesRecorded == 0) {
+            buffer->meta_data()->setInt64(kKeyTime, mStartTimeUs);
+        }
+        buffer->meta_data()->setInt64(kKeyDriftTime, readTimeUs - mInitialReadTimeUs);
         CHECK(timestampUs > mPrevSampleTimeUs);
         mPrevSampleTimeUs = timestampUs;
         LOGV("initial delay: %lld, sample rate: %d, timestamp: %lld",
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 2681dc3..8507afc 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -50,6 +50,9 @@
 
 namespace android {
 
+static int64_t kLowWaterMarkUs = 2000000ll;  // 2secs
+static int64_t kHighWaterMarkUs = 10000000ll;  // 10secs
+
 struct AwesomeEvent : public TimedEventQueue::Event {
     AwesomeEvent(
             AwesomePlayer *player,
@@ -327,6 +330,13 @@
         } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
             setAudioSource(extractor->getTrack(i));
             haveAudio = true;
+
+            sp<MetaData> fileMeta = extractor->getMetaData();
+            int32_t loop;
+            if (fileMeta != NULL
+                    && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
+                mFlags |= AUTO_LOOPING;
+            }
         }
 
         if (haveAudio && haveVideo) {
@@ -450,6 +460,25 @@
     }
 }
 
+// Returns true iff cached duration is available/applicable.
+bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
+    off_t totalSize;
+
+    if (mRTSPController != NULL) {
+        *durationUs = mRTSPController->getQueueDurationUs(eos);
+        return true;
+    } else if (mCachedSource != NULL && mDurationUs >= 0
+            && mCachedSource->getSize(&totalSize) == OK) {
+        int64_t bitrate = totalSize * 8000000ll / mDurationUs;  // in bits/sec
+
+        size_t cachedDataRemaining = mCachedSource->approxDataRemaining(eos);
+        *durationUs = cachedDataRemaining * 8000000ll / bitrate;
+        return true;
+    }
+
+    return false;
+}
+
 void AwesomePlayer::onBufferingUpdate() {
     Mutex::Autolock autoLock(mLock);
     if (!mBufferingEventPending) {
@@ -457,78 +486,82 @@
     }
     mBufferingEventPending = false;
 
-    int kLowWaterMarkSecs = 2;
-    int kHighWaterMarkSecs = 10;
-
-    if (mRTSPController != NULL) {
+    if (mCachedSource != NULL) {
         bool eos;
-        int64_t queueDurationUs = mRTSPController->getQueueDurationUs(&eos);
+        size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
 
-        LOGV("queueDurationUs = %.2f secs", queueDurationUs / 1E6);
+        if (eos) {
+            notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
+        } else {
+            off_t size;
+            if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) {
+                int64_t bitrate = size * 8000000ll / mDurationUs;  // in bits/sec
 
+                size_t cachedSize = mCachedSource->cachedSize();
+                int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
+
+                int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
+                if (percentage > 100) {
+                    percentage = 100;
+                }
+
+                notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
+            } else {
+                // We don't know the bitrate of the stream, use absolute size
+                // limits to maintain the cache.
+
+                const size_t kLowWaterMarkBytes = 400000;
+                const size_t kHighWaterMarkBytes = 1000000;
+
+                if ((mFlags & PLAYING) && !eos
+                        && (cachedDataRemaining < kLowWaterMarkBytes)) {
+                    LOGI("cache is running low (< %d) , pausing.",
+                         kLowWaterMarkBytes);
+                    mFlags |= CACHE_UNDERRUN;
+                    pause_l();
+                    notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
+                } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
+                    if (mFlags & CACHE_UNDERRUN) {
+                        LOGI("cache has filled up (> %d), resuming.",
+                             kHighWaterMarkBytes);
+                        mFlags &= ~CACHE_UNDERRUN;
+                        play_l();
+                        notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
+                    } else if (mFlags & PREPARING) {
+                        LOGV("cache has filled up (> %d), prepare is done",
+                             kHighWaterMarkBytes);
+                        finishAsyncPrepare_l();
+                    }
+                }
+            }
+        }
+    }
+
+    int64_t cachedDurationUs;
+    bool eos;
+    if (getCachedDuration_l(&cachedDurationUs, &eos)) {
         if ((mFlags & PLAYING) && !eos
-                && (queueDurationUs < kLowWaterMarkSecs * 1000000ll)) {
-            LOGI("rtsp cache is running low, pausing.");
+                && (cachedDurationUs < kLowWaterMarkUs)) {
+            LOGI("cache is running low (%.2f secs) , pausing.",
+                 cachedDurationUs / 1E6);
             mFlags |= CACHE_UNDERRUN;
             pause_l();
             notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
-        } else if ((mFlags & CACHE_UNDERRUN)
-                && (eos || queueDurationUs > kHighWaterMarkSecs * 1000000ll)) {
-            LOGI("rtsp cache has filled up, resuming.");
-            mFlags &= ~CACHE_UNDERRUN;
-            play_l();
-            notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
-        }
-
-        postBufferingEvent_l();
-        return;
-    }
-
-    if (mCachedSource == NULL) {
-        return;
-    }
-
-    bool eos;
-    size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
-
-    size_t lowWatermark = 400000;
-    size_t highWatermark = 1000000;
-
-    if (eos) {
-        notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
-    } else {
-        off_t size;
-        if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) {
-            int64_t bitrate = size * 8000000ll / mDurationUs;  // in bits/sec
-
-            size_t cachedSize = mCachedSource->cachedSize();
-            int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
-
-            int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
-            if (percentage > 100) {
-                percentage = 100;
+        } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
+            if (mFlags & CACHE_UNDERRUN) {
+                LOGI("cache has filled up (%.2f secs), resuming.",
+                     cachedDurationUs / 1E6);
+                mFlags &= ~CACHE_UNDERRUN;
+                play_l();
+                notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
+            } else if (mFlags & PREPARING) {
+                LOGV("cache has filled up (%.2f secs), prepare is done",
+                     cachedDurationUs / 1E6);
+                finishAsyncPrepare_l();
             }
-
-            notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
-
-            lowWatermark = kLowWaterMarkSecs * bitrate / 8;
-            highWatermark = kHighWaterMarkSecs * bitrate / 8;
         }
     }
 
-    if ((mFlags & PLAYING) && !eos && (cachedDataRemaining < lowWatermark)) {
-        LOGI("cache is running low (< %d) , pausing.", lowWatermark);
-        mFlags |= CACHE_UNDERRUN;
-        pause_l();
-        notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
-    } else if ((mFlags & CACHE_UNDERRUN)
-            && (eos || cachedDataRemaining > highWatermark)) {
-        LOGI("cache has filled up (> %d), resuming.", highWatermark);
-        mFlags &= ~CACHE_UNDERRUN;
-        play_l();
-        notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
-    }
-
     postBufferingEvent_l();
 }
 
@@ -561,7 +594,7 @@
         return;
     }
 
-    if (mFlags & LOOPING) {
+    if (mFlags & (LOOPING | AUTO_LOOPING)) {
         seekTo_l(0);
 
         if (mVideoSource != NULL) {
@@ -1437,45 +1470,49 @@
 }
 
 void AwesomePlayer::onPrepareAsyncEvent() {
-    {
-        Mutex::Autolock autoLock(mLock);
+    Mutex::Autolock autoLock(mLock);
 
-        if (mFlags & PREPARE_CANCELLED) {
-            LOGI("prepare was cancelled before doing anything");
-            abortPrepare(UNKNOWN_ERROR);
+    if (mFlags & PREPARE_CANCELLED) {
+        LOGI("prepare was cancelled before doing anything");
+        abortPrepare(UNKNOWN_ERROR);
+        return;
+    }
+
+    if (mUri.size() > 0) {
+        status_t err = finishSetDataSource_l();
+
+        if (err != OK) {
+            abortPrepare(err);
             return;
         }
-
-        if (mUri.size() > 0) {
-            status_t err = finishSetDataSource_l();
-
-            if (err != OK) {
-                abortPrepare(err);
-                return;
-            }
-        }
-
-        if (mVideoTrack != NULL && mVideoSource == NULL) {
-            status_t err = initVideoDecoder();
-
-            if (err != OK) {
-                abortPrepare(err);
-                return;
-            }
-        }
-
-        if (mAudioTrack != NULL && mAudioSource == NULL) {
-            status_t err = initAudioDecoder();
-
-            if (err != OK) {
-                abortPrepare(err);
-                return;
-            }
-        }
     }
 
-    Mutex::Autolock autoLock(mLock);
+    if (mVideoTrack != NULL && mVideoSource == NULL) {
+        status_t err = initVideoDecoder();
 
+        if (err != OK) {
+            abortPrepare(err);
+            return;
+        }
+    }
+
+    if (mAudioTrack != NULL && mAudioSource == NULL) {
+        status_t err = initAudioDecoder();
+
+        if (err != OK) {
+            abortPrepare(err);
+            return;
+        }
+    }
+
+    if (mCachedSource != NULL || mRTSPController != NULL) {
+        postBufferingEvent_l();
+    } else {
+        finishAsyncPrepare_l();
+    }
+}
+
+void AwesomePlayer::finishAsyncPrepare_l() {
     if (mIsAsyncPrepare) {
         if (mVideoWidth < 0 || mVideoHeight < 0) {
             notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
@@ -1491,8 +1528,6 @@
     mFlags |= PREPARED;
     mAsyncPrepareEvent = NULL;
     mPreparedCondition.broadcast();
-
-    postBufferingEvent_l();
 }
 
 status_t AwesomePlayer::suspend() {
@@ -1532,7 +1567,7 @@
     state->mUriHeaders = mUriHeaders;
     state->mFileSource = mFileSource;
 
-    state->mFlags = mFlags & (PLAYING | LOOPING | AT_EOS);
+    state->mFlags = mFlags & (PLAYING | AUTO_LOOPING | LOOPING | AT_EOS);
     getPosition(&state->mPositionUs);
 
     if (mLastVideoBuffer) {
@@ -1593,7 +1628,7 @@
 
     seekTo_l(state->mPositionUs);
 
-    mFlags = state->mFlags & (LOOPING | AT_EOS);
+    mFlags = state->mFlags & (AUTO_LOOPING | LOOPING | AT_EOS);
 
     if (state->mLastVideoFrame && mISurface != NULL) {
         mVideoRenderer =
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index a15b84e..806836d 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -32,12 +32,12 @@
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/Utils.h>
 #include <media/mediarecorder.h>
-#include <cutils/properties.h>
 
 #include "include/ESDS.h"
 
 namespace android {
 
+static const int64_t kMax32BitFileSize = 0x007fffffffLL;
 static const uint8_t kNalUnitTypeSeqParamSet = 0x07;
 static const uint8_t kNalUnitTypePicParamSet = 0x08;
 
@@ -59,7 +59,7 @@
     bool isAvc() const { return mIsAvc; }
     bool isAudio() const { return mIsAudio; }
     bool isMPEG4() const { return mIsMPEG4; }
-    void addChunkOffset(off_t offset) { mChunkOffsets.push_back(offset); }
+    void addChunkOffset(off_t offset);
     status_t dump(int fd, const Vector<String16>& args) const;
 
 private:
@@ -79,7 +79,7 @@
     bool mIsRealTimeRecording;
     int64_t mMaxTimeStampUs;
     int64_t mEstimatedTrackSizeBytes;
-    int64_t mMaxWriteTimeUs;
+    int64_t mMdatSizeBytes;
     int32_t mTimeScale;
 
     pthread_t mThread;
@@ -92,8 +92,11 @@
     bool                mSamplesHaveSameSize;
 
     List<MediaBuffer *> mChunkSamples;
+
+    size_t              mNumStcoTableEntries;
     List<off_t>         mChunkOffsets;
 
+    size_t              mNumStscTableEntries;
     struct StscTableEntry {
 
         StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id)
@@ -107,9 +110,10 @@
     };
     List<StscTableEntry> mStscTableEntries;
 
+    size_t        mNumStssTableEntries;
     List<int32_t> mStssTableEntries;
-    List<int64_t> mChunkDurations;
 
+    size_t        mNumSttsTableEntries;
     struct SttsTableEntry {
 
         SttsTableEntry(uint32_t count, uint32_t durationUs)
@@ -161,12 +165,6 @@
     void trackProgressStatus(int64_t timeUs, status_t err = OK);
     void initTrackingProgressStatus(MetaData *params);
 
-    // Utilities for collecting statistical data
-    void logStatisticalData(bool isAudio);
-    void findMinAvgMaxSampleDurationMs(
-            int32_t *min, int32_t *avg, int32_t *max);
-    void findMinMaxChunkDurations(int64_t *min, int64_t *max);
-
     void getCodecSpecificDataFromInputFormatIfPossible();
 
     // Determine the track time scale
@@ -178,14 +176,18 @@
     // Simple validation on the codec specific data
     status_t checkCodecSpecificData() const;
 
+    void updateTrackSizeEstimate();
+    void addOneStscTableEntry(size_t chunkId, size_t sampleId);
+    void addOneStssTableEntry(size_t sampleId);
+    void addOneSttsTableEntry(size_t sampleCount, int64_t durationUs);
+
     Track(const Track &);
     Track &operator=(const Track &);
 };
 
-#define USE_NALLEN_FOUR         1
-
 MPEG4Writer::MPEG4Writer(const char *filename)
     : mFile(fopen(filename, "wb")),
+      mUse4ByteNalLength(true),
       mUse32BitOffset(true),
       mPaused(false),
       mStarted(false),
@@ -198,6 +200,7 @@
 
 MPEG4Writer::MPEG4Writer(int fd)
     : mFile(fdopen(fd, "wb")),
+      mUse4ByteNalLength(true),
       mUse32BitOffset(true),
       mPaused(false),
       mStarted(false),
@@ -211,9 +214,11 @@
 MPEG4Writer::~MPEG4Writer() {
     stop();
 
-    for (List<Track *>::iterator it = mTracks.begin();
-         it != mTracks.end(); ++it) {
+    while (!mTracks.empty()) {
+        List<Track *>::iterator it = mTracks.begin();
         delete *it;
+        (*it) = NULL;
+        mTracks.erase(it);
     }
     mTracks.clear();
 }
@@ -332,11 +337,26 @@
         mUse32BitOffset = false;
     }
 
-    // System property can overwrite the file offset bits parameter
-    char value[PROPERTY_VALUE_MAX];
-    if (property_get("media.stagefright.record-64bits", value, NULL)
-        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
-        mUse32BitOffset = false;
+    if (mUse32BitOffset) {
+        // Implicit 32 bit file size limit
+        if (mMaxFileSizeLimitBytes == 0) {
+            mMaxFileSizeLimitBytes = kMax32BitFileSize;
+        }
+
+        // If file size is set to be larger than the 32 bit file
+        // size limit, treat it as an error.
+        if (mMaxFileSizeLimitBytes > kMax32BitFileSize) {
+            LOGE("32-bit file size limit too big: %lld bytes",
+                mMaxFileSizeLimitBytes);
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    int32_t use2ByteNalLength;
+    if (param &&
+        param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) &&
+        use2ByteNalLength) {
+        mUse4ByteNalLength = false;
     }
 
     mStartTimestampUs = -1;
@@ -413,6 +433,10 @@
     return OK;
 }
 
+bool MPEG4Writer::use32BitFileOffset() const {
+    return mUse32BitOffset;
+}
+
 status_t MPEG4Writer::pause() {
     if (mFile == NULL) {
         return OK;
@@ -607,32 +631,30 @@
 
     size_t length = buffer->range_length();
 
-#if USE_NALLEN_FOUR
-    uint8_t x = length >> 24;
-    fwrite(&x, 1, 1, mFile);
-    x = (length >> 16) & 0xff;
-    fwrite(&x, 1, 1, mFile);
-    x = (length >> 8) & 0xff;
-    fwrite(&x, 1, 1, mFile);
-    x = length & 0xff;
-    fwrite(&x, 1, 1, mFile);
-#else
-    CHECK(length < 65536);
+    if (mUse4ByteNalLength) {
+        uint8_t x = length >> 24;
+        fwrite(&x, 1, 1, mFile);
+        x = (length >> 16) & 0xff;
+        fwrite(&x, 1, 1, mFile);
+        x = (length >> 8) & 0xff;
+        fwrite(&x, 1, 1, mFile);
+        x = length & 0xff;
+        fwrite(&x, 1, 1, mFile);
 
-    uint8_t x = length >> 8;
-    fwrite(&x, 1, 1, mFile);
-    x = length & 0xff;
-    fwrite(&x, 1, 1, mFile);
-#endif
+        fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
+                1, length, mFile);
+        mOffset += length + 4;
+    } else {
+        CHECK(length < 65536);
 
-    fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
-           1, length, mFile);
-
-#if USE_NALLEN_FOUR
-    mOffset += length + 4;
-#else
-    mOffset += length + 2;
-#endif
+        uint8_t x = length >> 8;
+        fwrite(&x, 1, 1, mFile);
+        x = length & 0xff;
+        fwrite(&x, 1, 1, mFile);
+        fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
+                1, length, mFile);
+        mOffset += length + 2;
+    }
 
     return old_offset;
 }
@@ -739,7 +761,8 @@
          it != mTracks.end(); ++it) {
         nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
     }
-    return (nTotalBytesEstimate >= mMaxFileSizeLimitBytes);
+
+    return (nTotalBytesEstimate  + 1024 >= mMaxFileSizeLimitBytes);
 }
 
 bool MPEG4Writer::exceedsFileDurationLimit() {
@@ -819,6 +842,48 @@
     setTimeScale();
 }
 
+void MPEG4Writer::Track::updateTrackSizeEstimate() {
+
+    int64_t stcoBoxSizeBytes = mOwner->use32BitFileOffset()
+                                ? mNumStcoTableEntries * 4
+                                : mNumStcoTableEntries * 8;
+
+    int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mNumSamples * 4);
+
+    mEstimatedTrackSizeBytes = mMdatSizeBytes +             // media data size
+                               mNumStscTableEntries * 12 +  // stsc box size
+                               mNumStssTableEntries * 4 +   // stss box size
+                               mNumSttsTableEntries * 8 +   // stts box size
+                               stcoBoxSizeBytes +           // stco box size
+                               stszBoxSizeBytes;            // stsz box size
+}
+
+void MPEG4Writer::Track::addOneStscTableEntry(
+        size_t chunkId, size_t sampleId) {
+
+        StscTableEntry stscEntry(chunkId, sampleId, 1);
+        mStscTableEntries.push_back(stscEntry);
+        ++mNumStscTableEntries;
+}
+
+void MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) {
+    mStssTableEntries.push_back(sampleId);
+    ++mNumStssTableEntries;
+}
+
+void MPEG4Writer::Track::addOneSttsTableEntry(
+        size_t sampleCount, int64_t durationUs) {
+
+    SttsTableEntry sttsEntry(sampleCount, durationUs);
+    mSttsTableEntries.push_back(sttsEntry);
+    ++mNumSttsTableEntries;
+}
+
+void MPEG4Writer::Track::addChunkOffset(off_t offset) {
+    ++mNumStcoTableEntries;
+    mChunkOffsets.push_back(offset);
+}
+
 void MPEG4Writer::Track::setTimeScale() {
     LOGV("setTimeScale");
     // Default time scale
@@ -1039,6 +1104,7 @@
     return OK;
 }
 
+
 status_t MPEG4Writer::Track::start(MetaData *params) {
     if (!mDone && mPaused) {
         mPaused = false;
@@ -1077,6 +1143,11 @@
     mTrackDurationUs = 0;
     mReachedEOS = false;
     mEstimatedTrackSizeBytes = 0;
+    mNumStcoTableEntries = 0;
+    mNumStssTableEntries = 0;
+    mNumStscTableEntries = 0;
+    mNumSttsTableEntries = 0;
+    mMdatSizeBytes = 0;
 
     pthread_create(&mThread, &attr, ThreadWrapper, this);
     pthread_attr_destroy(&attr);
@@ -1123,46 +1194,6 @@
     return (void *) err;
 }
 
-#include <ctype.h>
-static void hexdump(const void *_data, size_t size) {
-    const uint8_t *data = (const uint8_t *)_data;
-    size_t offset = 0;
-    while (offset < size) {
-        printf("0x%04x  ", offset);
-
-        size_t n = size - offset;
-        if (n > 16) {
-            n = 16;
-        }
-
-        for (size_t i = 0; i < 16; ++i) {
-            if (i == 8) {
-                printf(" ");
-            }
-
-            if (offset + i < size) {
-                printf("%02x ", data[offset + i]);
-            } else {
-                printf("   ");
-            }
-        }
-
-        printf(" ");
-
-        for (size_t i = 0; i < n; ++i) {
-            if (isprint(data[offset + i])) {
-                printf("%c", data[offset + i]);
-            } else {
-                printf(".");
-            }
-        }
-
-        printf("\n");
-
-        offset += 16;
-    }
-}
-
 static void getNalUnitType(uint8_t byte, uint8_t* type) {
     LOGV("getNalUnitType: %d", byte);
 
@@ -1334,7 +1365,6 @@
 
 status_t MPEG4Writer::Track::makeAVCCodecSpecificData(
         const uint8_t *data, size_t size) {
-    // hexdump(data, size);
 
     if (mCodecSpecificData != NULL) {
         LOGE("Already have codec specific data");
@@ -1365,11 +1395,11 @@
     header[3] = mLevelIdc;
 
     // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne
-#if USE_NALLEN_FOUR
-    header[4] = 0xfc | 3;  // length size == 4 bytes
-#else
-    header[4] = 0xfc | 1;  // length size == 2 bytes
-#endif
+    if (mOwner->useNalLengthFour()) {
+        header[4] = 0xfc | 3;  // length size == 4 bytes
+    } else {
+        header[4] = 0xfc | 1;  // length size == 2 bytes
+    }
 
     // 3-bit '111' followed by 5-bit numSequenceParameterSets
     int nSequenceParamSets = mSeqParamSets.size();
@@ -1406,15 +1436,6 @@
     return OK;
 }
 
-static bool collectStatisticalData() {
-    char value[PROPERTY_VALUE_MAX];
-    if (property_get("media.stagefright.record-stats", value, NULL)
-        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
-        return true;
-    }
-    return false;
-}
-
 status_t MPEG4Writer::Track::threadEntry() {
     int32_t count = 0;
     const int64_t interleaveDurationUs = mOwner->interleaveDuration();
@@ -1430,14 +1451,9 @@
     int64_t previousPausedDurationUs = 0;
     int64_t timestampUs;
 
-    int64_t wallClockTimeUs = 0;
-    int64_t lastWallClockTimeUs = 0;
-
     sp<MetaData> meta_data;
-    bool collectStats = collectStatisticalData();
 
     mNumSamples = 0;
-    mMaxWriteTimeUs = 0;
     status_t err = OK;
     MediaBuffer *buffer;
     while (!mDone && (err = mSource->read(&buffer)) == OK) {
@@ -1498,17 +1514,19 @@
 
         if (mIsAvc) StripStartcode(copy);
 
-        size_t sampleSize;
-        sampleSize = mIsAvc
-#if USE_NALLEN_FOUR
-                ? copy->range_length() + 4
-#else
-                ? copy->range_length() + 2
-#endif
-                : copy->range_length();
+        size_t sampleSize = copy->range_length();
+        if (mIsAvc) {
+            if (mOwner->useNalLengthFour()) {
+                sampleSize += 4;
+            } else {
+                sampleSize += 2;
+            }
+        }
 
         // Max file size or duration handling
-        mEstimatedTrackSizeBytes += sampleSize;
+        mMdatSizeBytes += sampleSize;
+        updateTrackSizeEstimate();
+
         if (mOwner->exceedsFileSizeLimit()) {
             mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
             break;
@@ -1542,14 +1560,15 @@
             // of neighboring samples. This in turn helps reduce the track header size,
             // especially, the number of entries in the "stts" box.
             if (mNumSamples > 1) {
-                int64_t durationUs = timestampUs + mOwner->getDriftTimeUs() - lastTimestampUs;
+                int64_t currDriftTimeUs = mOwner->getDriftTimeUs();
+                int64_t durationUs = timestampUs + currDriftTimeUs - lastTimestampUs;
                 int64_t diffUs = (durationUs > lastDurationUs)
                             ? durationUs - lastDurationUs
                             : lastDurationUs - durationUs;
                 if (diffUs <= 5000) {  // XXX: Magic number 5ms
                     timestampUs = lastTimestampUs + lastDurationUs;
                 } else {
-                    timestampUs += mOwner->getDriftTimeUs();
+                    timestampUs += currDriftTimeUs;
                 }
             }
         }
@@ -1557,12 +1576,6 @@
         if (mNumSamples > 1) {
             if (timestampUs <= lastTimestampUs) {
                 LOGW("Frame arrives too late!");
-#if 0
-                // Drop the late frame.
-                copy->release();
-                copy = NULL;
-                continue;
-#else
                 // Don't drop the late frame, since dropping a frame may cause
                 // problems later during playback
 
@@ -1573,7 +1586,6 @@
                 } else {
                     timestampUs = lastTimestampUs + (1000000LL + (mTimeScale >> 1)) / mTimeScale;
                 }
-#endif
             }
         }
 
@@ -1596,8 +1608,7 @@
                      (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
 
             if (currDurationTicks != lastDurationTicks) {
-                SttsTableEntry sttsEntry(sampleCount, lastDurationUs);
-                mSttsTableEntries.push_back(sttsEntry);
+                addOneSttsTableEntry(sampleCount, lastDurationUs);
                 sampleCount = 1;
             } else {
                 ++sampleCount;
@@ -1613,16 +1624,14 @@
         lastDurationTicks = currDurationTicks;
         lastTimestampUs = timestampUs;
         if (mIsRealTimeRecording && mIsAudio) {
-            wallClockTimeUs = systemTime() / 1000;
-            int64_t wallClockDurationUs = wallClockTimeUs - lastWallClockTimeUs;
-            if (mNumSamples > 2) {
-                mOwner->addDriftTimeUs(lastDurationUs - wallClockDurationUs);
+            int64_t driftTimeUs = 0;
+            if (meta_data->findInt64(kKeyDriftTime, &driftTimeUs)) {
+                mOwner->setDriftTimeUs(driftTimeUs);
             }
-            lastWallClockTimeUs = wallClockTimeUs;
         }
 
         if (isSync != 0) {
-            mStssTableEntries.push_back(mNumSamples);
+            addOneStssTableEntry(mNumSamples);
         }
 
         if (mTrackingProgressStatus) {
@@ -1635,7 +1644,7 @@
             off_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy)
                                  : mOwner->addSample_l(copy);
             if (mChunkOffsets.empty()) {
-                mChunkOffsets.push_back(offset);
+                addChunkOffset(offset);
             }
             copy->release();
             copy = NULL;
@@ -1644,8 +1653,7 @@
 
         mChunkSamples.push_back(copy);
         if (interleaveDurationUs == 0) {
-            StscTableEntry stscEntry(++nChunks, 1, 1);
-            mStscTableEntries.push_back(stscEntry);
+            addOneStscTableEntry(++nChunks, 1);
             bufferChunk(timestampUs);
         } else {
             if (chunkTimestampUs == 0) {
@@ -1653,15 +1661,10 @@
             } else {
                 if (timestampUs - chunkTimestampUs > interleaveDurationUs) {
                     ++nChunks;
-                    if (collectStats) {
-                        mChunkDurations.push_back(timestampUs - chunkTimestampUs);
-                    }
                     if (nChunks == 1 ||  // First chunk
                         (--(mStscTableEntries.end()))->samplesPerChunk !=
                          mChunkSamples.size()) {
-                        StscTableEntry stscEntry(nChunks,
-                                mChunkSamples.size(), 1);
-                        mStscTableEntries.push_back(stscEntry);
+                        addOneStscTableEntry(nChunks, mChunkSamples.size());
                     }
                     bufferChunk(timestampUs);
                     chunkTimestampUs = timestampUs;
@@ -1680,12 +1683,9 @@
 
     // Last chunk
     if (mOwner->numTracks() == 1) {
-        StscTableEntry stscEntry(1, mNumSamples, 1);
-        mStscTableEntries.push_back(stscEntry);
+        addOneStscTableEntry(1, mNumSamples);
     } else if (!mChunkSamples.empty()) {
-        ++nChunks;
-        StscTableEntry stscEntry(nChunks, mChunkSamples.size(), 1);
-        mStscTableEntries.push_back(stscEntry);
+        addOneStscTableEntry(++nChunks, mChunkSamples.size());
         bufferChunk(timestampUs);
     }
 
@@ -1697,14 +1697,12 @@
     } else {
         ++sampleCount;  // Count for the last sample
     }
-    SttsTableEntry sttsEntry(sampleCount, lastDurationUs);
-    mSttsTableEntries.push_back(sttsEntry);
+    addOneSttsTableEntry(sampleCount, lastDurationUs);
     mTrackDurationUs += lastDurationUs;
     mReachedEOS = true;
-    LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. Max write time: %lld us - %s",
-            count, nZeroLengthFrames, mNumSamples, mMaxWriteTimeUs, mIsAudio? "audio": "video");
+    LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s",
+            count, nZeroLengthFrames, mNumSamples, mIsAudio? "audio": "video");
 
-    logStatisticalData(mIsAudio);
     if (err == ERROR_END_OF_STREAM) {
         return OK;
     }
@@ -1729,17 +1727,6 @@
     CHECK(nTracks < 64);  // Arbitrary number
 
     int32_t trackNum = 0;
-#if 0
-    // In the worst case, we can put the trackNum
-    // along with MEDIA_RECORDER_INFO_COMPLETION_STATUS
-    // to report the progress.
-    for (List<Track *>::iterator it = mTracks.begin();
-         it != mTracks.end(); ++it, ++trackNum) {
-        if (track == (*it)) {
-            break;
-        }
-    }
-#endif
     CHECK(trackNum < nTracks);
     trackNum <<= 16;
 
@@ -1766,95 +1753,10 @@
     }
 }
 
-void MPEG4Writer::Track::findMinAvgMaxSampleDurationMs(
-        int32_t *min, int32_t *avg, int32_t *max) {
-    CHECK(!mSampleSizes.empty());
-    int32_t avgSampleDurationMs = mTrackDurationUs / 1000 / mNumSamples;
-    int32_t minSampleDurationMs = 0x7FFFFFFF;
-    int32_t maxSampleDurationMs = 0;
-    for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
-        it != mSttsTableEntries.end(); ++it) {
-        int32_t sampleDurationMs =
-            (static_cast<int32_t>(it->sampleDurationUs) + 500) / 1000;
-        if (sampleDurationMs > maxSampleDurationMs) {
-            maxSampleDurationMs = sampleDurationMs;
-        } else if (sampleDurationMs < minSampleDurationMs) {
-            minSampleDurationMs = sampleDurationMs;
-        }
-        LOGI("sample duration: %d ms", sampleDurationMs);
-    }
-    CHECK(minSampleDurationMs != 0);
-    CHECK(avgSampleDurationMs != 0);
-    CHECK(maxSampleDurationMs != 0);
-    *min = minSampleDurationMs;
-    *avg = avgSampleDurationMs;
-    *max = maxSampleDurationMs;
-}
-
-// Don't count the last duration
-void MPEG4Writer::Track::findMinMaxChunkDurations(int64_t *min, int64_t *max) {
-    int64_t duration = mOwner->interleaveDuration();
-    int64_t minChunkDuration = duration;
-    int64_t maxChunkDuration = duration;
-    if (mChunkDurations.size() > 1) {
-        for (List<int64_t>::iterator it = mChunkDurations.begin();
-            it != --mChunkDurations.end(); ++it) {
-            if (minChunkDuration > (*it)) {
-                minChunkDuration = (*it);
-            } else if (maxChunkDuration < (*it)) {
-                maxChunkDuration = (*it);
-            }
-        }
-    }
-    *min = minChunkDuration;
-    *max = maxChunkDuration;
-}
-
-void MPEG4Writer::Track::logStatisticalData(bool isAudio) {
-    if (mTrackDurationUs <= 0 || mSampleSizes.empty()) {
-        LOGI("nothing is recorded");
-        return;
-    }
-
-    bool collectStats = collectStatisticalData();
-
-    if (collectStats) {
-        LOGI("%s track - duration %lld us, total %d frames",
-                isAudio? "audio": "video", mTrackDurationUs,
-                mNumSamples);
-        int32_t min, avg, max;
-        findMinAvgMaxSampleDurationMs(&min, &avg, &max);
-        LOGI("min/avg/max sample duration (ms): %d/%d/%d", min, avg, max);
-        if (!isAudio) {
-            float avgFps = 1000.0 / avg;
-            float minFps = 1000.0 / max;
-            float maxFps = 1000.0 / min;
-            LOGI("min/avg/max frame rate (fps): %.2f/%.2f/%.2f",
-                minFps, avgFps, maxFps);
-        }
-
-        int64_t totalBytes = 0;
-        for (List<size_t>::iterator it = mSampleSizes.begin();
-            it != mSampleSizes.end(); ++it) {
-            totalBytes += (*it);
-        }
-        float bitRate = (totalBytes * 8000000.0) / mTrackDurationUs;
-        LOGI("avg bit rate (bps): %.2f", bitRate);
-
-        int64_t duration = mOwner->interleaveDuration();
-        if (duration != 0) {  // If interleaving is enabled
-            int64_t minChunk, maxChunk;
-            findMinMaxChunkDurations(&minChunk, &maxChunk);
-            LOGI("min/avg/max chunk duration (ms): %lld/%lld/%lld",
-                minChunk, duration, maxChunk);
-        }
-    }
-}
-
-void MPEG4Writer::addDriftTimeUs(int64_t driftTimeUs) {
-    LOGV("addDriftTimeUs: %lld us", driftTimeUs);
+void MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) {
+    LOGV("setDriftTimeUs: %lld us", driftTimeUs);
     Mutex::Autolock autolock(mLock);
-    mDriftTimeUs += driftTimeUs;
+    mDriftTimeUs = driftTimeUs;
 }
 
 int64_t MPEG4Writer::getDriftTimeUs() {
@@ -1863,17 +1765,16 @@
     return mDriftTimeUs;
 }
 
+bool MPEG4Writer::useNalLengthFour() {
+    return mUse4ByteNalLength;
+}
+
 void MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
     LOGV("bufferChunk");
 
-    int64_t startTimeUs = systemTime() / 1000;
     Chunk chunk(this, timestampUs, mChunkSamples);
     mOwner->bufferChunk(chunk);
     mChunkSamples.clear();
-    int64_t endTimeUs = systemTime() / 1000;
-    if (mMaxWriteTimeUs < endTimeUs - startTimeUs) {
-        mMaxWriteTimeUs = endTimeUs - startTimeUs;
-    }
 }
 
 int64_t MPEG4Writer::Track::getDurationUs() const {
@@ -2226,7 +2127,7 @@
 
           mOwner->beginBox("stts");
             mOwner->writeInt32(0);  // version=0, flags=0
-            mOwner->writeInt32(mSttsTableEntries.size());
+            mOwner->writeInt32(mNumSttsTableEntries);
             int64_t prevTimestampUs = 0;
             for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
                  it != mSttsTableEntries.end(); ++it) {
@@ -2246,7 +2147,7 @@
           if (!mIsAudio) {
             mOwner->beginBox("stss");
               mOwner->writeInt32(0);  // version=0, flags=0
-              mOwner->writeInt32(mStssTableEntries.size());  // number of sync frames
+              mOwner->writeInt32(mNumStssTableEntries);  // number of sync frames
               for (List<int32_t>::iterator it = mStssTableEntries.begin();
                    it != mStssTableEntries.end(); ++it) {
                   mOwner->writeInt32(*it);
@@ -2273,7 +2174,7 @@
 
           mOwner->beginBox("stsc");
             mOwner->writeInt32(0);  // version=0, flags=0
-            mOwner->writeInt32(mStscTableEntries.size());
+            mOwner->writeInt32(mNumStscTableEntries);
             for (List<StscTableEntry>::iterator it = mStscTableEntries.begin();
                  it != mStscTableEntries.end(); ++it) {
                 mOwner->writeInt32(it->firstChunk);
@@ -2283,7 +2184,7 @@
           mOwner->endBox();  // stsc
           mOwner->beginBox(use32BitOffset? "stco": "co64");
             mOwner->writeInt32(0);  // version=0, flags=0
-            mOwner->writeInt32(mChunkOffsets.size());
+            mOwner->writeInt32(mNumStcoTableEntries);
             for (List<off_t>::iterator it = mChunkOffsets.begin();
                  it != mChunkOffsets.end(); ++it) {
                 if (use32BitOffset) {
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 2c1311a..7a8cf32 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -592,6 +592,7 @@
         { "DATE", kKeyDate },
         { "LYRICIST", kKeyWriter },
         { "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
+        { "ANDROID_LOOP", kKeyAutoLoop },
     };
 
     for (int i = 0; i < mVc.comments; ++i) {
@@ -605,12 +606,15 @@
                     extractAlbumArt(
                             &comment[tagLen + 1],
                             mVc.comment_lengths[i] - tagLen - 1);
+                } else if (kMap[j].mKey == kKeyAutoLoop) {
+                    if (!strcasecmp(&comment[tagLen + 1], "true")) {
+                        mFileMeta->setInt32(kKeyAutoLoop, true);
+                    }
                 } else {
                     mFileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
                 }
             }
         }
-
     }
 
 #if 0
diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
index 052c354..e391c72 100644
--- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
@@ -208,6 +208,8 @@
     MediaBuffer *buffer;
     CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
     uint8_t *outPtr = (uint8_t *)buffer->data();
+    bool readFromSource = false;
+    int64_t wallClockTimeUs = -1;
 
     if (mFrameCount == 0) {
         memcpy(outPtr, mAudioSpecificConfigData, 2);
@@ -238,9 +240,15 @@
             CHECK_EQ(align, 0);
 
             int64_t timeUs;
+            if (mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs)) {
+                wallClockTimeUs = timeUs;
+            }
             if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
                 mAnchorTimeUs = timeUs;
             }
+            readFromSource = true;
+        } else {
+            readFromSource = false;
         }
         size_t copy =
             (kNumSamplesPerFrame - mNumInputSamples) * sizeof(int16_t);
@@ -288,9 +296,13 @@
     CHECK(outputData.Length != 0);
     buffer->set_range(0, outputData.Length);
 
-    int64_t timestampUs = ((mFrameCount - 1) * 1000000LL * kNumSamplesPerFrame) / mSampleRate;
+    int64_t mediaTimeUs =
+        ((mFrameCount - 1) * 1000000LL * kNumSamplesPerFrame) / mSampleRate;
+    buffer->meta_data()->setInt64(kKeyTime, mAnchorTimeUs + mediaTimeUs);
+    if (readFromSource && wallClockTimeUs != -1) {
+        buffer->meta_data()->setInt64(kKeyDriftTime, mediaTimeUs - wallClockTimeUs);
+    }
     ++mFrameCount;
-    buffer->meta_data()->setInt64(kKeyTime, timestampUs);
 
     *out = buffer;
     return OK;
diff --git a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
index c875426..858e6d0 100644
--- a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
@@ -147,6 +147,8 @@
     int64_t seekTimeUs;
     ReadOptions::SeekMode mode;
     CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &mode));
+    bool readFromSource = false;
+    int64_t wallClockTimeUs = -1;
 
     while (mNumInputSamples < kNumSamplesPerFrame) {
         if (mInputBuffer == NULL) {
@@ -166,12 +168,17 @@
 
             size_t align = mInputBuffer->range_length() % sizeof(int16_t);
             CHECK_EQ(align, 0);
+            readFromSource = true;
 
             int64_t timeUs;
+            if (mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs)) {
+                wallClockTimeUs = timeUs;
+            }
             if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
                 mAnchorTimeUs = timeUs;
-                mNumFramesOutput = 0;
             }
+        } else {
+            readFromSource = false;
         }
 
         size_t copy =
@@ -217,8 +224,14 @@
     buffer->set_range(0, res);
 
     // Each frame of 160 samples is 20ms long.
+    int64_t mediaTimeUs = mNumFramesOutput * 20000LL;
     buffer->meta_data()->setInt64(
-            kKeyTime, mAnchorTimeUs + mNumFramesOutput * 20000);
+            kKeyTime, mAnchorTimeUs + mediaTimeUs);
+
+    if (readFromSource && wallClockTimeUs != -1) {
+        buffer->meta_data()->setInt64(kKeyDriftTime,
+            mediaTimeUs - wallClockTimeUs);
+    }
 
     ++mNumFramesOutput;
 
diff --git a/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
index 93304d0..cd28413 100644
--- a/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
+++ b/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
@@ -198,6 +198,8 @@
     int64_t seekTimeUs;
     ReadOptions::SeekMode mode;
     CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &mode));
+    bool readFromSource = false;
+    int64_t wallClockTimeUs = -1;
 
     while (mNumInputSamples < kNumSamplesPerFrame) {
         if (mInputBuffer == NULL) {
@@ -219,9 +221,15 @@
             CHECK_EQ(align, 0);
 
             int64_t timeUs;
+            if (mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs)) {
+                wallClockTimeUs = timeUs;
+            }
             if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
                 mAnchorTimeUs = timeUs;
             }
+            readFromSource = true;
+        } else {
+            readFromSource = false;
         }
 
         size_t copy =
@@ -276,10 +284,11 @@
     buffer->set_range(0, outputData.Length);
     ++mNumFramesOutput;
 
-    // XXX: fix timestamp calculation
-    int64_t timestampUs = mNumFramesOutput * 20000LL;
-
-    buffer->meta_data()->setInt64(kKeyTime, timestampUs);
+    int64_t mediaTimeUs = mNumFramesOutput * 20000LL;
+    buffer->meta_data()->setInt64(kKeyTime, mAnchorTimeUs + mediaTimeUs);
+    if (readFromSource && wallClockTimeUs != -1) {
+        buffer->meta_data()->setInt64(kKeyDriftTime, mediaTimeUs - wallClockTimeUs);
+    }
 
     *out = buffer;
     return OK;
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 55e2c36..1f3946c 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -106,6 +106,7 @@
         CACHE_UNDERRUN      = 128,
         AUDIO_AT_EOS        = 256,
         VIDEO_AT_EOS        = 512,
+        AUTO_LOOPING        = 1024,
     };
 
     mutable Mutex mLock;
@@ -238,6 +239,9 @@
     void onCheckAudioStatus();
     void onPrepareAsyncEvent();
     void abortPrepare(status_t err);
+    void finishAsyncPrepare_l();
+
+    bool getCachedDuration_l(int64_t *durationUs, bool *eos);
 
     status_t finishSetDataSource_l();
 
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 344bfc1..6e8b42e 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -68,6 +68,8 @@
 
     private static final String TAG = "MountService";
 
+    private static final String VOLD_TAG = "VoldConnector";
+
     /*
      * Internal vold volume state constants
      */
@@ -993,9 +995,15 @@
             return;
         }
 
-        mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector");
+        /*
+         * Create the connection to vold with a maximum queue of twice the
+         * amount of containers we'd ever expect to have. This keeps an
+         * "asec list" from blocking a thread repeatedly.
+         */
+        mConnector = new NativeDaemonConnector(this, "vold",
+                PackageManagerService.MAX_CONTAINERS * 2, VOLD_TAG);
         mReady = false;
-        Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
+        Thread thread = new Thread(mConnector, VOLD_TAG);
         thread.start();
     }
 
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index c452590..f3cb9b7 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -109,6 +109,10 @@
                 int count = inputStream.read(buffer, start, BUFFER_SIZE - start);
                 if (count < 0) break;
 
+                // Add our starting point to the count and reset the start.
+                count += start;
+                start = 0;
+
                 for (int i = 0; i < count; i++) {
                     if (buffer[i] == 0) {
                         String event = new String(buffer, start, i - start);
@@ -140,6 +144,9 @@
                         start = i + 1;
                     }
                 }
+
+                // We should end at the amount we read. If not, compact then
+                // buffer and read again.
                 if (start != count) {
                     final int remaining = BUFFER_SIZE - start;
                     System.arraycopy(buffer, start, buffer, 0, remaining);
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index c156150..4a69f20 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -55,6 +55,8 @@
 
     private static final String TAG = "NetworkManagmentService";
 
+    private static final String NETD_TAG = "NetdConnector";
+
     class NetdResponseCode {
         public static final int InterfaceListResult       = 110;
         public static final int TetherInterfaceListResult = 111;
@@ -101,8 +103,8 @@
         }
 
         mConnector = new NativeDaemonConnector(
-                new NetdCallbackReceiver(), "netd", 10, "NetdConnector");
-        Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
+                new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
+        Thread thread = new Thread(mConnector, NETD_TAG);
         thread.start();
     }
 
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 1141fdce..e3480a8 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -2022,7 +2022,11 @@
                     ActivityInfo ai = getActivityInfo(pa.mActivity, flags);
                     if (DEBUG_PREFERRED) {
                         Log.v(TAG, "Got preferred activity:");
-                        ai.dump(new LogPrinter(Log.INFO, TAG), "  ");
+                        if (ai != null) {
+                            ai.dump(new LogPrinter(Log.VERBOSE, TAG), "  ");
+                        } else {
+                            Log.v(TAG, "  null");
+                        }
                     }
                     if (ai != null) {
                         for (int j=0; j<N; j++) {
@@ -9383,17 +9387,18 @@
 
     // ------- apps on sdcard specific code -------
     static final boolean DEBUG_SD_INSTALL = false;
-    final private String mSdEncryptKey = "AppsOnSD";
-    final private String mSdEncryptAlg = "AES";
+    private static final String SD_ENCRYPTION_KEYSTORE_NAME = "AppsOnSD";
+    private static final String SD_ENCRYPTION_ALGORITHM = "AES";
+    static final int MAX_CONTAINERS = 250;
     private boolean mMediaMounted = false;
-    private static final int MAX_CONTAINERS = 250;
 
     private String getEncryptKey() {
         try {
-            String sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString(mSdEncryptKey);
+            String sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString(
+                    SD_ENCRYPTION_KEYSTORE_NAME);
             if (sdEncKey == null) {
-                sdEncKey = SystemKeyStore.getInstance().
-                        generateNewKeyHexString(128, mSdEncryptAlg, mSdEncryptKey);
+                sdEncKey = SystemKeyStore.getInstance().generateNewKeyHexString(128,
+                        SD_ENCRYPTION_ALGORITHM, SD_ENCRYPTION_KEYSTORE_NAME);
                 if (sdEncKey == null) {
                     Slog.e(TAG, "Failed to create encryption keys");
                     return null;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 30dc5ea..89a1627 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -6801,7 +6801,7 @@
                                 app.pid, app.getPackageList());
                     currApp.uid = app.info.uid;
                     if (mHeavyWeightProcess == app) {
-                        currApp.flags |= ActivityManager.RunningAppProcessInfo.FLAG_HEAVY_WEIGHT;
+                        currApp.flags |= ActivityManager.RunningAppProcessInfo.FLAG_CANT_SAVE_STATE;
                     }
                     int adj = app.curAdj;
                     if (adj >= EMPTY_APP_ADJ) {
diff --git a/services/java/com/android/server/sip/SipSessionListenerProxy.java b/services/java/com/android/server/sip/SipSessionListenerProxy.java
index 7004204..7234196 100644
--- a/services/java/com/android/server/sip/SipSessionListenerProxy.java
+++ b/services/java/com/android/server/sip/SipSessionListenerProxy.java
@@ -19,6 +19,7 @@
 import android.net.sip.ISipSession;
 import android.net.sip.ISipSessionListener;
 import android.net.sip.SipProfile;
+import android.os.DeadObjectException;
 import android.util.Log;
 
 /** Class to help safely run a callback in a different thread. */
@@ -49,7 +50,7 @@
                 try {
                     mListener.onCalling(session);
                 } catch (Throwable t) {
-                    Log.w(TAG, "onCalling()", t);
+                    handle(t, "onCalling()");
                 }
             }
         });
@@ -63,7 +64,7 @@
                 try {
                     mListener.onRinging(session, caller, sessionDescription);
                 } catch (Throwable t) {
-                    Log.w(TAG, "onRinging()", t);
+                    handle(t, "onRinging()");
                 }
             }
         });
@@ -76,7 +77,7 @@
                 try {
                     mListener.onRingingBack(session);
                 } catch (Throwable t) {
-                    Log.w(TAG, "onRingingBack()", t);
+                    handle(t, "onRingingBack()");
                 }
             }
         });
@@ -90,7 +91,7 @@
                 try {
                     mListener.onCallEstablished(session, sessionDescription);
                 } catch (Throwable t) {
-                    Log.w(TAG, "onCallEstablished()", t);
+                    handle(t, "onCallEstablished()");
                 }
             }
         });
@@ -103,7 +104,7 @@
                 try {
                     mListener.onCallEnded(session);
                 } catch (Throwable t) {
-                    Log.w(TAG, "onCallEnded()", t);
+                    handle(t, "onCallEnded()");
                 }
             }
         });
@@ -116,7 +117,7 @@
                 try {
                     mListener.onCallBusy(session);
                 } catch (Throwable t) {
-                    Log.w(TAG, "onCallBusy()", t);
+                    handle(t, "onCallBusy()");
                 }
             }
         });
@@ -130,7 +131,7 @@
                 try {
                     mListener.onCallChangeFailed(session, className, message);
                 } catch (Throwable t) {
-                    Log.w(TAG, "onCallChangeFailed()", t);
+                    handle(t, "onCallChangeFailed()");
                 }
             }
         });
@@ -144,7 +145,7 @@
                 try {
                     mListener.onError(session, className, message);
                 } catch (Throwable t) {
-                    Log.w(TAG, "onError()", t);
+                    handle(t, "onError()");
                 }
             }
         });
@@ -157,7 +158,7 @@
                 try {
                     mListener.onRegistering(session);
                 } catch (Throwable t) {
-                    Log.w(TAG, "onRegistering()", t);
+                    handle(t, "onRegistering()");
                 }
             }
         });
@@ -171,7 +172,7 @@
                 try {
                     mListener.onRegistrationDone(session, duration);
                 } catch (Throwable t) {
-                    Log.w(TAG, "onRegistrationDone()", t);
+                    handle(t, "onRegistrationDone()");
                 }
             }
         });
@@ -185,7 +186,7 @@
                 try {
                     mListener.onRegistrationFailed(session, className, message);
                 } catch (Throwable t) {
-                    Log.w(TAG, "onRegistrationFailed()", t);
+                    handle(t, "onRegistrationFailed()");
                 }
             }
         });
@@ -198,9 +199,19 @@
                 try {
                     mListener.onRegistrationTimeout(session);
                 } catch (Throwable t) {
-                    Log.w(TAG, "onRegistrationTimeout()", t);
+                    handle(t, "onRegistrationTimeout()");
                 }
             }
         });
     }
+
+    private void handle(Throwable t, String message) {
+        if (t instanceof DeadObjectException) {
+            mListener = null;
+            // This creates race but it's harmless. Just don't log the error
+            // when it happens.
+        } else if (mListener != null) {
+            Log.w(TAG, message, t);
+        }
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 12df44e..c1232e8 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -1108,14 +1108,21 @@
      */
 
     /**
-     * @return list of ringing calls
+     * @return list of all ringing calls
      */
     public ArrayList<Call> getRingingCalls() {
         return mRingingCalls;
     }
 
     /**
-     * @return list of background calls
+     * @return list of all foreground calls
+     */
+    public ArrayList<Call> getForegroundCalls() {
+        return mForegroundCalls;
+    }
+
+    /**
+     * @return list of all background calls
      */
     public ArrayList<Call> getBackgroundCalls() {
         return mBackgroundCalls;
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 74601e6..ff28773 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -286,7 +286,7 @@
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
         SharedPreferences.Editor editor = sp.edit();
         editor.putBoolean(DNS_SERVER_CHECK_DISABLED_KEY, b);
-        editor.commit();
+        editor.apply();
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index c21b6d9..4508e9a 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -1405,7 +1405,7 @@
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
         SharedPreferences.Editor editor = sp.edit();
         editor.putString(VM_NUMBER_CDMA, number);
-        editor.commit();
+        editor.apply();
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index 8eaf4a2..dceff2a 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -127,7 +127,7 @@
                     mPhone.getContext());
             SharedPreferences.Editor editor = sp.edit();
             editor.putInt(CDMAPhone.VM_COUNT_CDMA, voicemailCount);
-            editor.commit();
+            editor.apply();
             ((CDMAPhone) mPhone).updateMessageWaitingIndicator(voicemailCount);
             handled = true;
         } else if (((SmsEnvelope.TELESERVICE_WMT == teleService) ||
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index c7b1e5c..e5ca519 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -807,7 +807,7 @@
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
         SharedPreferences.Editor editor = sp.edit();
         editor.putString(VM_NUMBER, number);
-        editor.commit();
+        editor.apply();
         setVmSimImsi(getSubscriberId());
     }
 
@@ -830,7 +830,7 @@
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
         SharedPreferences.Editor editor = sp.edit();
         editor.putString(VM_SIM_IMSI, imsi);
-        editor.commit();
+        editor.apply();
     }
 
     public String getVoiceMailAlphaTag() {
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index 1325dd3..6eb619a 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -107,6 +107,10 @@
         return mProfile.getUriString();
     }
 
+    public boolean equals(SipPhone phone) {
+        return getSipUri().equals(phone.getSipUri());
+    }
+
     public boolean canTake(Object incomingCall) {
         synchronized (SipPhone.class) {
             if (!(incomingCall instanceof SipAudioCall)) return false;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index b0f086b..f71ebb9 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -853,6 +853,15 @@
                                     error.string());
                             goto bail;
                         }
+                    } else if (tag == "uses-package") {
+                        String8 name = getAttribute(tree, NAME_ATTR, &error);
+                        if (name != "" && error == "") {
+                            printf("uses-package:'%s'\n", name.string());
+                        } else {
+                            fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
+                                    error.string());
+                                goto bail;
+                        }
                     } else if (tag == "original-package") {
                         String8 name = getAttribute(tree, NAME_ATTR, &error);
                         if (name != "" && error == "") {
diff --git a/voip/java/android/net/sip/SipManager.java b/voip/java/android/net/sip/SipManager.java
index 700fb4e..beec8fe 100644
--- a/voip/java/android/net/sip/SipManager.java
+++ b/voip/java/android/net/sip/SipManager.java
@@ -83,16 +83,22 @@
      * Returns true if the SIP API is supported by the system.
      */
     public static boolean isApiSupported(Context context) {
+        return true;
+        /* 
         return context.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_SIP);
+         */
     }
 
     /**
      * Returns true if the system supports SIP-based VoIP.
      */
     public static boolean isVoipSupported(Context context) {
+        return true;
+        /* 
         return context.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_SIP_VOIP) && isApiSupported(context);
+         */
     }
 
     private SipManager() {