Merge "Reduce footprint of Signature from ~7000 to ~1448" 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/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/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/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 0b6201c..1e447f1 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -92,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/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/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 c05e3e5..e391c72 100644
--- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
@@ -209,7 +209,7 @@
     CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
     uint8_t *outPtr = (uint8_t *)buffer->data();
     bool readFromSource = false;
-    int64_t wallClockTimeUs = 0;
+    int64_t wallClockTimeUs = -1;
 
     if (mFrameCount == 0) {
         memcpy(outPtr, mAudioSpecificConfigData, 2);
@@ -240,8 +240,9 @@
             CHECK_EQ(align, 0);
 
             int64_t timeUs;
-            CHECK(mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs));
-            wallClockTimeUs = timeUs;
+            if (mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs)) {
+                wallClockTimeUs = timeUs;
+            }
             if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
                 mAnchorTimeUs = timeUs;
             }
@@ -298,7 +299,7 @@
     int64_t mediaTimeUs =
         ((mFrameCount - 1) * 1000000LL * kNumSamplesPerFrame) / mSampleRate;
     buffer->meta_data()->setInt64(kKeyTime, mAnchorTimeUs + mediaTimeUs);
-    if (readFromSource) {
+    if (readFromSource && wallClockTimeUs != -1) {
         buffer->meta_data()->setInt64(kKeyDriftTime, mediaTimeUs - wallClockTimeUs);
     }
     ++mFrameCount;
diff --git a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
index dab1390..858e6d0 100644
--- a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
@@ -148,7 +148,7 @@
     ReadOptions::SeekMode mode;
     CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &mode));
     bool readFromSource = false;
-    int64_t wallClockTimeUs = 0;
+    int64_t wallClockTimeUs = -1;
 
     while (mNumInputSamples < kNumSamplesPerFrame) {
         if (mInputBuffer == NULL) {
@@ -171,8 +171,9 @@
             readFromSource = true;
 
             int64_t timeUs;
-            CHECK(mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs));
-            wallClockTimeUs = timeUs;
+            if (mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs)) {
+                wallClockTimeUs = timeUs;
+            }
             if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
                 mAnchorTimeUs = timeUs;
             }
@@ -227,7 +228,7 @@
     buffer->meta_data()->setInt64(
             kKeyTime, mAnchorTimeUs + mediaTimeUs);
 
-    if (readFromSource) {
+    if (readFromSource && wallClockTimeUs != -1) {
         buffer->meta_data()->setInt64(kKeyDriftTime,
             mediaTimeUs - wallClockTimeUs);
     }
diff --git a/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
index b62eb5b..cd28413 100644
--- a/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
+++ b/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
@@ -199,7 +199,7 @@
     ReadOptions::SeekMode mode;
     CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &mode));
     bool readFromSource = false;
-    int64_t wallClockTimeUs = 0;
+    int64_t wallClockTimeUs = -1;
 
     while (mNumInputSamples < kNumSamplesPerFrame) {
         if (mInputBuffer == NULL) {
@@ -221,8 +221,9 @@
             CHECK_EQ(align, 0);
 
             int64_t timeUs;
-            CHECK(mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs));
-            wallClockTimeUs = timeUs;
+            if (mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs)) {
+                wallClockTimeUs = timeUs;
+            }
             if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
                 mAnchorTimeUs = timeUs;
             }
@@ -285,7 +286,7 @@
 
     int64_t mediaTimeUs = mNumFramesOutput * 20000LL;
     buffer->meta_data()->setInt64(kKeyTime, mAnchorTimeUs + mediaTimeUs);
-    if (readFromSource) {
+    if (readFromSource && wallClockTimeUs != -1) {
         buffer->meta_data()->setInt64(kKeyDriftTime, mediaTimeUs - wallClockTimeUs);
     }
 
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/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/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() {