Merge "change the DRT to use Light theme"
diff --git a/Android.mk b/Android.mk
index a73767b..7c848c6 100644
--- a/Android.mk
+++ b/Android.mk
@@ -123,10 +123,6 @@
 	core/java/android/net/IThrottleManager.aidl \
 	core/java/android/os/IHardwareService.aidl \
 	core/java/android/os/IMessenger.aidl \
-	core/java/android/os/storage/IMountService.aidl \
-	core/java/android/os/storage/IMountServiceListener.aidl \
-	core/java/android/os/storage/IMountShutdownObserver.aidl \
-	core/java/android/os/storage/IObbActionListener.aidl \
 	core/java/android/os/INetworkManagementService.aidl \
 	core/java/android/os/INetStatService.aidl \
 	core/java/android/os/IPermissionController.aidl \
@@ -383,8 +379,6 @@
 # (see development/build/sdk.atree)
 web_docs_sample_code_flags := \
 		-hdf android.hasSamples 1 \
-		-samplecode $(sample_dir)/AccessibilityService \
-		            resources/samples/AccessibilityService "Accessibility Service" \
 		-samplecode $(sample_dir)/ApiDemos \
 		            resources/samples/ApiDemos "API Demos" \
 		-samplecode $(sample_dir)/BackupRestore \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index f73e4d5..a9f4d19 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -76,6 +76,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/lib/libhwui.so)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/symbols/system/lib/libhwui.so)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libhwui.so)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/os/storage/*)
 
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/api/current.xml b/api/current.xml
index d935c38..bba70f9 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -16663,7 +16663,7 @@
  visibility="public"
 >
 </field>
-<field name="Theme_Holo_NoTitleBar"
+<field name="Theme_Holo_NoActionBar"
  type="int"
  transient="false"
  volatile="false"
@@ -16674,7 +16674,7 @@
  visibility="public"
 >
 </field>
-<field name="Theme_Holo_NoTitleBar_Fullscreen"
+<field name="Theme_Holo_NoActionBar_Fullscreen"
  type="int"
  transient="false"
  volatile="false"
@@ -16718,7 +16718,7 @@
  visibility="public"
 >
 </field>
-<field name="Theme_Light_Holo_NoTitleBar"
+<field name="Theme_Light_Holo_NoActionBar"
  type="int"
  transient="false"
  volatile="false"
@@ -16729,7 +16729,7 @@
  visibility="public"
 >
 </field>
-<field name="Theme_Light_Holo_NoTitleBar_Fullscreen"
+<field name="Theme_Light_Holo_NoActionBar_Fullscreen"
  type="int"
  transient="false"
  volatile="false"
@@ -20080,6 +20080,17 @@
  visibility="public"
 >
 </method>
+<method name="getDuration"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getFrameDelay"
  return="long"
  abstract="false"
@@ -20091,6 +20102,17 @@
  visibility="public"
 >
 </method>
+<method name="getInterpolator"
+ return="android.view.animation.Interpolator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getRepeatCount"
  return="int"
  abstract="false"
@@ -62851,6 +62873,42 @@
 <parameter name="table" type="java.lang.String">
 </parameter>
 </method>
+<method name="queryNumEntries"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="db" type="android.database.sqlite.SQLiteDatabase">
+</parameter>
+<parameter name="table" type="java.lang.String">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+</method>
+<method name="queryNumEntries"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="db" type="android.database.sqlite.SQLiteDatabase">
+</parameter>
+<parameter name="table" type="java.lang.String">
+</parameter>
+<parameter name="selection" type="java.lang.String">
+</parameter>
+<parameter name="selectionArgs" type="java.lang.String[]">
+</parameter>
+</method>
 <method name="readExceptionFromParcel"
  return="void"
  abstract="false"
@@ -84570,6 +84628,17 @@
  visibility="public"
 >
 </field>
+<field name="TYPE_GRAVITY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="9"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TYPE_GYROSCOPE"
  type="int"
  transient="false"
@@ -84592,6 +84661,17 @@
  visibility="public"
 >
 </field>
+<field name="TYPE_LINEAR_ACCELERATION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="10"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TYPE_MAGNETIC_FIELD"
  type="int"
  transient="false"
@@ -84636,6 +84716,17 @@
  visibility="public"
 >
 </field>
+<field name="TYPE_ROTATION_VECTOR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="11"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TYPE_TEMPERATURE"
  type="int"
  transient="false"
@@ -84795,6 +84886,23 @@
 <parameter name="p" type="float">
 </parameter>
 </method>
+<method name="getAngleChange"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="angleChange" type="float[]">
+</parameter>
+<parameter name="R" type="float[]">
+</parameter>
+<parameter name="prevR" type="float[]">
+</parameter>
+</method>
 <method name="getDefaultSensor"
  return="android.hardware.Sensor"
  abstract="false"
@@ -84836,6 +84944,21 @@
 <parameter name="values" type="float[]">
 </parameter>
 </method>
+<method name="getQuaternionFromVector"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="Q" type="float[]">
+</parameter>
+<parameter name="rv" type="float[]">
+</parameter>
+</method>
 <method name="getRotationMatrix"
  return="boolean"
  abstract="false"
@@ -84855,6 +84978,21 @@
 <parameter name="geomagnetic" type="float[]">
 </parameter>
 </method>
+<method name="getRotationMatrixFromVector"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="R" type="float[]">
+</parameter>
+<parameter name="rotationVector" type="float[]">
+</parameter>
+</method>
 <method name="getSensorList"
  return="java.util.List&lt;android.hardware.Sensor&gt;"
  abstract="false"
@@ -234473,7 +234611,9 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="offset" type="int">
+<parameter name="x" type="int">
+</parameter>
+<parameter name="y" type="int">
 </parameter>
 </method>
 <field name="FADE_OUT_DURATION"
@@ -258044,7 +258184,7 @@
 <method name="copySign"
  return="double"
  abstract="false"
- native="true"
+ native="false"
  synchronized="false"
  static="true"
  final="false"
@@ -258059,7 +258199,7 @@
 <method name="copySign"
  return="float"
  abstract="false"
- native="true"
+ native="false"
  synchronized="false"
  static="true"
  final="false"
@@ -276495,6 +276635,19 @@
 <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"
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index 951d104..385e75d 100755
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.util.AttributeSet;
 import android.view.animation.AccelerateDecelerateInterpolator;
@@ -197,15 +198,13 @@
     /**
      * The property/value sets being animated.
      */
-    HashMap<String, PropertyValuesHolder> mValues;
+    PropertyValuesHolder[] mValues;
 
     /**
-     * This value is used in the simple/common case of animating just one value; the user
-     * may call getAnimatedValue(), which should return the value of the first (and only)
-     * ProeprtyValuesHolder animated value, which is looked up using this string.
+     * A hashmap of the PropertyValuesHolder objects. This map is used to lookup animated values
+     * by property name during calls to getAnimatedValue(String).
      */
-    String mFirstPropertyName;
-
+    HashMap<String, PropertyValuesHolder> mValuesMap;
 
     /**
      * The type of the values, as determined by the valueFrom/valueTo properties.
@@ -290,11 +289,11 @@
                 break;
         }
 
-        mValues = new HashMap<String, PropertyValuesHolder>(1);
-        mFirstPropertyName = "";
-        PropertyValuesHolder valuesHolder = new PropertyValuesHolder(mFirstPropertyName,
-                valueFrom, valueTo);
-        mValues.put(mFirstPropertyName, valuesHolder);
+        PropertyValuesHolder valuesHolder = new PropertyValuesHolder("", valueFrom, valueTo);
+        mValues = new PropertyValuesHolder[1];
+        mValues[0] = valuesHolder;
+        mValuesMap = new HashMap<String, PropertyValuesHolder>(1);
+        mValuesMap.put("", valuesHolder);
 
         mRepeatCount = a.getInt(com.android.internal.R.styleable.Animator_repeatCount, mRepeatCount);
         mRepeatMode = a.getInt(com.android.internal.R.styleable.Animator_repeatMode, RESTART);
@@ -323,15 +322,11 @@
 
     public void setValues(PropertyValuesHolder... values) {
         int numValues = values.length;
-        mValues = new HashMap<String, PropertyValuesHolder>(numValues);
+        mValues = values;
+        mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
         for (int i = 0; i < numValues; ++i) {
             PropertyValuesHolder valuesHolder = (PropertyValuesHolder) values[i];
-            mValues.put(valuesHolder.getPropertyName(), valuesHolder);
-        }
-        if (numValues > 0 && values[0] != null) {
-            mFirstPropertyName = ((PropertyValuesHolder) values[0]).getPropertyName();
-        } else {
-            mFirstPropertyName = "";
+            mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
         }
     }
 
@@ -348,26 +343,12 @@
      * @param values The set of values to animate between.
      */
     public void setValues(T... values) {
-        if (values[0] instanceof PropertyValuesHolder) {
-            int numValues = values.length;
-            mValues = new HashMap<String, PropertyValuesHolder>(numValues);
-            for (int i = 0; i < numValues; ++i) {
-                PropertyValuesHolder valuesHolder = (PropertyValuesHolder) values[i];
-                mValues.put(valuesHolder.getPropertyName(), valuesHolder);
-            }
-            if (numValues > 0 && values[0] != null) {
-                mFirstPropertyName = ((PropertyValuesHolder) values[0]).getPropertyName();
-            } else {
-                mFirstPropertyName = "";
-            }
+        if (mValues == null || mValues.length == 0) {
+            setValues(new PropertyValuesHolder[]{
+                    new PropertyValuesHolder("", (Object[])values)});
         } else {
-            if (mValues == null) {
-                setValues(new PropertyValuesHolder[]{
-                        new PropertyValuesHolder("", (Object[])values)});
-            } else {
-                PropertyValuesHolder valuesHolder = mValues.get(mFirstPropertyName);
-                valuesHolder.setValues(values);
-            }
+            PropertyValuesHolder valuesHolder = mValues[0];
+            valuesHolder.setValues(values);
         }
     }
 
@@ -382,8 +363,9 @@
      *  that internal mechanisms for the animation are set up correctly.</p>
      */
     void initAnimation() {
-        for (PropertyValuesHolder pvHolder: mValues.values()) {
-            pvHolder.init();
+        int numValues = mValues.length;
+        for (int i = 0; i < numValues; ++i) {
+            mValues[i].init();
         }
         mCurrentIteration = 0;
         mInitialized = true;
@@ -394,8 +376,8 @@
      * be between 0 and the total duration of the animation, including any repetition. If
      * the animation has not yet been started, then it will not advance forward after it is
      * set to this time; it will simply set the time to this value and perform any appropriate
-     * actions based on that time. If the animation is already running, then seek() will
-     * set the current playing time to this value and continue playing from that point.
+     * actions based on that time. If the animation is already running, then setCurrentPlayTime()
+     * will set the current playing time to this value and continue playing from that point.
      *
      * @param playTime The time, in milliseconds, to which the animation is advanced or rewound.
      */
@@ -587,7 +569,11 @@
      * returns the animated value for the first of those objects.
      */
     public Object getAnimatedValue() {
-        return getAnimatedValue(mFirstPropertyName);
+        if (mValues != null && mValues.length > 0) {
+            return mValues[0].getAnimatedValue();
+        }
+        // Shouldn't get here; should always have values unless Animator was set up wrong
+        return null;
     }
 
     /**
@@ -601,7 +587,13 @@
      * by this <code>Animator</code>.
      */
     public Object getAnimatedValue(String propertyName) {
-        return mValues.get(mFirstPropertyName).getAnimatedValue();
+        PropertyValuesHolder valuesHolder = mValuesMap.get(propertyName);
+        if (valuesHolder != null) {
+            return valuesHolder.getAnimatedValue();
+        } else {
+            // At least avoid crashing if called with bogus propertyName
+            return null;
+        }
     }
 
     /**
@@ -691,6 +683,15 @@
     }
 
     /**
+     * Returns the timing interpolator that this Animator uses.
+     *
+     * @return The timing interpolator for this Animator.
+     */
+    public Interpolator getInterpolator() {
+        return mInterpolator;
+    }
+
+    /**
      * The type evaluator to be used when calculating the animated values of this animation.
      * The system will automatically assign a float, int, or double evaluator based on the type
      * of <code>startValue</code> and <code>endValue</code> in the constructor. But if these values
@@ -707,8 +708,8 @@
      * @param value the evaluator to be used this animation
      */
     public void setEvaluator(TypeEvaluator value) {
-        if (value != null && mValues != null) {
-            mValues.get(mFirstPropertyName).setEvaluator(value);
+        if (value != null && mValues != null && mValues.length > 0) {
+            mValues[0].setEvaluator(value);
         }
     }
 
@@ -720,6 +721,10 @@
      * @param playBackwards Whether the Animator should start playing in reverse.
      */
     private void start(boolean playBackwards) {
+        if ((mStartDelay == 0) && (Thread.currentThread() == Looper.getMainLooper().getThread())) {
+            // This sets the initial value of the animation, prior to actually starting it running
+            setCurrentPlayTime(getCurrentPlayTime());
+        }
         mPlayingBackwards = playBackwards;
         mPlayingState = STOPPED;
         sPendingAnimations.add(this);
@@ -731,6 +736,15 @@
         sAnimationHandler.sendEmptyMessage(ANIMATION_START);
     }
 
+    /**
+     * Returns the duration that this animation will run for.
+     *
+     * @return The length in time of the animation, in milliseconds.
+     */
+    public long getDuration() {
+        return mDuration;
+    }
+
     @Override
     public void start() {
         start(false);
@@ -928,8 +942,9 @@
      */
     void animateValue(float fraction) {
         fraction = mInterpolator.getInterpolation(fraction);
-        for (PropertyValuesHolder valuesHolder : mValues.values()) {
-            valuesHolder.calculateValue(fraction);
+        int numValues = mValues.length;
+        for (int i = 0; i < numValues; ++i) {
+            mValues[i].calculateValue(fraction);
         }
         if (mUpdateListeners != null) {
             int numListeners = mUpdateListeners.size();
diff --git a/core/java/android/animation/PropertyAnimator.java b/core/java/android/animation/PropertyAnimator.java
index 9366a71..1a010a9 100644
--- a/core/java/android/animation/PropertyAnimator.java
+++ b/core/java/android/animation/PropertyAnimator.java
@@ -21,10 +21,7 @@
 import android.util.AttributeSet;
 import android.util.Log;
 
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 /**
  * This subclass of {@link Animator} provides support for animating properties on target objects.
@@ -61,10 +58,12 @@
      */
     public void setPropertyName(String propertyName) {
         if (mValues != null) {
-            // should always be the case
-            PropertyValuesHolder valuesHolder = mValues.get(mFirstPropertyName);
+            // mValues should always be non-null
+            PropertyValuesHolder valuesHolder = mValues[0];
+            String oldName = valuesHolder.getPropertyName();
             valuesHolder.setPropertyName(propertyName);
-            mFirstPropertyName = propertyName;
+            mValuesMap.remove(oldName);
+            mValuesMap.put(propertyName, valuesHolder);
         }
         mPropertyName = propertyName;
     }
@@ -184,8 +183,9 @@
     @Override
     void initAnimation() {
         super.initAnimation();
-        for (PropertyValuesHolder valuesHolder : mValues.values()) {
-            valuesHolder.setupSetterAndGetter(mTarget);
+        int numValues = mValues.length;
+        for (int i = 0; i < numValues; ++i) {
+            mValues[i].setupSetterAndGetter(mTarget);
         }
     }
 
@@ -223,8 +223,9 @@
     @Override
     void animateValue(float fraction) {
         super.animateValue(fraction);
-        for (PropertyValuesHolder valuesHolder : mValues.values()) {
-            valuesHolder.setAnimatedValue(mTarget);
+        int numValues = mValues.length;
+        for (int i = 0; i < numValues; ++i) {
+            mValues[i].setAnimatedValue(mTarget);
         }
     }
 }
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index 05e0bc1..fc829b8 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -261,11 +261,12 @@
                     // Swallow the error and keep trying other variants
                 }
             }
+            // If we got here, then no appropriate function was found
+            Log.e("PropertyValuesHolder",
+                    "Couldn't find setter/getter for property " + mPropertyName +
+                            "with value type "+ mValueType);
         }
-        // If we got here, then no appropriate function was found
-        Log.e("PropertyValuesHolder",
-                "Couldn't find setter/getter for property " + mPropertyName +
-                        "with value type "+ mValueType);
+
         return returnVal;
     }
 
diff --git a/core/java/android/bluetooth/AtCommandHandler.java b/core/java/android/bluetooth/AtCommandHandler.java
index 8de2133..6deab34 100644
--- a/core/java/android/bluetooth/AtCommandHandler.java
+++ b/core/java/android/bluetooth/AtCommandHandler.java
@@ -73,7 +73,7 @@
      *             least one element in this array.
      * @return     The result of this command.
      */
-    // Typically used to set this paramter
+    // Typically used to set this parameter
     public AtCommandResult handleSetCommand(Object[] args) {
         return new AtCommandResult(AtCommandResult.ERROR);
     }
@@ -83,11 +83,12 @@
      * Test commands are part of the Extended command syntax, and are typically
      * used to request an indication of the range of legal values that "FOO"
      * can take.<p>
-     * By defualt we return an OK result, to indicate that this command is at
+     * By default we return an OK result, to indicate that this command is at
      * least recognized.<p>
      * @return The result of this command.
      */
     public AtCommandResult handleTestCommand() {
         return new AtCommandResult(AtCommandResult.OK);
     }
+
 }
diff --git a/core/java/android/bluetooth/BluetoothAssignedNumbers.java b/core/java/android/bluetooth/BluetoothAssignedNumbers.java
new file mode 100644
index 0000000..55bc814
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAssignedNumbers.java
@@ -0,0 +1,523 @@
+/*
+ * 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.
+ */
+
+package android.bluetooth;
+
+/**
+ * Bluetooth Assigned Numbers.
+ * <p>
+ * For now we only include Company ID values.
+ * @see <a href="https://www.bluetooth.org/technical/assignednumbers/identifiers.htm">
+ * The Official Bluetooth SIG Member Website | Company Identifiers</a>
+ *
+ * @hide
+ */
+public class BluetoothAssignedNumbers {
+
+    //// Bluetooth SIG Company ID values
+
+    /*
+     * Ericsson Technology Licensing.
+     */
+    public static final int ERICSSON_TECHNOLOGY = 0x0000;
+
+    /*
+     * Nokia Mobile Phones.
+     */
+    public static final int NOKIA_MOBILE_PHONES = 0x0001;
+
+    /*
+     * Intel Corp.
+     */
+    public static final int INTEL = 0x0002;
+
+    /*
+     * IBM Corp.
+     */
+    public static final int IBM = 0x0003;
+
+    /*
+     * Toshiba Corp.
+     */
+    public static final int TOSHIBA = 0x0004;
+
+    /*
+     * 3Com.
+     */
+    public static final int THREECOM = 0x0005;
+
+    /*
+     * Microsoft.
+     */
+    public static final int MICROSOFT = 0x0006;
+
+    /*
+     * Lucent.
+     */
+    public static final int LUCENT = 0x0007;
+
+    /*
+     * Motorola.
+     */
+    public static final int MOTOROLA = 0x0008;
+
+    /*
+     * Infineon Technologies AG.
+     */
+    public static final int INFINEON_TECHNOLOGIES = 0x0009;
+
+    /*
+     * Cambridge Silicon Radio.
+     */
+    public static final int CAMBRIDGE_SILICON_RADIO = 0x000A;
+
+    /*
+     * Silicon Wave.
+     */
+    public static final int SILICON_WAVE = 0x000B;
+
+    /*
+     * Digianswer A/S.
+     */
+    public static final int DIGIANSWER = 0x000C;
+
+    /*
+     * Texas Instruments Inc.
+     */
+    public static final int TEXAS_INSTRUMENTS = 0x000D;
+
+    /*
+     * Parthus Technologies Inc.
+     */
+    public static final int PARTHUS_TECHNOLOGIES = 0x000E;
+
+    /*
+     * Broadcom Corporation.
+     */
+    public static final int BROADCOM = 0x000F;
+
+    /*
+     * Mitel Semiconductor.
+     */
+    public static final int MITEL_SEMICONDUCTOR = 0x0010;
+
+    /*
+     * Widcomm, Inc.
+     */
+    public static final int WIDCOMM = 0x0011;
+
+    /*
+     * Zeevo, Inc.
+     */
+    public static final int ZEEVO = 0x0012;
+
+    /*
+     * Atmel Corporation.
+     */
+    public static final int ATMEL = 0x0013;
+
+    /*
+     * Mitsubishi Electric Corporation.
+     */
+    public static final int MITSUBISHI_ELECTRIC = 0x0014;
+
+    /*
+     * RTX Telecom A/S.
+     */
+    public static final int RTX_TELECOM = 0x0015;
+
+    /*
+     * KC Technology Inc.
+     */
+    public static final int KC_TECHNOLOGY = 0x0016;
+
+    /*
+     * Newlogic.
+     */
+    public static final int NEWLOGIC = 0x0017;
+
+    /*
+     * Transilica, Inc.
+     */
+    public static final int TRANSILICA = 0x0018;
+
+    /*
+     * Rohde & Schwarz GmbH & Co. KG.
+     */
+    public static final int ROHDE_AND_SCHWARZ = 0x0019;
+
+    /*
+     * TTPCom Limited.
+     */
+    public static final int TTPCOM = 0x001A;
+
+    /*
+     * Signia Technologies, Inc.
+     */
+    public static final int SIGNIA_TECHNOLOGIES = 0x001B;
+
+    /*
+     * Conexant Systems Inc.
+     */
+    public static final int CONEXANT_SYSTEMS = 0x001C;
+
+    /*
+     * Qualcomm.
+     */
+    public static final int QUALCOMM = 0x001D;
+
+    /*
+     * Inventel.
+     */
+    public static final int INVENTEL = 0x001E;
+
+    /*
+     * AVM Berlin.
+     */
+    public static final int AVM_BERLIN = 0x001F;
+
+    /*
+     * BandSpeed, Inc.
+     */
+    public static final int BANDSPEED = 0x0020;
+
+    /*
+     * Mansella Ltd.
+     */
+    public static final int MANSELLA = 0x0021;
+
+    /*
+     * NEC Corporation.
+     */
+    public static final int NEC = 0x0022;
+
+    /*
+     * WavePlus Technology Co., Ltd.
+     */
+    public static final int WAVEPLUS_TECHNOLOGY = 0x0023;
+
+    /*
+     * Alcatel.
+     */
+    public static final int ALCATEL = 0x0024;
+
+    /*
+     * Philips Semiconductors.
+     */
+    public static final int PHILIPS_SEMICONDUCTORS = 0x0025;
+
+    /*
+     * C Technologies.
+     */
+    public static final int C_TECHNOLOGIES = 0x0026;
+
+    /*
+     * Open Interface.
+     */
+    public static final int OPEN_INTERFACE = 0x0027;
+
+    /*
+     * R F Micro Devices.
+     */
+    public static final int RF_MICRO_DEVICES = 0x0028;
+
+    /*
+     * Hitachi Ltd.
+     */
+    public static final int HITACHI = 0x0029;
+
+    /*
+     * Symbol Technologies, Inc.
+     */
+    public static final int SYMBOL_TECHNOLOGIES = 0x002A;
+
+    /*
+     * Tenovis.
+     */
+    public static final int TENOVIS = 0x002B;
+
+    /*
+     * Macronix International Co. Ltd.
+     */
+    public static final int MACRONIX = 0x002C;
+
+    /*
+     * GCT Semiconductor.
+     */
+    public static final int GCT_SEMICONDUCTOR = 0x002D;
+
+    /*
+     * Norwood Systems.
+     */
+    public static final int NORWOOD_SYSTEMS = 0x002E;
+
+    /*
+     * MewTel Technology Inc.
+     */
+    public static final int MEWTEL_TECHNOLOGY = 0x002F;
+
+    /*
+     * ST Microelectronics.
+     */
+    public static final int ST_MICROELECTRONICS = 0x0030;
+
+    /*
+     * Synopsys.
+     */
+    public static final int SYNOPSYS = 0x0031;
+
+    /*
+     * Red-M (Communications) Ltd.
+     */
+    public static final int RED_M = 0x0032;
+
+    /*
+     * Commil Ltd.
+     */
+    public static final int COMMIL = 0x0033;
+
+    /*
+     * Computer Access Technology Corporation (CATC).
+     */
+    public static final int CATC = 0x0034;
+
+    /*
+     * Eclipse (HQ Espana) S.L.
+     */
+    public static final int ECLIPSE = 0x0035;
+
+    /*
+     * Renesas Technology Corp.
+     */
+    public static final int RENESAS_TECHNOLOGY = 0x0036;
+
+    /*
+     * Mobilian Corporation.
+     */
+    public static final int MOBILIAN_CORPORATION = 0x0037;
+
+    /*
+     * Terax.
+     */
+    public static final int TERAX = 0x0038;
+
+    /*
+     * Integrated System Solution Corp.
+     */
+    public static final int INTEGRATED_SYSTEM_SOLUTION = 0x0039;
+
+    /*
+     * Matsushita Electric Industrial Co., Ltd.
+     */
+    public static final int MATSUSHITA_ELECTRIC = 0x003A;
+
+    /*
+     * Gennum Corporation.
+     */
+    public static final int GENNUM = 0x003B;
+
+    /*
+     * Research In Motion.
+     */
+    public static final int RESEARCH_IN_MOTION = 0x003C;
+
+    /*
+     * IPextreme, Inc.
+     */
+    public static final int IPEXTREME = 0x003D;
+
+    /*
+     * Systems and Chips, Inc.
+     */
+    public static final int SYSTEMS_AND_CHIPS = 0x003E;
+
+    /*
+     * Bluetooth SIG, Inc.
+     */
+    public static final int BLUETOOTH_SIG = 0x003F;
+
+    /*
+     * Seiko Epson Corporation.
+     */
+    public static final int SEIKO_EPSON = 0x0040;
+
+    /*
+     * Integrated Silicon Solution Taiwan, Inc.
+     */
+    public static final int INTEGRATED_SILICON_SOLUTION = 0x0041;
+
+    /*
+     * CONWISE Technology Corporation Ltd.
+     */
+    public static final int CONWISE_TECHNOLOGY = 0x0042;
+
+    /*
+     * PARROT SA.
+     */
+    public static final int PARROT = 0x0043;
+
+    /*
+     * Socket Mobile.
+     */
+    public static final int SOCKET_MOBILE = 0x0044;
+
+    /*
+     * Atheros Communications, Inc.
+     */
+    public static final int ATHEROS_COMMUNICATIONS = 0x0045;
+
+    /*
+     * MediaTek, Inc.
+     */
+    public static final int MEDIATEK = 0x0046;
+
+    /*
+     * Bluegiga.
+     */
+    public static final int BLUEGIGA = 0x0047;
+
+    /*
+     * Marvell Technology Group Ltd.
+     */
+    public static final int MARVELL = 0x0048;
+
+    /*
+     * 3DSP Corporation.
+     */
+    public static final int THREE_DSP = 0x0049;
+
+    /*
+     * Accel Semiconductor Ltd.
+     */
+    public static final int ACCEL_SEMICONDUCTOR = 0x004A;
+
+    /*
+     * Continental Automotive Systems.
+     */
+    public static final int CONTINENTAL_AUTOMOTIVE = 0x004B;
+
+    /*
+     * Apple, Inc.
+     */
+    public static final int APPLE = 0x004C;
+
+    /*
+     * Staccato Communications, Inc.
+     */
+    public static final int STACCATO_COMMUNICATIONS = 0x004D;
+
+    /*
+     * Avago Technologies.
+     */
+    public static final int AVAGO = 0x004E;
+
+    /*
+     * APT Licensing Ltd.
+     */
+    public static final int APT_LICENSING = 0x004F;
+
+    /*
+     * SiRF Technology, Inc.
+     */
+    public static final int SIRF_TECHNOLOGY = 0x0050;
+
+    /*
+     * Tzero Technologies, Inc.
+     */
+    public static final int TZERO_TECHNOLOGIES = 0x0051;
+
+    /*
+     * J&M Corporation.
+     */
+    public static final int J_AND_M = 0x0052;
+
+    /*
+     * Free2move AB.
+     */
+    public static final int FREE2MOVE = 0x0053;
+
+    /*
+     * 3DiJoy Corporation.
+     */
+    public static final int THREE_DIJOY = 0x0054;
+
+    /*
+     * Plantronics, Inc.
+     */
+    public static final int PLANTRONICS = 0x0055;
+
+    /*
+     * Sony Ericsson Mobile Communications.
+     */
+    public static final int SONY_ERICSSON = 0x0056;
+
+    /*
+     * Harman International Industries, Inc.
+     */
+    public static final int HARMAN_INTERNATIONAL = 0x0057;
+
+    /*
+     * Vizio, Inc.
+     */
+    public static final int VIZIO = 0x0058;
+
+    /*
+     * Nordic Semiconductor ASA.
+     */
+    public static final int NORDIC_SEMICONDUCTOR = 0x0059;
+
+    /*
+     * EM Microelectronic-Marin SA.
+     */
+    public static final int EM_MICROELECTRONIC_MARIN = 0x005A;
+
+    /*
+     * Ralink Technology Corporation.
+     */
+    public static final int RALINK_TECHNOLOGY = 0x005B;
+
+    /*
+     * Belkin International, Inc.
+     */
+    public static final int BELKIN_INTERNATIONAL = 0x005C;
+
+    /*
+     * Realtek Semiconductor Corporation.
+     */
+    public static final int REALTEK_SEMICONDUCTOR = 0x005D;
+
+    /*
+     * Stonestreet One, LLC.
+     */
+    public static final int STONESTREET_ONE = 0x005E;
+
+    /*
+     * Wicentric, Inc.
+     */
+    public static final int WICENTRIC = 0x005F;
+
+    /*
+     * RivieraWaves S.A.S.
+     */
+    public static final int RIVIERAWAVES = 0x0060;
+
+    /*
+     * You can't instantiate one of these.
+     */
+    private BluetoothAssignedNumbers() {
+    }
+
+}
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
index 0c9bab2..c8381c9 100644
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -261,6 +261,10 @@
     public static final int PROFILE_OPP = 2;
     /** @hide */
     public static final int PROFILE_HID = 3;
+    /** @hide */
+    public static final int PROFILE_PANU = 4;
+    /** @hide */
+    public static final int PROFILE_NAP = 5;
 
     /**
      * Check class bits for possible bluetooth profile support.
@@ -328,6 +332,12 @@
             }
         } else if (profile == PROFILE_HID) {
             return (getDeviceClass() & Device.Major.PERIPHERAL) == Device.Major.PERIPHERAL;
+        } else if (profile == PROFILE_PANU || profile == PROFILE_NAP){
+            // No good way to distinguish between the two, based on class bits.
+            if (hasService(Service.NETWORKING)) {
+                return true;
+            }
+            return (getDeviceClass() & Device.Major.NETWORKING) == Device.Major.NETWORKING;
         } else {
             return false;
         }
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 4a91a8c..53d6a37 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -45,7 +45,7 @@
  * This BluetoothHeadset object is not immediately bound to the
  * BluetoothHeadset service. Use the ServiceListener interface to obtain a
  * notification when it is bound, this is especially important if you wish to
- * immediately call methods on BluetootHeadset after construction.
+ * immediately call methods on BluetoothHeadset after construction.
  *
  * Android only supports one connected Bluetooth Headset at a time.
  *
@@ -85,6 +85,43 @@
             "android.bluetooth.headset.extra.DISCONNECT_INITIATOR";
 
     /**
+     * Broadcast Action: Indicates a headset has posted a vendor-specific event.
+     * <p>Always contains the extra fields {@link #EXTRA_DEVICE},
+     * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD}, and
+     * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS}.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_VENDOR_SPECIFIC_HEADSET_EVENT =
+            "android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT";
+
+    /**
+     * A String extra field in {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT}
+     * intents that contains the name of the vendor-specific command.
+     */
+    public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD =
+            "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_CMD";
+
+    /**
+     * An int extra field in {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT}
+     * intents that contains the Company ID of the vendor defining the vendor-specific
+     * command.
+     * @see <a href="https://www.bluetooth.org/Technical/AssignedNumbers/identifiers.htm">
+     * Bluetooth SIG Assigned Numbers - Company Identifiers</a>
+     */
+    public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID =
+            "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID";
+
+    /**
+     * A Parcelable String array extra field in
+     * {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT} intents that contains
+     * the arguments to the vendor-specific command.
+     */
+    public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS =
+            "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_ARGS";
+
+
+    /**
      * TODO(API release): Consider incorporating as new state in
      * HEADSET_STATE_CHANGED
      */
@@ -108,7 +145,7 @@
 
     public static final int RESULT_FAILURE = 0;
     public static final int RESULT_SUCCESS = 1;
-    /** Connection canceled before completetion. */
+    /** Connection canceled before completion. */
     public static final int RESULT_CANCELED = 2;
 
     /** Values for {@link #EXTRA_DISCONNECT_INITIATOR} */
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index fb3dfe4..3fbfc70 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -55,6 +55,8 @@
             ParcelUuid.fromString("00001115-0000-1000-8000-00805F9B34FB");
     public static final ParcelUuid NAP =
             ParcelUuid.fromString("00001116-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid BNEP =
+            ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB");
 
     public static final ParcelUuid[] RESERVED_UUIDS = {
         AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
@@ -92,13 +94,17 @@
         return uuid.equals(Hid);
     }
 
-    public static boolean isPANU(ParcelUuid uuid) {
+    public static boolean isPanu(ParcelUuid uuid) {
         return uuid.equals(PANU);
     }
 
-    public static boolean isNAP(ParcelUuid uuid) {
+    public static boolean isNap(ParcelUuid uuid) {
         return uuid.equals(NAP);
     }
+
+    public static boolean isBnep(ParcelUuid uuid) {
+        return uuid.equals(BNEP);
+    }
     /**
      * Returns true if ParcelUuid is present in uuidArray
      *
diff --git a/core/java/android/bluetooth/HeadsetBase.java b/core/java/android/bluetooth/HeadsetBase.java
index e2935c9..9ef2eb5 100644
--- a/core/java/android/bluetooth/HeadsetBase.java
+++ b/core/java/android/bluetooth/HeadsetBase.java
@@ -74,8 +74,8 @@
 
     private native void cleanupNativeDataNative();
 
-    public HeadsetBase(PowerManager pm, BluetoothAdapter adapter, BluetoothDevice device,
-            int rfcommChannel) {
+    public HeadsetBase(PowerManager pm, BluetoothAdapter adapter,
+                       BluetoothDevice device, int rfcommChannel) {
         mDirection = DIRECTION_OUTGOING;
         mConnectTimestamp = System.currentTimeMillis();
         mAdapter = adapter;
@@ -89,9 +89,10 @@
         initializeNativeDataNative(-1);
     }
 
-    /* Create from an already exisiting rfcomm connection */
-    public HeadsetBase(PowerManager pm, BluetoothAdapter adapter, BluetoothDevice device,
-            int socketFd, int rfcommChannel, Handler handler) {
+    /* Create from an existing rfcomm connection */
+    public HeadsetBase(PowerManager pm, BluetoothAdapter adapter,
+                       BluetoothDevice device,
+                       int socketFd, int rfcommChannel, Handler handler) {
         mDirection = DIRECTION_INCOMING;
         mConnectTimestamp = System.currentTimeMillis();
         mAdapter = adapter;
@@ -128,7 +129,7 @@
                        (System.currentTimeMillis() - timestamp) + " ms");
 
         if (result.getResultCode() == AtCommandResult.ERROR) {
-            Log.i(TAG, "Error pocessing <" + input + ">");
+            Log.i(TAG, "Error processing <" + input + ">");
         }
 
         sendURC(result.toString());
@@ -142,8 +143,9 @@
      */
     protected void initializeAtParser() {
         mAtParser = new AtParser();
-        //TODO(): Get rid of this as there are no parsers registered. But because of dependencies,
-        //it needs to be done as part of refactoring HeadsetBase and BluetoothHandsfree
+
+        //TODO(): Get rid of this as there are no parsers registered. But because of dependencies
+        // it needs to be done as part of refactoring HeadsetBase and BluetoothHandsfree
     }
 
     public AtParser getAtParser() {
@@ -159,8 +161,7 @@
                         String input = readNative(500);
                         if (input != null) {
                             handleInput(input);
-                        }
-                        else {
+                        } else {
                             last_read_error = getLastReadStatusNative();
                             if (last_read_error != 0) {
                                 Log.i(TAG, "headset read error " + last_read_error);
@@ -179,8 +180,6 @@
         mEventThread.start();
     }
 
-
-
     private native String readNative(int timeout_ms);
     private native int getLastReadStatusNative();
 
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 7901b155..244d126 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -389,15 +389,17 @@
         if (permission != null) {
             pw.println(prefix + "permission=" + permission);
         }
-        pw.println(prefix + "uid=" + uid + " taskAffinity=" + taskAffinity);
-        if (theme != 0) {
-            pw.println(prefix + "theme=0x" + Integer.toHexString(theme));
-        }
-        pw.println(prefix + "flags=0x" + Integer.toHexString(flags)
-                + " processName=" + processName);
+        pw.println(prefix + "processName=" + processName);
+        pw.println(prefix + "taskAffinity=" + taskAffinity);
+        pw.println(prefix + "uid=" + uid + " flags=0x" + Integer.toHexString(flags)
+                + " theme=0x" + Integer.toHexString(theme));
         pw.println(prefix + "sourceDir=" + sourceDir);
-        pw.println(prefix + "publicSourceDir=" + publicSourceDir);
-        pw.println(prefix + "resourceDirs=" + resourceDirs);
+        if (!sourceDir.equals(publicSourceDir)) {
+            pw.println(prefix + "publicSourceDir=" + publicSourceDir);
+        }
+        if (resourceDirs != null) {
+            pw.println(prefix + "resourceDirs=" + resourceDirs);
+        }
         pw.println(prefix + "dataDir=" + dataDir);
         if (sharedLibraryFiles != null) {
             pw.println(prefix + "sharedLibraryFiles=" + sharedLibraryFiles);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 155c86c..7c6e142 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1494,12 +1494,18 @@
             ai.nonLocalizedLabel = v.coerceToString();
         }
 
+        int defaultTheme = 0;
+        if (owner.applicationInfo.targetSdkVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) {
+            // As of honeycomb, the default application theme is holographic.
+            defaultTheme = android.R.style.Theme_Holo;
+        }
+
         ai.icon = sa.getResourceId(
                 com.android.internal.R.styleable.AndroidManifestApplication_icon, 0);
         ai.logo = sa.getResourceId(
                 com.android.internal.R.styleable.AndroidManifestApplication_logo, 0);
         ai.theme = sa.getResourceId(
-                com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
+                com.android.internal.R.styleable.AndroidManifestApplication_theme, defaultTheme);
         ai.descriptionRes = sa.getResourceId(
                 com.android.internal.R.styleable.AndroidManifestApplication_description, 0);
 
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 03aa968..38d6526 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -651,14 +651,40 @@
      * @return the number of rows in the table
      */
     public static long queryNumEntries(SQLiteDatabase db, String table) {
-        Cursor cursor = db.query(table, countProjection,
-                null, null, null, null, null);
-        try {
-            cursor.moveToFirst();
-            return cursor.getLong(0);
-        } finally {
-            cursor.close();
-        }
+        return queryNumEntries(db, table, null, null);
+    }
+
+    /**
+     * Query the table for the number of rows in the table.
+     * @param db the database the table is in
+     * @param table the name of the table to query
+     * @param selection A filter declaring which rows to return,
+     *              formatted as an SQL WHERE clause (excluding the WHERE itself).
+     *              Passing null will count all rows for the given table
+     * @return the number of rows in the table filtered by the selection
+     */
+    public static long queryNumEntries(SQLiteDatabase db, String table, String selection) {
+        return queryNumEntries(db, table, selection, null);
+    }
+
+    /**
+     * Query the table for the number of rows in the table.
+     * @param db the database the table is in
+     * @param table the name of the table to query
+     * @param selection A filter declaring which rows to return,
+     *              formatted as an SQL WHERE clause (excluding the WHERE itself).
+     *              Passing null will count all rows for the given table
+     * @param selectionArgs You may include ?s in selection,
+     *              which will be replaced by the values from selectionArgs,
+     *              in order that they appear in the selection.
+     *              The values will be bound as Strings.
+     * @return the number of rows in the table filtered by the selection
+     */
+    public static long queryNumEntries(SQLiteDatabase db, String table, String selection,
+            String[] selectionArgs) {
+        String s = (!TextUtils.isEmpty(selection)) ? " where " + selection : "";
+        return longForQuery(db, "select count(*) from " + table + s,
+                    selectionArgs);
     }
 
     /**
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 54feb6d..b83d5ad 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -2066,11 +2066,9 @@
      * mapping is NOT replaced with the new mapping).
      */
     /* package */ void addToCompiledQueries(String sql, SQLiteCompiledSql compiledStatement) {
-        SQLiteCompiledSql compiledSql = null;
         synchronized(mCompiledQueries) {
             // don't insert the new mapping if a mapping already exists
-            compiledSql = mCompiledQueries.get(sql);
-            if (compiledSql != null) {
+            if (mCompiledQueries.containsKey(sql)) {
                 return;
             }
 
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index d8cce21..ccf8d68 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -121,8 +121,13 @@
      * @return a read/write database object valid until {@link #close} is called
      */
     public synchronized SQLiteDatabase getWritableDatabase() {
-        if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) {
-            return mDatabase;  // The database is already open for business
+        if (mDatabase != null) {
+            if (!mDatabase.isOpen()) {
+                // darn! the user closed the database by calling mDatabase.close()
+                mDatabase = null;
+            } else if (!mDatabase.isReadOnly()) {
+                return mDatabase;  // The database is already open for business
+            }
         }
 
         if (mIsInitializing) {
@@ -207,8 +212,13 @@
      *     or {@link #close} is called.
      */
     public synchronized SQLiteDatabase getReadableDatabase() {
-        if (mDatabase != null && mDatabase.isOpen()) {
-            return mDatabase;  // The database is already open for business
+        if (mDatabase != null) {
+            if (!mDatabase.isOpen()) {
+                // darn! the user closed the database by calling mDatabase.close()
+                mDatabase = null;
+            } else {
+                return mDatabase;  // The database is already open for business
+            }
         }
 
         if (mIsInitializing) {
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index 231d8e6..9b7d823 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -158,18 +158,18 @@
 
     @Override
     protected void onAllReferencesReleased() {
-        releaseCompiledSqlIfNotInCache();
+        release();
         mDatabase.removeSQLiteClosable(this);
         mDatabase.releaseReference();
     }
 
     @Override
     protected void onAllReferencesReleasedFromContainer() {
-        releaseCompiledSqlIfNotInCache();
+        release();
         mDatabase.releaseReference();
     }
 
-    /* package */ synchronized void releaseCompiledSqlIfNotInCache() {
+    /* package */ synchronized void release() {
         if (mCompiledSql == null) {
             return;
         }
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index 14de60f..dc07db0 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -265,7 +265,7 @@
         clearBindings();
         // release the compiled sql statement so that the caller's SQLiteStatement no longer
         // has a hard reference to a database object that may get deallocated at any point.
-        releaseCompiledSqlIfNotInCache();
+        release();
         // restore the database connection handle to the original value
         mDatabase = mOrigDb;
         nHandle = mDatabase.mNativeHandle;
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index a0abc6c..e432a47 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -960,6 +960,7 @@
         private static final String KEY_PREVIEW_SIZE = "preview-size";
         private static final String KEY_PREVIEW_FORMAT = "preview-format";
         private static final String KEY_PREVIEW_FRAME_RATE = "preview-frame-rate";
+        private static final String KEY_PREVIEW_FPS_RANGE = "preview-fps-range";
         private static final String KEY_PICTURE_SIZE = "picture-size";
         private static final String KEY_PICTURE_FORMAT = "picture-format";
         private static final String KEY_JPEG_THUMBNAIL_SIZE = "jpeg-thumbnail-size";
@@ -1219,6 +1220,22 @@
          */
         public static final String METERING_MODE_SPOT = "spot";
 
+        /**
+         * The array index of minimum preview fps for use with {@link
+         * #getPreviewFpsRange(int[])} or {@link
+         * #getSupportedPreviewFpsRange()}.
+         * @hide
+         */
+        public static final int PREVIEW_FPS_MIN_INDEX = 0;
+
+        /**
+         * The array index of maximum preview fps for use with {@link
+         * #getPreviewFpsRange(int[])} or {@link
+         * #getSupportedPreviewFpsRange()}.
+         * @hide
+         */
+        public static final int PREVIEW_FPS_MAX_INDEX = 1;
+
         // Formats for setPreviewFormat and setPictureFormat.
         private static final String PIXEL_FORMAT_YUV422SP = "yuv422sp";
         private static final String PIXEL_FORMAT_YUV420SP = "yuv420sp";
@@ -1482,6 +1499,64 @@
         }
 
         /**
+         * Sets the maximum and maximum preview fps. This controls the rate of
+         * preview frames received in {@link #PreviewCallback}. The minimum and
+         * maximum preview fps must be one of the elements from {@link
+         * #getSupportedPreviewFpsRange}.
+         *
+         * @param min the minimum preview fps (scaled by 1000).
+         * @param max the maximum preview fps (scaled by 1000).
+         * @throws RuntimeException if fps range is invalid.
+         * @see #setPreviewCallbackWithBuffer(Camera.PreviewCallback)
+         * @see #getSupportedPreviewFpsRange()
+         * @hide
+         */
+        public void setPreviewFpsRange(int min, int max) {
+            set(KEY_PREVIEW_FPS_RANGE, "" + min + "," + max);
+        }
+
+        /**
+         * Returns the current minimum and maximum preview fps. The values are
+         * one of the elements returned by {@link #getSupportedPreviewFpsRange}.
+         *
+         * @return range the minimum and maximum preview fps (scaled by 1000).
+         * @see #PREVIEW_FPS_MIN_INDEX
+         * @see #PREVIEW_FPS_MAX_INDEX
+         * @see #getSupportedPreviewFpsRange()
+         * @hide
+         */
+        public void getPreviewFpsRange(int[] range) {
+            if (range == null || range.length != 2) {
+                throw new IllegalArgumentException(
+                        "range must be an float array with two elements.");
+            }
+            splitInt(get(KEY_PREVIEW_FPS_RANGE), range);
+        }
+
+        /**
+         * Gets the supported preview fps (frame-per-second) ranges. Each range
+         * contains a minimum fps and maximum fps. If minimum fps equals to
+         * maximum fps, the camera outputs frames in fixed frame rate. If not,
+         * the camera outputs frames in auto frame rate. The actual frame rate
+         * fluctuates between the minimum and the maximum. The values are
+         * multiplied by 1000 and represented in integers. For example, if frame
+         * rate is 26.623 frames per second, the value is 26623.
+         *
+         * @return a list of supported preview fps ranges. This method returns a
+         *         list with at least one element. Every element is an int array
+         *         of two values - minimum fps and maximum fps. The list is
+         *         sorted from small to large (first by maximum fps and then
+         *         minimum fps).
+         * @see #PREVIEW_FPS_MIN_INDEX
+         * @see #PREVIEW_FPS_MAX_INDEX
+         * @hide
+         */
+        public List<int[]> getSupportedPreviewFpsRange() {
+            String str = get(KEY_PREVIEW_FPS_RANGE + SUPPORTED_VALUES_SUFFIX);
+            return splitRange(str);
+        }
+
+        /**
          * Sets the image format for preview pictures.
          * <p>If this is never called, the default format will be
          * {@link android.graphics.ImageFormat#NV21}, which
@@ -2184,10 +2259,7 @@
                 throw new IllegalArgumentException(
                         "output must be an float array with three elements.");
             }
-            List<Float> distances = splitFloat(get(KEY_FOCUS_DISTANCES));
-            output[0] = distances.get(0);
-            output[1] = distances.get(1);
-            output[2] = distances.get(2);
+            splitFloat(get(KEY_FOCUS_DISTANCES), output);
         }
 
         /**
@@ -2255,19 +2327,27 @@
             return substrings;
         }
 
-        // Splits a comma delimited string to an ArrayList of Float.
-        // Return null if the passing string is null or the size is 0.
-        private ArrayList<Float> splitFloat(String str) {
-            if (str == null) return null;
+        private void splitInt(String str, int[] output) {
+            if (str == null) return;
 
             StringTokenizer tokenizer = new StringTokenizer(str, ",");
-            ArrayList<Float> substrings = new ArrayList<Float>();
+            int index = 0;
             while (tokenizer.hasMoreElements()) {
                 String token = tokenizer.nextToken();
-                substrings.add(Float.parseFloat(token));
+                output[index++] = Integer.parseInt(token);
             }
-            if (substrings.size() == 0) return null;
-            return substrings;
+        }
+
+        // Splits a comma delimited string to an ArrayList of Float.
+        private void splitFloat(String str, float[] output) {
+            if (str == null) return;
+
+            StringTokenizer tokenizer = new StringTokenizer(str, ",");
+            int index = 0;
+            while (tokenizer.hasMoreElements()) {
+                String token = tokenizer.nextToken();
+                output[index++] = Float.parseFloat(token);
+            }
         }
 
         // Returns the value of a float parameter.
@@ -2318,5 +2398,30 @@
             Log.e(TAG, "Invalid size parameter string=" + str);
             return null;
         }
+
+        // Splits a comma delimited string to an ArrayList of int array.
+        // Example string: "(10000,26623),(10000,30000)". Return null if the
+        // passing string is null or the size is 0.
+        private ArrayList<int[]> splitRange(String str) {
+            if (str == null || str.charAt(0) != '('
+                    || str.charAt(str.length() - 1) != ')') {
+                Log.e(TAG, "Invalid range list string=" + str);
+                return null;
+            }
+
+            ArrayList<int[]> rangeList = new ArrayList<int[]>();
+            int endIndex, fromIndex = 1;
+            do {
+                int[] range = new int[2];
+                endIndex = str.indexOf("),(", fromIndex);
+                if (endIndex == -1) endIndex = str.length() - 1;
+                splitInt(str.substring(fromIndex, endIndex), range);
+                rangeList.add(range);
+                fromIndex = endIndex + 3;
+            } while (endIndex != str.length() - 1);
+
+            if (rangeList.size() == 0) return null;
+            return rangeList;
+        }
     };
 }
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index b49a409..f2b907b 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -77,6 +77,27 @@
     public static final int TYPE_PROXIMITY = 8;
 
     /**
+     * A constant describing a gravity sensor type.
+     * See {@link android.hardware.SensorEvent SensorEvent}
+     * for more details.
+     */
+    public static final int TYPE_GRAVITY = 9;
+
+    /**
+     * A constant describing a linear acceleration sensor type.
+     * See {@link android.hardware.SensorEvent SensorEvent}
+     * for more details.
+     */
+    public static final int TYPE_LINEAR_ACCELERATION = 10;
+
+    /**
+     * A constant describing a rotation vector sensor type.
+     * See {@link android.hardware.SensorEvent SensorEvent}
+     * for more details.
+     */
+    public static final int TYPE_ROTATION_VECTOR = 11;
+
+    /** 
      * A constant describing all sensor types.
      */
     public static final int TYPE_ALL = -1;
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index aaf3898..2c5c909 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -133,6 +133,16 @@
      * All values are in micro-Tesla (uT) and measure the ambient magnetic field
      * in the X, Y and Z axis.
      * 
+     * <h4>{@link android.hardware.Sensor#TYPE_GYROSCOPE Sensor.TYPE_GYROSCOPE}:</h4>
+     *  All values are in radians/second and measure the rate of rotation
+     *  around the X, Y and Z axis. The coordinate system is the same as is
+     *  used for the acceleration sensor.  Rotation is positive in the counter-clockwise
+     *  direction.  That is, an observer looking from some positive location on the x, y.
+     *  or z axis at a device positioned on the origin would report positive rotation
+     *  if the device appeared to be rotating counter clockwise.  Note that this is the
+     *  standard mathematical definition of positive rotation and does not agree with the
+     *  definition of roll given earlier.
+     *
      * <h4>{@link android.hardware.Sensor#TYPE_LIGHT Sensor.TYPE_LIGHT}:</h4>
      * 
      * <ul>
@@ -155,6 +165,27 @@
      * the <i>far</i> state and a lesser value in the <i>near</i> state.
      * </p>
      * 
+     *  <h4>{@link android.hardware.Sensor#TYPE_GRAVITY Sensor.TYPE_GRAVITY}:</h4>
+     *  A three dimensional vector indicating the direction and magnitude of gravity.  Units
+     *  are m/s^2.  The coordinate system is the same as is used by the acceleration sensor.
+     *
+     *  <h4>{@link android.hardware.Sensor#TYPE_LINEAR_ACCELERATION Sensor.TYPE_LINEAR_ACCELERATION}:</h4>
+     *  A three dimensional vector indicating acceleration along each device axis, not including
+     *  gravity.  All values have units of m/s^2.  The coordinate system is the same as is used by the
+     * acceleration sensor.
+     *
+     *  <h4>{@link android.hardware.Sensor#TYPE_ROTATION_VECTOR Sensor.TYPE_ROTATION_VECTOR}:</h4>
+     *  The rotation vector represents the orientation of the device as a combination of an angle
+     *  and an axis, in which the device has rotated through an angle theta around an axis
+     *  <x, y, z>. The three elements of the rotation vector are
+     *  <x*sin(theta/2), y*sin(theta/2), z*sin(theta/2)>, such that the magnitude of the rotation
+     *  vector is equal to sin(theta/2), and the direction of the rotation vector is equal to the
+     *  direction of the axis of rotation. The three elements of the rotation vector are equal to
+     *  the last three components of a unit quaternion
+     *  <cos(theta/2), x*sin(theta/2), y*sin(theta/2), z*sin(theta/2)>.  Elements of the rotation
+     *  vector are unitless.  The x,y, and z axis are defined in the same way as the acceleration
+     *  sensor.
+     *
      * <h4>{@link android.hardware.Sensor#TYPE_ORIENTATION
      * Sensor.TYPE_ORIENTATION}:</h4> All values are angles in degrees.
      * 
@@ -201,6 +232,7 @@
      * @see SensorEvent
      * @see GeomagneticField
      */
+
     public final float[] values;
 
     /**
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index d2c3eaa..97921fe 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -1769,6 +1769,183 @@
     }
 
 
+    /** Helper function to compute the angle change between two rotation matrices.
+     *  Given a current rotation matrix (R) and a previous rotation matrix
+     *  (prevR) computes the rotation around the x,y, and z axes which
+     *  transforms prevR to R.
+     *  outputs a 3 element vector containing the x,y, and z angle
+     *  change at indexes 0, 1, and 2 respectively.
+     * <p> Each input matrix is either as a 3x3 or 4x4 row-major matrix
+     * depending on the length of the passed array:
+     * <p>If the array length is 9, then the array elements represent this matrix
+     * <pre>
+     *   /  R[ 0]   R[ 1]   R[ 2]   \
+     *   |  R[ 3]   R[ 4]   R[ 5]   |
+     *   \  R[ 6]   R[ 7]   R[ 8]   /
+     *</pre>
+     * <p>If the array length is 16, then the array elements represent this matrix
+     * <pre>
+     *   /  R[ 0]   R[ 1]   R[ 2]   R[ 3]  \
+     *   |  R[ 4]   R[ 5]   R[ 6]   R[ 7]  |
+     *   |  R[ 8]   R[ 9]   R[10]   R[11]  |
+     *   \  R[12]   R[13]   R[14]   R[15]  /
+     *</pre>
+     * @param R current rotation matrix
+     * @param prevR previous rotation matrix
+     * @param angleChange an array of floats in which the angle change is stored
+     */
+
+    public static void getAngleChange( float[] angleChange, float[] R, float[] prevR) {
+        float rd1=0,rd4=0, rd6=0,rd7=0, rd8=0;
+        float ri0=0,ri1=0,ri2=0,ri3=0,ri4=0,ri5=0,ri6=0,ri7=0,ri8=0;
+        float pri0=0, pri1=0, pri2=0, pri3=0, pri4=0, pri5=0, pri6=0, pri7=0, pri8=0;
+        int i, j, k;
+
+        if(R.length == 9) {
+            ri0 = R[0];
+            ri1 = R[1];
+            ri2 = R[2];
+            ri3 = R[3];
+            ri4 = R[4];
+            ri5 = R[5];
+            ri6 = R[6];
+            ri7 = R[7];
+            ri8 = R[8];
+        } else if(R.length == 16) {
+            ri0 = R[0];
+            ri1 = R[1];
+            ri2 = R[2];
+            ri3 = R[4];
+            ri4 = R[5];
+            ri5 = R[6];
+            ri6 = R[8];
+            ri7 = R[9];
+            ri8 = R[10];
+        }
+
+        if(prevR.length == 9) {
+            pri0 = R[0];
+            pri1 = R[1];
+            pri2 = R[2];
+            pri3 = R[3];
+            pri4 = R[4];
+            pri5 = R[5];
+            pri6 = R[6];
+            pri7 = R[7];
+            pri8 = R[8];
+        } else if(prevR.length == 16) {
+            pri0 = R[0];
+            pri1 = R[1];
+            pri2 = R[2];
+            pri3 = R[4];
+            pri4 = R[5];
+            pri5 = R[6];
+            pri6 = R[8];
+            pri7 = R[9];
+            pri8 = R[10];
+        }
+
+        // calculate the parts of the rotation difference matrix we need
+        // rd[i][j] = pri[0][i] * ri[0][j] + pri[1][i] * ri[1][j] + pri[2][i] * ri[2][j];
+
+        rd1 = pri0 * ri1 + pri3 * ri4 + pri6 * ri7; //rd[0][1]
+        rd4 = pri1 * ri1 + pri4 * ri4 + pri7 * ri7; //rd[1][1]
+        rd6 = pri2 * ri0 + pri5 * ri3 + pri8 * ri6; //rd[2][0]
+        rd7 = pri2 * ri1 + pri5 * ri4 + pri8 * ri7; //rd[2][1]
+        rd8 = pri2 * ri2 + pri5 * ri5 + pri8 * ri8; //rd[2][2]
+
+        angleChange[0] = (float)Math.atan2(rd1, rd4);
+        angleChange[1] = (float)Math.asin(-rd7);
+        angleChange[2] = (float)Math.atan2(-rd6, rd8);
+
+    }
+
+    /** Helper function to convert a rotation vector to a rotation matrix.
+     *  Given a rotation vector (presumably from a ROTATION_VECTOR sensor), returns a
+     *  9  or 16 element rotation matrix in the array R.  R must have length 9 or 16.
+     *  If R.length == 9, the following matrix is returned:
+     * <pre>
+     *   /  R[ 0]   R[ 1]   R[ 2]   \
+     *   |  R[ 3]   R[ 4]   R[ 5]   |
+     *   \  R[ 6]   R[ 7]   R[ 8]   /
+     *</pre>
+     * If R.length == 16, the following matrix is returned:
+     * <pre>
+     *   /  R[ 0]   R[ 1]   R[ 2]   0  \
+     *   |  R[ 4]   R[ 5]   R[ 6]   0  |
+     *   |  R[ 8]   R[ 9]   R[10]   0  |
+     *   \  0       0       0       1  /
+     *</pre>
+     *  @param rotationVector the rotation vector to convert
+     *  @param R an array of floats in which to store the rotation matrix
+     */
+    public static void getRotationMatrixFromVector(float[] R, float[] rotationVector) {
+        float q0 = (float)Math.sqrt(1 - rotationVector[0]*rotationVector[0] -
+                                    rotationVector[1]*rotationVector[1] -
+                                    rotationVector[2]*rotationVector[2]);
+        float q1 = rotationVector[0];
+        float q2 = rotationVector[1];
+        float q3 = rotationVector[2];
+
+        float sq_q1 = 2 * q1 * q1;
+        float sq_q2 = 2 * q2 * q2;
+        float sq_q3 = 2 * q3 * q3;
+        float q1_q2 = 2 * q1 * q2;
+        float q3_q0 = 2 * q3 * q0;
+        float q1_q3 = 2 * q1 * q3;
+        float q2_q0 = 2 * q2 * q0;
+        float q2_q3 = 2 * q2 * q3;
+        float q1_q0 = 2 * q1 * q0;
+
+        if(R.length == 9) {
+            R[0] = 1 - sq_q2 - sq_q3;
+            R[1] = q1_q2 - q3_q0;
+            R[2] = q1_q3 + q2_q0;
+
+            R[3] = q1_q2 + q3_q0;
+            R[4] = 1 - sq_q1 - sq_q3;
+            R[5] = q2_q3 - q1_q0;
+
+            R[6] = q1_q3 - q2_q0;
+            R[7] = q2_q3 + q1_q0;
+            R[8] = 1 - sq_q1 - sq_q2;
+        } else if (R.length == 16) {
+            R[0] = 1 - sq_q2 - sq_q3;
+            R[1] = q1_q2 - q3_q0;
+            R[2] = q1_q3 + q2_q0;
+            R[3] = 0.0f;
+
+            R[4] = q1_q2 + q3_q0;
+            R[5] = 1 - sq_q1 - sq_q3;
+            R[6] = q2_q3 - q1_q0;
+            R[7] = 0.0f;
+
+            R[8] = q1_q3 - q2_q0;
+            R[9] = q2_q3 + q1_q0;
+            R[10] = 1 - sq_q1 - sq_q2;
+            R[11] = 0.0f;
+
+            R[12] = R[13] = R[14] = 0.0f;
+            R[15] = 1.0f;
+        }
+    }
+
+    /** Helper function to convert a rotation vector to a normalized quaternion.
+     *  Given a rotation vector (presumably from a ROTATION_VECTOR sensor), returns a normalized
+     *  quaternion in the array Q.  The quaternion is stored as [w, x, y, z]
+     *  @param rv the rotation vector to convert
+     *  @param Q an array of floats in which to store the computed quaternion
+     */
+    public static void getQuaternionFromVector(float[] Q, float[] rv) {
+        float w = (float)Math.sqrt(1 - rv[0]*rv[0] - rv[1]*rv[1] - rv[2]*rv[2]);
+        //In this case, the w component of the quaternion is known to be a positive number
+
+        Q[0] = w;
+        Q[1] = rv[0];
+        Q[2] = rv[1];
+        Q[3] = rv[2];
+    }
+
     private static native void nativeClassInit();
 
     private static native int sensors_module_init();
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 95f217f..9fe6e01 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1400,6 +1400,7 @@
                         pw.println(getDischargeStartLevel());
                 pw.print(prefix); pw.print("    Discharge cycle current level: ");
                         pw.println(getDischargeCurrentLevel());
+            } else {
                 pw.print(prefix); pw.println("  Device is currently plugged into power");
                 pw.print(prefix); pw.print("    Last discharge cycle start level: "); 
                         pw.println(getDischargeStartLevel());
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 8624467..9268cd1 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -206,7 +206,8 @@
          * <p>Applications targeting this or a later release will get these
          * new changes in behavior:</p>
          * <ul>
-         * <li> Alerts UI change?
+         * <li> The default theme for applications is now dark holographic:
+         *      {@link android.R.style#Theme_Holo}.
          * </ul>
          */
         public static final int HONEYCOMB = CUR_DEVELOPMENT;
diff --git a/core/java/android/os/storage/IMountService.aidl b/core/java/android/os/storage/IMountService.aidl
deleted file mode 100644
index 5c69214..0000000
--- a/core/java/android/os/storage/IMountService.aidl
+++ /dev/null
@@ -1,184 +0,0 @@
-/* //device/java/android/android/os/IUsb.aidl
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
-
-package android.os.storage;
-
-import android.os.storage.IMountServiceListener;
-import android.os.storage.IMountShutdownObserver;
-import android.os.storage.IObbActionListener;
-
-/** WARNING! Update IMountService.h and IMountService.cpp if you change this file.
- * In particular, the ordering of the methods below must match the 
- * _TRANSACTION enum in IMountService.cpp
- * @hide - Applications should use android.os.storage.StorageManager to access
- * storage functions.
- */
-interface IMountService
-{
-    /**
-     * Registers an IMountServiceListener for receiving async
-     * notifications.
-     */
-    void registerListener(IMountServiceListener listener);
-
-    /**
-     * Unregisters an IMountServiceListener
-     */
-    void unregisterListener(IMountServiceListener listener);
-
-    /**
-     * Returns true if a USB mass storage host is connected
-     */
-    boolean isUsbMassStorageConnected();
-
-    /**
-     * Enables / disables USB mass storage.
-     * The caller should check actual status of enabling/disabling
-     * USB mass storage via StorageEventListener.
-     */
-    void setUsbMassStorageEnabled(boolean enable);
-
-    /**
-     * Returns true if a USB mass storage host is enabled (media is shared)
-     */
-    boolean isUsbMassStorageEnabled();
-
-    /**
-     * Mount external storage at given mount point.
-     * Returns an int consistent with MountServiceResultCode
-     */
-    int mountVolume(String mountPoint);
-
-    /**
-     * Safely unmount external storage at given mount point.
-     * The unmount is an asynchronous operation. Applications
-     * should register StorageEventListener for storage related
-     * status changes.
-     * 
-     */
-    void unmountVolume(String mountPoint, boolean force);
-
-    /**
-     * Format external storage given a mount point.
-     * Returns an int consistent with MountServiceResultCode
-     */
-    int formatVolume(String mountPoint);
-
-    /**
-     * Returns an array of pids with open files on
-     * the specified path.
-     */
-    int[] getStorageUsers(String path);
-
-    /**
-     * Gets the state of a volume via its mountpoint.
-     */
-    String getVolumeState(String mountPoint);
-
-    /*
-     * Creates a secure container with the specified parameters.
-     * Returns an int consistent with MountServiceResultCode
-     */
-    int createSecureContainer(String id, int sizeMb, String fstype, String key, int ownerUid);
-
-    /*
-     * Finalize a container which has just been created and populated.
-     * After finalization, the container is immutable.
-     * Returns an int consistent with MountServiceResultCode
-     */
-    int finalizeSecureContainer(String id);
-
-    /*
-     * Destroy a secure container, and free up all resources associated with it.
-     * NOTE: Ensure all references are released prior to deleting.
-     * Returns an int consistent with MountServiceResultCode
-     */
-    int destroySecureContainer(String id, boolean force);
-
-    /*
-     * Mount a secure container with the specified key and owner UID.
-     * Returns an int consistent with MountServiceResultCode
-     */
-    int mountSecureContainer(String id, String key, int ownerUid);
-
-    /*
-     * Unount a secure container.
-     * Returns an int consistent with MountServiceResultCode
-     */
-    int unmountSecureContainer(String id, boolean force);
-
-    /*
-     * Returns true if the specified container is mounted
-     */
-    boolean isSecureContainerMounted(String id);
-
-    /*
-     * Rename an unmounted secure container.
-     * Returns an int consistent with MountServiceResultCode
-     */
-    int renameSecureContainer(String oldId, String newId);
-
-    /*
-     * Returns the filesystem path of a mounted secure container.
-     */
-    String getSecureContainerPath(String id);
-
-    /**
-     * Gets an Array of currently known secure container IDs
-     */
-    String[] getSecureContainerList();
-
-    /**
-     * Shuts down the MountService and gracefully unmounts all external media.
-     * Invokes call back once the shutdown is complete.
-     */
-    void shutdown(IMountShutdownObserver observer);
-
-    /**
-     * Call into MountService by PackageManager to notify that its done
-     * processing the media status update request.
-     */
-    void finishMediaUpdate();
-
-    /**
-     * Mounts an Opaque Binary Blob (OBB) with the specified decryption key and only
-     * allows the calling process's UID access to the contents.
-     *
-     * MountService will call back to the supplied IObbActionListener to inform
-     * it of the terminal state of the call.
-     */
-    void mountObb(String filename, String key, IObbActionListener token);
-
-    /**
-     * Unmounts an Opaque Binary Blob (OBB). When the force flag is specified, any
-     * program using it will be forcibly killed to unmount the image.
-     *
-     * MountService will call back to the supplied IObbActionListener to inform
-     * it of the terminal state of the call.
-     */
-    void unmountObb(String filename, boolean force, IObbActionListener token);
-
-    /**
-     * Checks whether the specified Opaque Binary Blob (OBB) is mounted somewhere.
-     */
-    boolean isObbMounted(String filename);
-
-    /**
-     * Gets the path to the mounted Opaque Binary Blob (OBB).
-     */
-    String getMountedObbPath(String filename);
-}
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
new file mode 100644
index 0000000..60ea95c
--- /dev/null
+++ b/core/java/android/os/storage/IMountService.java
@@ -0,0 +1,1046 @@
+/*
+ * 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.
+ */
+
+package android.os.storage;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Parcel;
+import android.os.RemoteException;
+
+/**
+ * WARNING! Update IMountService.h and IMountService.cpp if you change this
+ * file. In particular, the ordering of the methods below must match the
+ * _TRANSACTION enum in IMountService.cpp
+ * 
+ * @hide - Applications should use android.os.storage.StorageManager to access
+ *       storage functions.
+ */
+public interface IMountService extends IInterface {
+    /** Local-side IPC implementation stub class. */
+    public static abstract class Stub extends Binder implements IMountService {
+        private static class Proxy implements IMountService {
+            private IBinder mRemote;
+
+            Proxy(IBinder remote) {
+                mRemote = remote;
+            }
+
+            public IBinder asBinder() {
+                return mRemote;
+            }
+
+            public String getInterfaceDescriptor() {
+                return DESCRIPTOR;
+            }
+
+            /**
+             * Registers an IMountServiceListener for receiving async
+             * notifications.
+             */
+            public void registerListener(IMountServiceListener listener) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeStrongBinder((listener != null ? listener.asBinder() : null));
+                    mRemote.transact(Stub.TRANSACTION_registerListener, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
+            /**
+             * Unregisters an IMountServiceListener
+             */
+            public void unregisterListener(IMountServiceListener listener) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeStrongBinder((listener != null ? listener.asBinder() : null));
+                    mRemote.transact(Stub.TRANSACTION_unregisterListener, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
+            /**
+             * Returns true if a USB mass storage host is connected
+             */
+            public boolean isUsbMassStorageConnected() throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                boolean _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    mRemote.transact(Stub.TRANSACTION_isUsbMassStorageConnected, _data, _reply, 0);
+                    _reply.readException();
+                    _result = 0 != _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            /**
+             * Enables / disables USB mass storage. The caller should check
+             * actual status of enabling/disabling USB mass storage via
+             * StorageEventListener.
+             */
+            public void setUsbMassStorageEnabled(boolean enable) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeInt((enable ? 1 : 0));
+                    mRemote.transact(Stub.TRANSACTION_setUsbMassStorageEnabled, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
+            /**
+             * Returns true if a USB mass storage host is enabled (media is
+             * shared)
+             */
+            public boolean isUsbMassStorageEnabled() throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                boolean _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    mRemote.transact(Stub.TRANSACTION_isUsbMassStorageEnabled, _data, _reply, 0);
+                    _reply.readException();
+                    _result = 0 != _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            /**
+             * Mount external storage at given mount point. Returns an int
+             * consistent with MountServiceResultCode
+             */
+            public int mountVolume(String mountPoint) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                int _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(mountPoint);
+                    mRemote.transact(Stub.TRANSACTION_mountVolume, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            /**
+             * Safely unmount external storage at given mount point. The unmount
+             * is an asynchronous operation. Applications should register
+             * StorageEventListener for storage related status changes.
+             */
+            public void unmountVolume(String mountPoint, boolean force) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(mountPoint);
+                    _data.writeInt((force ? 1 : 0));
+                    mRemote.transact(Stub.TRANSACTION_unmountVolume, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
+            /**
+             * Format external storage given a mount point. Returns an int
+             * consistent with MountServiceResultCode
+             */
+            public int formatVolume(String mountPoint) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                int _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(mountPoint);
+                    mRemote.transact(Stub.TRANSACTION_formatVolume, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            /**
+             * Returns an array of pids with open files on the specified path.
+             */
+            public int[] getStorageUsers(String path) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                int[] _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(path);
+                    mRemote.transact(Stub.TRANSACTION_getStorageUsers, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.createIntArray();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            /**
+             * Gets the state of a volume via its mountpoint.
+             */
+            public String getVolumeState(String mountPoint) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                String _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(mountPoint);
+                    mRemote.transact(Stub.TRANSACTION_getVolumeState, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readString();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            /*
+             * Creates a secure container with the specified parameters. Returns
+             * an int consistent with MountServiceResultCode
+             */
+            public int createSecureContainer(String id, int sizeMb, String fstype, String key,
+                    int ownerUid) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                int _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(id);
+                    _data.writeInt(sizeMb);
+                    _data.writeString(fstype);
+                    _data.writeString(key);
+                    _data.writeInt(ownerUid);
+                    mRemote.transact(Stub.TRANSACTION_createSecureContainer, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            /*
+             * Destroy a secure container, and free up all resources associated
+             * with it. NOTE: Ensure all references are released prior to
+             * deleting. Returns an int consistent with MountServiceResultCode
+             */
+            public int destroySecureContainer(String id, boolean force) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                int _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(id);
+                    _data.writeInt((force ? 1 : 0));
+                    mRemote.transact(Stub.TRANSACTION_destroySecureContainer, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            /*
+             * Finalize a container which has just been created and populated.
+             * After finalization, the container is immutable. Returns an int
+             * consistent with MountServiceResultCode
+             */
+            public int finalizeSecureContainer(String id) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                int _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(id);
+                    mRemote.transact(Stub.TRANSACTION_finalizeSecureContainer, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            /*
+             * Mount a secure container with the specified key and owner UID.
+             * Returns an int consistent with MountServiceResultCode
+             */
+            public int mountSecureContainer(String id, String key, int ownerUid)
+                    throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                int _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(id);
+                    _data.writeString(key);
+                    _data.writeInt(ownerUid);
+                    mRemote.transact(Stub.TRANSACTION_mountSecureContainer, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            /*
+             * Unount a secure container. Returns an int consistent with
+             * MountServiceResultCode
+             */
+            public int unmountSecureContainer(String id, boolean force) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                int _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(id);
+                    _data.writeInt((force ? 1 : 0));
+                    mRemote.transact(Stub.TRANSACTION_unmountSecureContainer, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            /*
+             * Returns true if the specified container is mounted
+             */
+            public boolean isSecureContainerMounted(String id) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                boolean _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(id);
+                    mRemote.transact(Stub.TRANSACTION_isSecureContainerMounted, _data, _reply, 0);
+                    _reply.readException();
+                    _result = 0 != _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            /*
+             * Rename an unmounted secure container. Returns an int consistent
+             * with MountServiceResultCode
+             */
+            public int renameSecureContainer(String oldId, String newId) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                int _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(oldId);
+                    _data.writeString(newId);
+                    mRemote.transact(Stub.TRANSACTION_renameSecureContainer, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            /*
+             * Returns the filesystem path of a mounted secure container.
+             */
+            public String getSecureContainerPath(String id) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                String _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(id);
+                    mRemote.transact(Stub.TRANSACTION_getSecureContainerPath, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readString();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            /**
+             * Gets an Array of currently known secure container IDs
+             */
+            public String[] getSecureContainerList() throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                String[] _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    mRemote.transact(Stub.TRANSACTION_getSecureContainerList, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.createStringArray();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            /**
+             * Shuts down the MountService and gracefully unmounts all external
+             * media. Invokes call back once the shutdown is complete.
+             */
+            public void shutdown(IMountShutdownObserver observer)
+                    throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeStrongBinder((observer != null ? observer.asBinder() : null));
+                    mRemote.transact(Stub.TRANSACTION_shutdown, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
+            /**
+             * Call into MountService by PackageManager to notify that its done
+             * processing the media status update request.
+             */
+            public void finishMediaUpdate() throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    mRemote.transact(Stub.TRANSACTION_finishMediaUpdate, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
+            /**
+             * Mounts an Opaque Binary Blob (OBB) with the specified decryption
+             * key and only allows the calling process's UID access to the
+             * contents. MountService will call back to the supplied
+             * IObbActionListener to inform it of the terminal state of the
+             * call.
+             */
+            public void mountObb(String filename, String key, IObbActionListener token)
+                    throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(filename);
+                    _data.writeString(key);
+                    _data.writeStrongBinder((token != null ? token.asBinder() : null));
+                    mRemote.transact(Stub.TRANSACTION_mountObb, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
+            /**
+             * Unmounts an Opaque Binary Blob (OBB). When the force flag is
+             * specified, any program using it will be forcibly killed to
+             * unmount the image. MountService will call back to the supplied
+             * IObbActionListener to inform it of the terminal state of the
+             * call.
+             */
+            public void unmountObb(String filename, boolean force, IObbActionListener token)
+                    throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(filename);
+                    _data.writeInt((force ? 1 : 0));
+                    _data.writeStrongBinder((token != null ? token.asBinder() : null));
+                    mRemote.transact(Stub.TRANSACTION_unmountObb, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
+            /**
+             * Checks whether the specified Opaque Binary Blob (OBB) is mounted
+             * somewhere.
+             */
+            public boolean isObbMounted(String filename) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                boolean _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(filename);
+                    mRemote.transact(Stub.TRANSACTION_isObbMounted, _data, _reply, 0);
+                    _reply.readException();
+                    _result = 0 != _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            /**
+             * Gets the path to the mounted Opaque Binary Blob (OBB).
+             */
+            public String getMountedObbPath(String filename) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                String _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(filename);
+                    mRemote.transact(Stub.TRANSACTION_getMountedObbPath, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readString();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+        }
+
+        private static final String DESCRIPTOR = "IMountService";
+
+        static final int TRANSACTION_registerListener = IBinder.FIRST_CALL_TRANSACTION + 0;
+
+        static final int TRANSACTION_unregisterListener = IBinder.FIRST_CALL_TRANSACTION + 1;
+
+        static final int TRANSACTION_isUsbMassStorageConnected = IBinder.FIRST_CALL_TRANSACTION + 2;
+
+        static final int TRANSACTION_setUsbMassStorageEnabled = IBinder.FIRST_CALL_TRANSACTION + 3;
+
+        static final int TRANSACTION_isUsbMassStorageEnabled = IBinder.FIRST_CALL_TRANSACTION + 4;
+
+        static final int TRANSACTION_mountVolume = IBinder.FIRST_CALL_TRANSACTION + 5;
+
+        static final int TRANSACTION_unmountVolume = IBinder.FIRST_CALL_TRANSACTION + 6;
+
+        static final int TRANSACTION_formatVolume = IBinder.FIRST_CALL_TRANSACTION + 7;
+
+        static final int TRANSACTION_getStorageUsers = IBinder.FIRST_CALL_TRANSACTION + 8;
+
+        static final int TRANSACTION_getVolumeState = IBinder.FIRST_CALL_TRANSACTION + 9;
+
+        static final int TRANSACTION_createSecureContainer = IBinder.FIRST_CALL_TRANSACTION + 10;
+
+        static final int TRANSACTION_finalizeSecureContainer = IBinder.FIRST_CALL_TRANSACTION + 11;
+
+        static final int TRANSACTION_destroySecureContainer = IBinder.FIRST_CALL_TRANSACTION + 12;
+
+        static final int TRANSACTION_mountSecureContainer = IBinder.FIRST_CALL_TRANSACTION + 13;
+
+        static final int TRANSACTION_unmountSecureContainer = IBinder.FIRST_CALL_TRANSACTION + 14;
+
+        static final int TRANSACTION_isSecureContainerMounted = IBinder.FIRST_CALL_TRANSACTION + 15;
+
+        static final int TRANSACTION_renameSecureContainer = IBinder.FIRST_CALL_TRANSACTION + 16;
+
+        static final int TRANSACTION_getSecureContainerPath = IBinder.FIRST_CALL_TRANSACTION + 17;
+
+        static final int TRANSACTION_getSecureContainerList = IBinder.FIRST_CALL_TRANSACTION + 18;
+
+        static final int TRANSACTION_shutdown = IBinder.FIRST_CALL_TRANSACTION + 19;
+
+        static final int TRANSACTION_finishMediaUpdate = IBinder.FIRST_CALL_TRANSACTION + 20;
+
+        static final int TRANSACTION_mountObb = IBinder.FIRST_CALL_TRANSACTION + 21;
+
+        static final int TRANSACTION_unmountObb = IBinder.FIRST_CALL_TRANSACTION + 22;
+
+        static final int TRANSACTION_isObbMounted = IBinder.FIRST_CALL_TRANSACTION + 23;
+
+        static final int TRANSACTION_getMountedObbPath = IBinder.FIRST_CALL_TRANSACTION + 24;
+
+        /**
+         * Cast an IBinder object into an IMountService interface, generating a
+         * proxy if needed.
+         */
+        public static IMountService asInterface(IBinder obj) {
+            if (obj == null) {
+                return null;
+            }
+            IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
+            if (iin != null && iin instanceof IMountService) {
+                return (IMountService) iin;
+            }
+            return new IMountService.Stub.Proxy(obj);
+        }
+
+        /** Construct the stub at attach it to the interface. */
+        public Stub() {
+            attachInterface(this, DESCRIPTOR);
+        }
+
+        public IBinder asBinder() {
+            return this;
+        }
+
+        @Override
+        public boolean onTransact(int code, Parcel data, Parcel reply,
+                int flags) throws RemoteException {
+            switch (code) {
+                case INTERFACE_TRANSACTION: {
+                    reply.writeString(DESCRIPTOR);
+                    return true;
+                }
+                case TRANSACTION_registerListener: {
+                    data.enforceInterface(DESCRIPTOR);
+                    IMountServiceListener listener;
+                    listener = IMountServiceListener.Stub.asInterface(data.readStrongBinder());
+                    registerListener(listener);
+                    reply.writeNoException();
+                    return true;
+                }
+                case TRANSACTION_unregisterListener: {
+                    data.enforceInterface(DESCRIPTOR);
+                    IMountServiceListener listener;
+                    listener = IMountServiceListener.Stub.asInterface(data.readStrongBinder());
+                    unregisterListener(listener);
+                    reply.writeNoException();
+                    return true;
+                }
+                case TRANSACTION_isUsbMassStorageConnected: {
+                    data.enforceInterface(DESCRIPTOR);
+                    boolean result = isUsbMassStorageConnected();
+                    reply.writeNoException();
+                    reply.writeInt((result ? 1 : 0));
+                    return true;
+                }
+                case TRANSACTION_setUsbMassStorageEnabled: {
+                    data.enforceInterface(DESCRIPTOR);
+                    boolean enable;
+                    enable = 0 != data.readInt();
+                    setUsbMassStorageEnabled(enable);
+                    reply.writeNoException();
+                    return true;
+                }
+                case TRANSACTION_isUsbMassStorageEnabled: {
+                    data.enforceInterface(DESCRIPTOR);
+                    boolean result = isUsbMassStorageEnabled();
+                    reply.writeNoException();
+                    reply.writeInt((result ? 1 : 0));
+                    return true;
+                }
+                case TRANSACTION_mountVolume: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String mountPoint;
+                    mountPoint = data.readString();
+                    int resultCode = mountVolume(mountPoint);
+                    reply.writeNoException();
+                    reply.writeInt(resultCode);
+                    return true;
+                }
+                case TRANSACTION_unmountVolume: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String mountPoint;
+                    mountPoint = data.readString();
+                    boolean force;
+                    force = 0 != data.readInt();
+                    unmountVolume(mountPoint, force);
+                    reply.writeNoException();
+                    return true;
+                }
+                case TRANSACTION_formatVolume: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String mountPoint;
+                    mountPoint = data.readString();
+                    int result = formatVolume(mountPoint);
+                    reply.writeNoException();
+                    reply.writeInt(result);
+                    return true;
+                }
+                case TRANSACTION_getStorageUsers: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String path;
+                    path = data.readString();
+                    int[] pids = getStorageUsers(path);
+                    reply.writeNoException();
+                    reply.writeIntArray(pids);
+                    return true;
+                }
+                case TRANSACTION_getVolumeState: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String mountPoint;
+                    mountPoint = data.readString();
+                    String state = getVolumeState(mountPoint);
+                    reply.writeNoException();
+                    reply.writeString(state);
+                    return true;
+                }
+                case TRANSACTION_createSecureContainer: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String id;
+                    id = data.readString();
+                    int sizeMb;
+                    sizeMb = data.readInt();
+                    String fstype;
+                    fstype = data.readString();
+                    String key;
+                    key = data.readString();
+                    int ownerUid;
+                    ownerUid = data.readInt();
+                    int resultCode = createSecureContainer(id, sizeMb, fstype, key, ownerUid);
+                    reply.writeNoException();
+                    reply.writeInt(resultCode);
+                    return true;
+                }
+                case TRANSACTION_finalizeSecureContainer: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String id;
+                    id = data.readString();
+                    int resultCode = finalizeSecureContainer(id);
+                    reply.writeNoException();
+                    reply.writeInt(resultCode);
+                    return true;
+                }
+                case TRANSACTION_destroySecureContainer: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String id;
+                    id = data.readString();
+                    boolean force;
+                    force = 0 != data.readInt();
+                    int resultCode = destroySecureContainer(id, force);
+                    reply.writeNoException();
+                    reply.writeInt(resultCode);
+                    return true;
+                }
+                case TRANSACTION_mountSecureContainer: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String id;
+                    id = data.readString();
+                    String key;
+                    key = data.readString();
+                    int ownerUid;
+                    ownerUid = data.readInt();
+                    int resultCode = mountSecureContainer(id, key, ownerUid);
+                    reply.writeNoException();
+                    reply.writeInt(resultCode);
+                    return true;
+                }
+                case TRANSACTION_unmountSecureContainer: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String id;
+                    id = data.readString();
+                    boolean force;
+                    force = 0 != data.readInt();
+                    int resultCode = unmountSecureContainer(id, force);
+                    reply.writeNoException();
+                    reply.writeInt(resultCode);
+                    return true;
+                }
+                case TRANSACTION_isSecureContainerMounted: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String id;
+                    id = data.readString();
+                    boolean status = isSecureContainerMounted(id);
+                    reply.writeNoException();
+                    reply.writeInt((status ? 1 : 0));
+                    return true;
+                }
+                case TRANSACTION_renameSecureContainer: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String oldId;
+                    oldId = data.readString();
+                    String newId;
+                    newId = data.readString();
+                    int resultCode = renameSecureContainer(oldId, newId);
+                    reply.writeNoException();
+                    reply.writeInt(resultCode);
+                    return true;
+                }
+                case TRANSACTION_getSecureContainerPath: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String id;
+                    id = data.readString();
+                    String path = getSecureContainerPath(id);
+                    reply.writeNoException();
+                    reply.writeString(path);
+                    return true;
+                }
+                case TRANSACTION_getSecureContainerList: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String[] ids = getSecureContainerList();
+                    reply.writeNoException();
+                    reply.writeStringArray(ids);
+                    return true;
+                }
+                case TRANSACTION_shutdown: {
+                    data.enforceInterface(DESCRIPTOR);
+                    IMountShutdownObserver observer;
+                    observer = IMountShutdownObserver.Stub.asInterface(data
+                            .readStrongBinder());
+                    shutdown(observer);
+                    reply.writeNoException();
+                    return true;
+                }
+                case TRANSACTION_finishMediaUpdate: {
+                    data.enforceInterface(DESCRIPTOR);
+                    finishMediaUpdate();
+                    reply.writeNoException();
+                    return true;
+                }
+                case TRANSACTION_mountObb: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String filename;
+                    filename = data.readString();
+                    String key;
+                    key = data.readString();
+                    IObbActionListener observer;
+                    observer = IObbActionListener.Stub.asInterface(data.readStrongBinder());
+                    mountObb(filename, key, observer);
+                    reply.writeNoException();
+                    return true;
+                }
+                case TRANSACTION_unmountObb: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String filename;
+                    filename = data.readString();
+                    boolean force;
+                    force = 0 != data.readInt();
+                    IObbActionListener observer;
+                    observer = IObbActionListener.Stub.asInterface(data.readStrongBinder());
+                    unmountObb(filename, force, observer);
+                    reply.writeNoException();
+                    return true;
+                }
+                case TRANSACTION_isObbMounted: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String filename;
+                    filename = data.readString();
+                    boolean status = isObbMounted(filename);
+                    reply.writeNoException();
+                    reply.writeInt((status ? 1 : 0));
+                    return true;
+                }
+                case TRANSACTION_getMountedObbPath: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String filename;
+                    filename = data.readString();
+                    String mountedPath = getMountedObbPath(filename);
+                    reply.writeNoException();
+                    reply.writeString(mountedPath);
+                    return true;
+                }
+            }
+            return super.onTransact(code, data, reply, flags);
+        }
+    }
+
+    /*
+     * Creates a secure container with the specified parameters. Returns an int
+     * consistent with MountServiceResultCode
+     */
+    public int createSecureContainer(String id, int sizeMb, String fstype, String key, int ownerUid)
+            throws RemoteException;
+
+    /*
+     * Destroy a secure container, and free up all resources associated with it.
+     * NOTE: Ensure all references are released prior to deleting. Returns an
+     * int consistent with MountServiceResultCode
+     */
+    public int destroySecureContainer(String id, boolean force) throws RemoteException;
+
+    /*
+     * Finalize a container which has just been created and populated. After
+     * finalization, the container is immutable. Returns an int consistent with
+     * MountServiceResultCode
+     */
+    public int finalizeSecureContainer(String id) throws RemoteException;
+
+    /**
+     * Call into MountService by PackageManager to notify that its done
+     * processing the media status update request.
+     */
+    public void finishMediaUpdate() throws RemoteException;
+
+    /**
+     * Format external storage given a mount point. Returns an int consistent
+     * with MountServiceResultCode
+     */
+    public int formatVolume(String mountPoint) throws RemoteException;
+
+    /**
+     * Gets the path to the mounted Opaque Binary Blob (OBB).
+     */
+    public String getMountedObbPath(String filename) throws RemoteException;
+
+    /**
+     * Gets an Array of currently known secure container IDs
+     */
+    public String[] getSecureContainerList() throws RemoteException;
+
+    /*
+     * Returns the filesystem path of a mounted secure container.
+     */
+    public String getSecureContainerPath(String id) throws RemoteException;
+
+    /**
+     * Returns an array of pids with open files on the specified path.
+     */
+    public int[] getStorageUsers(String path) throws RemoteException;
+
+    /**
+     * Gets the state of a volume via its mountpoint.
+     */
+    public String getVolumeState(String mountPoint) throws RemoteException;
+
+    /**
+     * Checks whether the specified Opaque Binary Blob (OBB) is mounted
+     * somewhere.
+     */
+    public boolean isObbMounted(String filename) throws RemoteException;
+
+    /*
+     * Returns true if the specified container is mounted
+     */
+    public boolean isSecureContainerMounted(String id) throws RemoteException;
+
+    /**
+     * Returns true if a USB mass storage host is connected
+     */
+    public boolean isUsbMassStorageConnected() throws RemoteException;
+
+    /**
+     * Returns true if a USB mass storage host is enabled (media is shared)
+     */
+    public boolean isUsbMassStorageEnabled() throws RemoteException;
+
+    /**
+     * Mounts an Opaque Binary Blob (OBB) with the specified decryption key and
+     * only allows the calling process's UID access to the contents.
+     * MountService will call back to the supplied IObbActionListener to inform
+     * it of the terminal state of the call.
+     */
+    public void mountObb(String filename, String key, IObbActionListener token)
+            throws RemoteException;
+
+    /*
+     * Mount a secure container with the specified key and owner UID. Returns an
+     * int consistent with MountServiceResultCode
+     */
+    public int mountSecureContainer(String id, String key, int ownerUid) throws RemoteException;
+
+    /**
+     * Mount external storage at given mount point. Returns an int consistent
+     * with MountServiceResultCode
+     */
+    public int mountVolume(String mountPoint) throws RemoteException;
+
+    /**
+     * Registers an IMountServiceListener for receiving async notifications.
+     */
+    public void registerListener(IMountServiceListener listener) throws RemoteException;
+
+    /*
+     * Rename an unmounted secure container. Returns an int consistent with
+     * MountServiceResultCode
+     */
+    public int renameSecureContainer(String oldId, String newId) throws RemoteException;
+
+    /**
+     * Enables / disables USB mass storage. The caller should check actual
+     * status of enabling/disabling USB mass storage via StorageEventListener.
+     */
+    public void setUsbMassStorageEnabled(boolean enable) throws RemoteException;
+
+    /**
+     * Shuts down the MountService and gracefully unmounts all external media.
+     * Invokes call back once the shutdown is complete.
+     */
+    public void shutdown(IMountShutdownObserver observer) throws RemoteException;
+
+    /**
+     * Unmounts an Opaque Binary Blob (OBB). When the force flag is specified,
+     * any program using it will be forcibly killed to unmount the image.
+     * MountService will call back to the supplied IObbActionListener to inform
+     * it of the terminal state of the call.
+     */
+    public void unmountObb(String filename, boolean force, IObbActionListener token)
+            throws RemoteException;
+
+    /*
+     * Unount a secure container. Returns an int consistent with
+     * MountServiceResultCode
+     */
+    public int unmountSecureContainer(String id, boolean force) throws RemoteException;
+
+    /**
+     * Safely unmount external storage at given mount point. The unmount is an
+     * asynchronous operation. Applications should register StorageEventListener
+     * for storage related status changes.
+     */
+    public void unmountVolume(String mountPoint, boolean force) throws RemoteException;
+
+    /**
+     * Unregisters an IMountServiceListener
+     */
+    public void unregisterListener(IMountServiceListener listener) throws RemoteException;
+}
diff --git a/core/java/android/os/storage/IMountServiceListener.aidl b/core/java/android/os/storage/IMountServiceListener.aidl
deleted file mode 100644
index 883413a..0000000
--- a/core/java/android/os/storage/IMountServiceListener.aidl
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os.storage;
-
-/**
- * Callback class for receiving events from MountService.
- *
- * @hide - Applications should use android.os.storage.IStorageEventListener
- * for storage event callbacks.
- */
-interface IMountServiceListener {
-    /**
-     * Detection state of USB Mass Storage has changed
-     *
-     * @param available true if a UMS host is connected.
-     */
-    void onUsbMassStorageConnectionChanged(boolean connected);
-
-    /**
-     * Storage state has changed.
-     *
-     * @param path The volume mount path.
-     * @param oldState The old state of the volume.
-     * @param newState The new state of the volume.
-     *
-     * Note: State is one of the values returned by Environment.getExternalStorageState()
-     */
-    void onStorageStateChanged(String path, String oldState, String newState);
-}
diff --git a/core/java/android/os/storage/IMountServiceListener.java b/core/java/android/os/storage/IMountServiceListener.java
new file mode 100644
index 0000000..d5c5fa5
--- /dev/null
+++ b/core/java/android/os/storage/IMountServiceListener.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Parcel;
+import android.os.RemoteException;
+
+/**
+ * Callback class for receiving events from MountService.
+ * 
+ * @hide - Applications should use IStorageEventListener for storage event
+ *       callbacks.
+ */
+public interface IMountServiceListener extends IInterface {
+    /** Local-side IPC implementation stub class. */
+    public static abstract class Stub extends Binder implements IMountServiceListener {
+        private static final String DESCRIPTOR = "IMountServiceListener";
+
+        /** Construct the stub at attach it to the interface. */
+        public Stub() {
+            this.attachInterface(this, DESCRIPTOR);
+        }
+
+        /**
+         * Cast an IBinder object into an IMountServiceListener interface,
+         * generating a proxy if needed.
+         */
+        public static IMountServiceListener asInterface(IBinder obj) {
+            if ((obj == null)) {
+                return null;
+            }
+            IInterface iin = (IInterface) obj.queryLocalInterface(DESCRIPTOR);
+            if (((iin != null) && (iin instanceof IMountServiceListener))) {
+                return ((IMountServiceListener) iin);
+            }
+            return new IMountServiceListener.Stub.Proxy(obj);
+        }
+
+        public IBinder asBinder() {
+            return this;
+        }
+
+        @Override
+        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+                throws RemoteException {
+            switch (code) {
+                case INTERFACE_TRANSACTION: {
+                    reply.writeString(DESCRIPTOR);
+                    return true;
+                }
+                case TRANSACTION_onUsbMassStorageConnectionChanged: {
+                    data.enforceInterface(DESCRIPTOR);
+                    boolean connected;
+                    connected = (0 != data.readInt());
+                    this.onUsbMassStorageConnectionChanged(connected);
+                    reply.writeNoException();
+                    return true;
+                }
+                case TRANSACTION_onStorageStateChanged: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String path;
+                    path = data.readString();
+                    String oldState;
+                    oldState = data.readString();
+                    String newState;
+                    newState = data.readString();
+                    this.onStorageStateChanged(path, oldState, newState);
+                    reply.writeNoException();
+                    return true;
+                }
+            }
+            return super.onTransact(code, data, reply, flags);
+        }
+
+        private static class Proxy implements IMountServiceListener {
+            private IBinder mRemote;
+
+            Proxy(IBinder remote) {
+                mRemote = remote;
+            }
+
+            public IBinder asBinder() {
+                return mRemote;
+            }
+
+            public String getInterfaceDescriptor() {
+                return DESCRIPTOR;
+            }
+
+            /**
+             * Detection state of USB Mass Storage has changed
+             * 
+             * @param available true if a UMS host is connected.
+             */
+            public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeInt(((connected) ? (1) : (0)));
+                    mRemote.transact(Stub.TRANSACTION_onUsbMassStorageConnectionChanged, _data,
+                            _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
+            /**
+             * Storage state has changed.
+             * 
+             * @param path The volume mount path.
+             * @param oldState The old state of the volume.
+             * @param newState The new state of the volume. Note: State is one
+             *            of the values returned by
+             *            Environment.getExternalStorageState()
+             */
+            public void onStorageStateChanged(String path, String oldState, String newState)
+                    throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(path);
+                    _data.writeString(oldState);
+                    _data.writeString(newState);
+                    mRemote.transact(Stub.TRANSACTION_onStorageStateChanged, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+        }
+
+        static final int TRANSACTION_onUsbMassStorageConnectionChanged = (IBinder.FIRST_CALL_TRANSACTION + 0);
+
+        static final int TRANSACTION_onStorageStateChanged = (IBinder.FIRST_CALL_TRANSACTION + 1);
+    }
+
+    /**
+     * Detection state of USB Mass Storage has changed
+     * 
+     * @param available true if a UMS host is connected.
+     */
+    public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException;
+
+    /**
+     * Storage state has changed.
+     * 
+     * @param path The volume mount path.
+     * @param oldState The old state of the volume.
+     * @param newState The new state of the volume. Note: State is one of the
+     *            values returned by Environment.getExternalStorageState()
+     */
+    public void onStorageStateChanged(String path, String oldState, String newState)
+            throws RemoteException;
+}
diff --git a/core/java/android/os/storage/IMountShutdownObserver.aidl b/core/java/android/os/storage/IMountShutdownObserver.aidl
deleted file mode 100644
index 0aa8a45..0000000
--- a/core/java/android/os/storage/IMountShutdownObserver.aidl
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os.storage;
-
-/**
- * Callback class for receiving events related
- * to shutdown.
- *
- * @hide - For internal consumption only.
- */
-interface IMountShutdownObserver {
-    /**
-     * This method is called when the shutdown
-     * of MountService completed.
-     * @param statusCode indicates success or failure
-     * of the shutdown.
-     */
-    void onShutDownComplete(int statusCode);
-}
diff --git a/core/java/android/os/storage/IMountShutdownObserver.java b/core/java/android/os/storage/IMountShutdownObserver.java
new file mode 100644
index 0000000..d946e1a
--- /dev/null
+++ b/core/java/android/os/storage/IMountShutdownObserver.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Parcel;
+import android.os.RemoteException;
+
+/**
+ * Callback class for receiving events related to shutdown.
+ * 
+ * @hide - For internal consumption only.
+ */
+public interface IMountShutdownObserver extends IInterface {
+    /** Local-side IPC implementation stub class. */
+    public static abstract class Stub extends Binder implements IMountShutdownObserver {
+        private static final java.lang.String DESCRIPTOR = "IMountShutdownObserver";
+
+        /** Construct the stub at attach it to the interface. */
+        public Stub() {
+            this.attachInterface(this, DESCRIPTOR);
+        }
+
+        /**
+         * Cast an IBinder object into an IMountShutdownObserver interface,
+         * generating a proxy if needed.
+         */
+        public static IMountShutdownObserver asInterface(IBinder obj) {
+            if ((obj == null)) {
+                return null;
+            }
+            IInterface iin = (IInterface) obj.queryLocalInterface(DESCRIPTOR);
+            if (((iin != null) && (iin instanceof IMountShutdownObserver))) {
+                return ((IMountShutdownObserver) iin);
+            }
+            return new IMountShutdownObserver.Stub.Proxy(obj);
+        }
+
+        public IBinder asBinder() {
+            return this;
+        }
+
+        @Override
+        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+                throws RemoteException {
+            switch (code) {
+                case INTERFACE_TRANSACTION: {
+                    reply.writeString(DESCRIPTOR);
+                    return true;
+                }
+                case TRANSACTION_onShutDownComplete: {
+                    data.enforceInterface(DESCRIPTOR);
+                    int statusCode;
+                    statusCode = data.readInt();
+                    this.onShutDownComplete(statusCode);
+                    reply.writeNoException();
+                    return true;
+                }
+            }
+            return super.onTransact(code, data, reply, flags);
+        }
+
+        private static class Proxy implements IMountShutdownObserver {
+            private IBinder mRemote;
+
+            Proxy(IBinder remote) {
+                mRemote = remote;
+            }
+
+            public IBinder asBinder() {
+                return mRemote;
+            }
+
+            public java.lang.String getInterfaceDescriptor() {
+                return DESCRIPTOR;
+            }
+
+            /**
+             * This method is called when the shutdown of MountService
+             * completed.
+             * 
+             * @param statusCode indicates success or failure of the shutdown.
+             */
+            public void onShutDownComplete(int statusCode) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeInt(statusCode);
+                    mRemote.transact(Stub.TRANSACTION_onShutDownComplete, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+        }
+
+        static final int TRANSACTION_onShutDownComplete = (IBinder.FIRST_CALL_TRANSACTION + 0);
+    }
+
+    /**
+     * This method is called when the shutdown of MountService completed.
+     * 
+     * @param statusCode indicates success or failure of the shutdown.
+     */
+    public void onShutDownComplete(int statusCode) throws RemoteException;
+}
diff --git a/core/java/android/os/storage/IObbActionListener.aidl b/core/java/android/os/storage/IObbActionListener.aidl
deleted file mode 100644
index 78d7a9e..0000000
--- a/core/java/android/os/storage/IObbActionListener.aidl
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.
- */
-
-package android.os.storage;
-
-/**
- * Callback class for receiving events from MountService about
- * Opaque Binary Blobs (OBBs).
- *
- * @hide - Applications should use android.os.storage.StorageManager
- * to interact with OBBs.
- */
-interface IObbActionListener {
-    /**
-     * Return from an OBB action result.
-     *
-     * @param filename the path to the OBB the operation was performed on
-     * @param returnCode status of the operation
-     */
-    void onObbResult(String filename, String status);
-}
diff --git a/core/java/android/os/storage/IObbActionListener.java b/core/java/android/os/storage/IObbActionListener.java
new file mode 100644
index 0000000..2c098ac
--- /dev/null
+++ b/core/java/android/os/storage/IObbActionListener.java
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+package android.os.storage;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Parcel;
+import android.os.RemoteException;
+
+/**
+ * Callback class for receiving events from MountService about Opaque Binary
+ * Blobs (OBBs).
+ * 
+ * @hide - Applications should use StorageManager to interact with OBBs.
+ */
+public interface IObbActionListener extends IInterface {
+    /** Local-side IPC implementation stub class. */
+    public static abstract class Stub extends Binder implements IObbActionListener {
+        private static final String DESCRIPTOR = "IObbActionListener";
+
+        /** Construct the stub at attach it to the interface. */
+        public Stub() {
+            this.attachInterface(this, DESCRIPTOR);
+        }
+
+        /**
+         * Cast an IBinder object into an IObbActionListener interface,
+         * generating a proxy if needed.
+         */
+        public static IObbActionListener asInterface(IBinder obj) {
+            if ((obj == null)) {
+                return null;
+            }
+            IInterface iin = (IInterface) obj.queryLocalInterface(DESCRIPTOR);
+            if (((iin != null) && (iin instanceof IObbActionListener))) {
+                return ((IObbActionListener) iin);
+            }
+            return new IObbActionListener.Stub.Proxy(obj);
+        }
+
+        public IBinder asBinder() {
+            return this;
+        }
+
+        @Override
+        public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+                throws RemoteException {
+            switch (code) {
+                case INTERFACE_TRANSACTION: {
+                    reply.writeString(DESCRIPTOR);
+                    return true;
+                }
+                case TRANSACTION_onObbResult: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String filename;
+                    filename = data.readString();
+                    String status;
+                    status = data.readString();
+                    this.onObbResult(filename, status);
+                    reply.writeNoException();
+                    return true;
+                }
+            }
+            return super.onTransact(code, data, reply, flags);
+        }
+
+        private static class Proxy implements IObbActionListener {
+            private IBinder mRemote;
+
+            Proxy(IBinder remote) {
+                mRemote = remote;
+            }
+
+            public IBinder asBinder() {
+                return mRemote;
+            }
+
+            public String getInterfaceDescriptor() {
+                return DESCRIPTOR;
+            }
+
+            /**
+             * Return from an OBB action result.
+             * 
+             * @param filename the path to the OBB the operation was performed
+             *            on
+             * @param returnCode status of the operation
+             */
+            public void onObbResult(String filename, String status) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(filename);
+                    _data.writeString(status);
+                    mRemote.transact(Stub.TRANSACTION_onObbResult, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+        }
+
+        static final int TRANSACTION_onObbResult = (IBinder.FIRST_CALL_TRANSACTION + 0);
+    }
+
+    /**
+     * Return from an OBB action result.
+     * 
+     * @param filename the path to the OBB the operation was performed on
+     * @param returnCode status of the operation
+     */
+    public void onObbResult(String filename, String status) throws RemoteException;
+}
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 9948060..3861ef5 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -644,7 +644,7 @@
              } else {
                  Log.i(TAG, "Rejecting incoming HID connection from " + address);
              }
-        } else if (BluetoothUuid.isNAP(uuid)){
+        } else if (BluetoothUuid.isBnep(uuid) || BluetoothUuid.isNap(uuid)){
             authorized = true;
         } else {
             Log.i(TAG, "Rejecting incoming " + deviceUuid + " connection from " + address);
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index 79a0c37..baaf39d 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -287,8 +287,7 @@
                     // Offset the current touch position (from controller to cursor)
                     final float x = event.getX() + mCursorController.getOffsetX();
                     final float y = event.getY() + mCursorController.getOffsetY();
-                    int offset = widget.getOffset((int) x, (int) y);
-                    mCursorController.updatePosition(offset);
+                    mCursorController.updatePosition((int) x, (int) y);
                     return true;
 
                 case MotionEvent.ACTION_UP:
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index e2e3333..3678684 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -856,6 +856,9 @@
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
         if ((mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == FLAG_SPLIT_MOTION_EVENTS) {
+            if (mSplitMotionTargets == null) {
+                mSplitMotionTargets = new SplitMotionTargets();
+            }
             return dispatchSplitTouchEvent(ev);
         }
 
@@ -1036,19 +1039,21 @@
                 ev.setAction(action);
                 // We know we want to dispatch the event down, try to find a child
                 // who can handle it, start with the front-most child.
+                final long downTime = ev.getEventTime();
                 final View[] children = mChildren;
                 final int count = mChildrenCount;
                 for (int i = count - 1; i >= 0; i--) {
                     final View child = children[i];
                     if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
                             || child.getAnimation() != null) {
-                        final MotionEvent childEvent = targets.filterMotionEventForChild(ev, child);
+                        final MotionEvent childEvent =
+                                targets.filterMotionEventForChild(ev, child, downTime);
                         if (childEvent != null) {
                             try {
                                 final int childActionIndex = childEvent.findPointerIndex(actionId);
                                 if (dispatchTouchEventIfInView(child, childEvent,
                                         childActionIndex)) {
-                                    targets.add(actionId, child);
+                                    targets.add(actionId, child, downTime);
 
                                     return true;
                                 }
@@ -1060,10 +1065,11 @@
                 }
 
                 // Didn't find a new target. Do we have a "primary" target to send to?
-                final View primaryTarget = targets.getPrimaryTarget();
-                if (primaryTarget != null) {
-                    final MotionEvent childEvent =
-                            targets.filterMotionEventForChild(ev, primaryTarget);
+                final SplitMotionTargets.TargetInfo primaryTargetInfo = targets.getPrimaryTarget();
+                if (primaryTargetInfo != null) {
+                    final View primaryTarget = primaryTargetInfo.view;
+                    final MotionEvent childEvent = targets.filterMotionEventForChild(ev,
+                            primaryTarget, primaryTargetInfo.downTime);
                     if (childEvent != null) {
                         try {
                             // Calculate the offset point into the target's local coordinates
@@ -1081,7 +1087,7 @@
                             }
                             childEvent.setLocation(xc, yc);
                             if (primaryTarget.dispatchTouchEvent(childEvent)) {
-                                targets.add(actionId, primaryTarget);
+                                targets.add(actionId, primaryTarget, primaryTargetInfo.downTime);
                                 return true;
                             }
                         } finally {
@@ -1119,7 +1125,7 @@
             mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
 
             for (int uniqueIndex = 0; uniqueIndex < uniqueTargetCount; uniqueIndex++) {
-                final View target = targets.getUniqueTargetAt(uniqueIndex);
+                final View target = targets.getUniqueTargetAt(uniqueIndex).view;
 
                 // Calculate the offset point into the target's local coordinates
                 float xc = scrolledXFloat - (float) target.mLeft;
@@ -1150,9 +1156,11 @@
 
         boolean handled = false;
         for (int uniqueIndex = 0; uniqueIndex < uniqueTargetCount; uniqueIndex++) {
-            final View target = targets.getUniqueTargetAt(uniqueIndex);
+            final SplitMotionTargets.TargetInfo targetInfo = targets.getUniqueTargetAt(uniqueIndex);
+            final View target = targetInfo.view;
 
-            final MotionEvent targetEvent = targets.filterMotionEventForChild(ev, target);
+            final MotionEvent targetEvent =
+                    targets.filterMotionEventForChild(ev, target, targetInfo.downTime);
             if (targetEvent == null) {
                 continue;
             }
@@ -1187,7 +1195,13 @@
                     uniqueTargetCount--;
                 }
 
-                handled |= target.dispatchTouchEvent(targetEvent);
+                final boolean childHandled = target.dispatchTouchEvent(targetEvent);
+                handled |= childHandled;
+                if (!childHandled) {
+                    // Child doesn't want these events anymore, but we're still dispatching
+                    // other split events to children.
+                    targets.removeView(target);
+                }
             } finally {
                 targetEvent.recycle();
             }
@@ -1223,9 +1237,6 @@
         // but perhaps this should handle that case and send ACTION_CANCELs to any child views
         // with gestures in progress when this is changed.
         if (split) {
-            if ((mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == 0) {
-                mSplitMotionTargets = new SplitMotionTargets();
-            }
             mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
         } else {
             mGroupFlags &= ~FLAG_SPLIT_MOTION_EVENTS;
@@ -4103,9 +4114,8 @@
 
     private static class SplitMotionTargets {
         private SparseArray<View> mTargets;
-        private View[] mUniqueTargets;
+        private TargetInfo[] mUniqueTargets;
         private int mUniqueTargetCount;
-        private long mDownTime;
         private MotionEvent.PointerCoords[] mPointerCoords;
         private int[] mPointerIds;
 
@@ -4114,7 +4124,7 @@
 
         public SplitMotionTargets() {
             mTargets = new SparseArray<View>();
-            mUniqueTargets = new View[INITIAL_UNIQUE_MOTION_TARGETS_SIZE];
+            mUniqueTargets = new TargetInfo[INITIAL_UNIQUE_MOTION_TARGETS_SIZE];
             mPointerIds = new int[INITIAL_BUCKET_SIZE];
             mPointerCoords = new MotionEvent.PointerCoords[INITIAL_BUCKET_SIZE];
             for (int i = 0; i < INITIAL_BUCKET_SIZE; i++) {
@@ -4124,31 +4134,32 @@
 
         public void clear() {
             mTargets.clear();
-            Arrays.fill(mUniqueTargets, null);
+            final int count = mUniqueTargetCount;
+            for (int i = 0; i < count; i++) {
+                mUniqueTargets[i].recycle();
+                mUniqueTargets[i] = null;
+            }
             mUniqueTargetCount = 0;
         }
 
-        public void add(int pointerId, View target) {
+        public void add(int pointerId, View target, long downTime) {
             mTargets.put(pointerId, target);
 
             final int uniqueCount = mUniqueTargetCount;
             boolean addUnique = true;
             for (int i = 0; i < uniqueCount; i++) {
-                if (mUniqueTargets[i] == target) {
+                if (mUniqueTargets[i].view == target) {
                     addUnique = false;
                 }
             }
             if (addUnique) {
-                if (mUniqueTargets == null) {
-                    mUniqueTargets = new View[INITIAL_UNIQUE_MOTION_TARGETS_SIZE];
-                }
                 if (mUniqueTargets.length == uniqueCount) {
-                    View[] newTargets =
-                        new View[uniqueCount + INITIAL_UNIQUE_MOTION_TARGETS_SIZE];
+                    TargetInfo[] newTargets =
+                        new TargetInfo[uniqueCount + INITIAL_UNIQUE_MOTION_TARGETS_SIZE];
                     System.arraycopy(mUniqueTargets, 0, newTargets, 0, uniqueCount);
                     mUniqueTargets = newTargets;
                 }
-                mUniqueTargets[uniqueCount] = target;
+                mUniqueTargets[uniqueCount] = TargetInfo.obtain(target, downTime);
                 mUniqueTargetCount++;
             }
         }
@@ -4161,7 +4172,7 @@
             return mUniqueTargetCount;
         }
 
-        public View getUniqueTargetAt(int index) {
+        public TargetInfo getUniqueTargetAt(int index) {
             return mUniqueTargets[index];
         }
 
@@ -4185,18 +4196,29 @@
             return mTargets.valueAt(index);
         }
 
-        public View getPrimaryTarget() {
+        public TargetInfo getPrimaryTarget() {
             if (!isEmpty()) {
-                return mUniqueTargets[0];
+                // Find the longest-lived target
+                long firstTime = Long.MAX_VALUE;
+                int firstIndex = 0;
+                final int uniqueCount = mUniqueTargetCount;
+                for (int i = 0; i < uniqueCount; i++) {
+                    TargetInfo info = mUniqueTargets[i];
+                    if (info.downTime < firstTime) {
+                        firstTime = info.downTime;
+                        firstIndex = i;
+                    }
+                }
+                return mUniqueTargets[firstIndex];
             }
             return null;
         }
 
         public boolean hasTarget(View target) {
-            final View[] unique = mUniqueTargets;
+            final TargetInfo[] unique = mUniqueTargets;
             final int uniqueCount = mUniqueTargetCount;
             for (int i = 0; i < uniqueCount; i++) {
-                if (unique[i] == target) {
+                if (unique[i].view == target) {
                     return true;
                 }
             }
@@ -4237,10 +4259,11 @@
         }
 
         private void removeUnique(View removeView) {
-            View[] unique = mUniqueTargets;
+            TargetInfo[] unique = mUniqueTargets;
             int uniqueCount = mUniqueTargetCount;
             for (int i = 0; i < uniqueCount; i++) {
-                if (unique[i] == removeView) {
+                if (unique[i].view == removeView) {
+                    unique[i].recycle();
                     unique[i] = unique[--uniqueCount];
                     unique[uniqueCount] = null;
                     break;
@@ -4254,7 +4277,7 @@
          * Return a new (obtain()ed) MotionEvent containing only data for pointers that should
          * be dispatched to child. Don't forget to recycle it!
          */
-        public MotionEvent filterMotionEventForChild(MotionEvent ev, View child) {
+        public MotionEvent filterMotionEventForChild(MotionEvent ev, View child, long downTime) {
             int action = ev.getAction();
             final int maskedAction = action & MotionEvent.ACTION_MASK;
 
@@ -4279,7 +4302,6 @@
             if (maskedAction == MotionEvent.ACTION_DOWN) {
                 pointerCount++;
                 actionId = ev.getPointerId(0);
-                mDownTime = ev.getDownTime();
             } else if (maskedAction == MotionEvent.ACTION_POINTER_DOWN) {
                 pointerCount++;
 
@@ -4352,11 +4374,49 @@
                         (newActionIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
             }
 
-            MotionEvent result = MotionEvent.obtain(mDownTime, ev.getEventTime(),
+            MotionEvent result = MotionEvent.obtain(downTime, ev.getEventTime(),
                     action, pointerCount, mPointerIds, mPointerCoords, ev.getMetaState(),
                     ev.getXPrecision(), ev.getYPrecision(), ev.getDeviceId(), ev.getEdgeFlags(),
                     ev.getSource());
             return result;
         }
+
+        static class TargetInfo {
+            public View view;
+            public long downTime;
+
+            private TargetInfo mNextRecycled;
+
+            private static TargetInfo sRecycleBin;
+            private static int sRecycledCount;
+
+            private static int MAX_RECYCLED = 15;
+
+            private TargetInfo() {
+            }
+
+            public static TargetInfo obtain(View v, long time) {
+                TargetInfo info;
+                if (sRecycleBin == null) {
+                    info = new TargetInfo();
+                } else {
+                    info = sRecycleBin;
+                    sRecycleBin = info.mNextRecycled;
+                    sRecycledCount--;
+                }
+                info.view = v;
+                info.downTime = time;
+                return info;
+            }
+
+            public void recycle() {
+                if (sRecycledCount >= MAX_RECYCLED) {
+                    return;
+                }
+                mNextRecycled = sRecycleBin;
+                sRecycleBin = this;
+                sRecycledCount++;
+            }
+        }
     }
 }
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index b021ded..e972c24 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -38,6 +38,8 @@
 
 import junit.framework.Assert;
 
+import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.io.InputStream;
 import java.lang.ref.WeakReference;
 import java.net.URLEncoder;
@@ -658,6 +660,96 @@
     }
 
     /**
+     * Called by JNI.
+     * Read from an InputStream into a supplied byte[]
+     * This method catches any exceptions so they don't crash the JVM.
+     * @param inputStream InputStream to read from.
+     * @param output Bytearray that gets the output.
+     * @return the number of bytes read, or -i if then end of stream has been reached
+     */
+    private static int readFromStream(InputStream inputStream, byte[] output) {
+        try {
+            return inputStream.read(output);
+        } catch(java.io.IOException e) {
+            // If we get an exception, return end of stream
+            return -1;
+        }
+    }
+
+    /**
+     * Get the InputStream for an Android resource
+     * There are three different kinds of android resources:
+     * - file:///android_res
+     * - file:///android_asset
+     * - content://
+     * @param url The url to load.
+     * @return An InputStream to the android resource
+     */
+    private InputStream inputStreamForAndroidResource(String url, int type) {
+        final int RESOURCE = 1;
+        final int ASSET = 2;
+        final int CONTENT = 3;
+
+        if (type == RESOURCE) {
+            // file:///android_res
+            if (url == null || url.length() == 0) {
+                Log.e(LOGTAG, "url has length 0 " + url);
+                return null;
+            }
+            int slash = url.indexOf('/');
+            int dot = url.indexOf('.', slash);
+            if (slash == -1 || dot == -1) {
+                Log.e(LOGTAG, "Incorrect res path: " + url);
+                return null;
+            }
+            String subClassName = url.substring(0, slash);
+            String fieldName = url.substring(slash + 1, dot);
+            String errorMsg = null;
+            try {
+                final Class<?> d = mContext.getApplicationContext()
+                        .getClassLoader().loadClass(
+                                mContext.getPackageName() + ".R$"
+                                        + subClassName);
+                final java.lang.reflect.Field field = d.getField(fieldName);
+                final int id = field.getInt(null);
+                TypedValue value = new TypedValue();
+                mContext.getResources().getValue(id, value, true);
+                if (value.type == TypedValue.TYPE_STRING) {
+                    return mContext.getAssets().openNonAsset(
+                            value.assetCookie, value.string.toString(),
+                            AssetManager.ACCESS_STREAMING);
+                } else {
+                    // Old stack only supports TYPE_STRING for res files
+                    Log.e(LOGTAG, "not of type string: " + url);
+                    return null;
+                }
+            } catch (Exception e) {
+                Log.e(LOGTAG, "Exception: " + url);
+                return null;
+            }
+
+        } else if (type == ASSET) {
+            // file:///android_asset
+            try {
+                AssetManager assets = mContext.getAssets();
+                return assets.open(url, AssetManager.ACCESS_STREAMING);
+            } catch (IOException e) {
+                return null;
+            }
+        } else if (type == CONTENT) {
+            try {
+                Uri uri = Uri.parse(url);
+                return mContext.getContentResolver().openInputStream(uri);
+            } catch (Exception e) {
+                Log.e(LOGTAG, "Exception: " + url);
+                return null;
+            }
+        } else {
+            return null;
+        }
+    }
+
+    /**
      * Start loading a resource.
      * @param loaderHandle The native ResourceLoader that is the target of the
      *                     data.
diff --git a/core/java/android/webkit/DeviceOrientationService.java b/core/java/android/webkit/DeviceOrientationService.java
index 07d3d2f..4ff849e 100755
--- a/core/java/android/webkit/DeviceOrientationService.java
+++ b/core/java/android/webkit/DeviceOrientationService.java
@@ -16,19 +16,39 @@
 
 package android.webkit;
 
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
 import android.os.Handler;
 import android.webkit.DeviceOrientationManager;
 import java.lang.Runnable;
+import java.util.List;
 
 
-final class DeviceOrientationService {
+final class DeviceOrientationService implements SensorEventListener {
+    // The gravity vector expressed in the body frame.
+    private float[] mGravityVector;
+    // The geomagnetic vector expressed in the body frame.
+    private float[] mMagneticFieldVector;
+
     private DeviceOrientationManager mManager;
     private boolean mIsRunning;
     private Handler mHandler;
+    private SensorManager mSensorManager;
+    private Context mContext;
+    private Double mAlpha;
+    private Double mBeta;
+    private Double mGamma;
 
-    public DeviceOrientationService(DeviceOrientationManager manager) {
+    private static final double DELTA_DEGRESS = 1.0;
+
+    public DeviceOrientationService(DeviceOrientationManager manager, Context context) {
         mManager = manager;
         assert(mManager != null);
+        mContext = context;
+        assert(mContext != null);
      }
 
     public void start() {
@@ -55,9 +75,6 @@
 
     private void sendErrorEvent() {
         assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName());
-        if (mHandler == null) {
-            mHandler = new Handler();
-        }
         mHandler.post(new Runnable() {
             @Override
             public void run() {
@@ -70,12 +87,128 @@
     }
 
     private void registerForSensors() {
-        // Send the error event for now.
-        // FIXME: Implement.
-        sendErrorEvent();
+        if (mHandler == null) {
+            mHandler = new Handler();
+        }
+        if (!registerForAccelerometerSensor() || !registerForMagneticFieldSensor()) {
+            unregisterFromSensors();
+            sendErrorEvent();
+        }
+    }
+
+    private void getOrientationUsingGetRotationMatrix() {
+        if (mGravityVector == null || mMagneticFieldVector == null) {
+            return;
+        }
+
+        // Get the rotation matrix.
+        // The rotation matrix that transforms from the body frame to the earth frame.
+        float[] deviceRotationMatrix = new float[9];
+        if (!SensorManager.getRotationMatrix(
+                deviceRotationMatrix, null, mGravityVector, mMagneticFieldVector)) {
+            return;
+        }
+
+        // Convert rotation matrix to rotation angles.
+        // Assuming that the rotations are appied in the order listed at
+        // http://developer.android.com/reference/android/hardware/SensorEvent.html#values
+        // the rotations are applied about the same axes and in the same order as required by the
+        // API. The only conversions are sign changes as follows.
+        // The angles are in radians
+        float[] rotationAngles = new float[3];
+        SensorManager.getOrientation(deviceRotationMatrix, rotationAngles);
+        double alpha = Math.toDegrees(-rotationAngles[0]) - 90.0;
+        while (alpha < 0.0) { alpha += 360.0; } // [0, 360)
+        double beta = Math.toDegrees(-rotationAngles[1]);
+        while (beta < -180.0) { beta += 360.0; } // [-180, 180)
+        double gamma = Math.toDegrees(rotationAngles[2]);
+        while (gamma < -90.0) { gamma += 360.0; } // [-90, 90)
+
+        maybeSendChange(alpha, beta, gamma);
+    }
+
+    private SensorManager getSensorManager() {
+        assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName());
+        if (mSensorManager == null) {
+            mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
+        }
+        return mSensorManager;
+    }
+
+    private boolean registerForAccelerometerSensor() {
+        List<Sensor> sensors = getSensorManager().getSensorList(Sensor.TYPE_ACCELEROMETER);
+        if (sensors.isEmpty()) {
+            return false;
+        }
+        // TODO: Consider handling multiple sensors.
+        return getSensorManager().registerListener(
+                this, sensors.get(0), SensorManager.SENSOR_DELAY_FASTEST, mHandler);
+    }
+
+    private boolean registerForMagneticFieldSensor() {
+        List<Sensor> sensors = getSensorManager().getSensorList(Sensor.TYPE_MAGNETIC_FIELD);
+        if (sensors.isEmpty()) {
+            return false;
+        }
+        // TODO: Consider handling multiple sensors.
+        return getSensorManager().registerListener(
+                this, sensors.get(0), SensorManager.SENSOR_DELAY_FASTEST, mHandler);
     }
 
     private void unregisterFromSensors() {
-        // FIXME: Implement.
+        getSensorManager().unregisterListener(this);
+    }
+
+    private void maybeSendChange(double alpha, double beta, double gamma) {
+        assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName());
+        if (mAlpha == null || mBeta == null || mGamma == null
+                || Math.abs(alpha - mAlpha) > DELTA_DEGRESS
+                || Math.abs(beta - mBeta) > DELTA_DEGRESS
+                || Math.abs(gamma - mGamma) > DELTA_DEGRESS) {
+            mAlpha = alpha;
+            mBeta = beta;
+            mGamma = gamma;
+            mManager.onOrientationChange(mAlpha, mBeta, mGamma);
+        }
+    }
+
+    /**
+     * SensorEventListener implementation.
+     * Callbacks happen on the thread on which we registered - the WebCore thread.
+     */
+    public void onSensorChanged(SensorEvent event) {
+        assert(event.values.length == 3);
+        assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName());
+
+        if (!mIsRunning) {
+            return;
+        }
+
+        switch (event.sensor.getType()) {
+          case Sensor.TYPE_ACCELEROMETER:
+            if (mGravityVector == null) {
+                mGravityVector = new float[3];
+            }
+            mGravityVector[0] = event.values[0];
+            mGravityVector[1] = event.values[1];
+            mGravityVector[2] = event.values[2];
+            getOrientationUsingGetRotationMatrix();
+            break;
+          case Sensor.TYPE_MAGNETIC_FIELD:
+            if (mMagneticFieldVector == null) {
+                mMagneticFieldVector = new float[3];
+            }
+            mMagneticFieldVector[0] = event.values[0];
+            mMagneticFieldVector[1] = event.values[1];
+            mMagneticFieldVector[2] = event.values[2];
+            getOrientationUsingGetRotationMatrix();
+            break;
+          default:
+            assert(false);
+        }
+    }
+
+    public void onAccuracyChanged(Sensor sensor, int accuracy) {
+        assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName());
     }
 }
diff --git a/core/java/android/webkit/PluginManager.java b/core/java/android/webkit/PluginManager.java
index cdcb662..f7d1134 100644
--- a/core/java/android/webkit/PluginManager.java
+++ b/core/java/android/webkit/PluginManager.java
@@ -149,41 +149,11 @@
                     continue;
                 }
 
-                // check if the plugin has the required permissions
-                String permissions[] = pkgInfo.requestedPermissions;
-                if (permissions == null) {
+                // check if the plugin has the required permissions and
+                // signatures
+                if (!containsPluginPermissionAndSignatures(pkgInfo)) {
                     continue;
                 }
-                boolean permissionOk = false;
-                for (String permit : permissions) {
-                    if (PLUGIN_PERMISSION.equals(permit)) {
-                        permissionOk = true;
-                        break;
-                    }
-                }
-                if (!permissionOk) {
-                    continue;
-                }
-
-                // check to ensure the plugin is properly signed
-                Signature signatures[] = pkgInfo.signatures;
-                if (signatures == null) {
-                    continue;
-                }
-                if (SystemProperties.getBoolean("ro.secure", false)) {
-                    boolean signatureMatch = false;
-                    for (Signature signature : signatures) {
-                        for (int i = 0; i < SIGNATURES.length; i++) {
-                            if (SIGNATURES[i].equals(signature)) {
-                                signatureMatch = true;
-                                break;
-                            }
-                        }
-                    }
-                    if (!signatureMatch) {
-                        continue;
-                    }
-                }
 
                 // determine the type of plugin from the manifest
                 if (serviceInfo.metaData == null) {
@@ -226,6 +196,64 @@
     }
 
     /* package */
+    boolean containsPluginPermissionAndSignatures(String pluginAPKName) {
+        PackageManager pm = mContext.getPackageManager();
+
+        // retrieve information from the plugin's manifest
+        try {
+            PackageInfo pkgInfo = pm.getPackageInfo(pluginAPKName, PackageManager.GET_PERMISSIONS
+                    | PackageManager.GET_SIGNATURES);
+            if (pkgInfo != null) {
+                return containsPluginPermissionAndSignatures(pkgInfo);
+            }
+        } catch (NameNotFoundException e) {
+            Log.w(LOGTAG, "Can't find plugin: " + pluginAPKName);
+        }
+        return false;
+    }
+
+    private static boolean containsPluginPermissionAndSignatures(PackageInfo pkgInfo) {
+
+        // check if the plugin has the required permissions
+        String permissions[] = pkgInfo.requestedPermissions;
+        if (permissions == null) {
+            return false;
+        }
+        boolean permissionOk = false;
+        for (String permit : permissions) {
+            if (PLUGIN_PERMISSION.equals(permit)) {
+                permissionOk = true;
+                break;
+            }
+        }
+        if (!permissionOk) {
+            return false;
+        }
+
+        // check to ensure the plugin is properly signed
+        Signature signatures[] = pkgInfo.signatures;
+        if (signatures == null) {
+            return false;
+        }
+        if (SystemProperties.getBoolean("ro.secure", false)) {
+            boolean signatureMatch = false;
+            for (Signature signature : signatures) {
+                for (int i = 0; i < SIGNATURES.length; i++) {
+                    if (SIGNATURES[i].equals(signature)) {
+                        signatureMatch = true;
+                        break;
+                    }
+                }
+            }
+            if (!signatureMatch) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /* package */
     String getPluginsAPKName(String pluginLib) {
 
         // basic error checking on input params
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4823407..5d9ab90 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -18,10 +18,14 @@
 
 import android.annotation.Widget;
 import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
 import android.content.ClipboardManager;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.IntentFilter;
 import android.content.DialogInterface.OnCancelListener;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.content.Intent;
 import android.database.DataSetObserver;
 import android.graphics.Bitmap;
@@ -40,6 +44,7 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.net.http.SslCertificate;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -92,6 +97,7 @@
 import java.net.URLDecoder;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -877,6 +883,7 @@
          * such as the mZoomManager.
          */
         init();
+        setupPackageListener(context);
         updateMultiTouchSupport(context);
 
         if (privateBrowsing) {
@@ -884,6 +891,96 @@
         }
     }
 
+    /*
+     * The intent receiver that monitors for changes to relevant packages (e.g.,
+     * sGoogleApps) and notifies WebViewCore of their existence.
+     */
+    private static BroadcastReceiver sPackageInstallationReceiver = null;
+
+    /*
+     * A set of Google packages we monitor for the
+     * navigator.isApplicationInstalled() API. Add additional packages as
+     * needed.
+     */
+    private static Set<String> sGoogleApps;
+    static {
+        sGoogleApps = new HashSet<String>();
+        sGoogleApps.add("com.google.android.youtube");
+    }
+
+    private void setupPackageListener(Context context) {
+
+        /*
+         * we must synchronize the instance check and the creation of the
+         * receiver to ensure that only ONE receiver exists for all WebView
+         * instances.
+         */
+        synchronized (WebView.class) {
+
+            // if the receiver already exists then we do not need to register it
+            // again
+            if (sPackageInstallationReceiver != null) {
+                return;
+            }
+
+            IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+            filter.addDataScheme("package");
+            sPackageInstallationReceiver = new BroadcastReceiver() {
+
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    final String action = intent.getAction();
+                    final String packageName = intent.getData().getSchemeSpecificPart();
+                    final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+                    if (Intent.ACTION_PACKAGE_REMOVED.equals(action) && replacing) {
+                        // if it is replacing, refreshPlugins() when adding
+                        return;
+                    }
+
+                    if (sGoogleApps.contains(packageName)) {
+                        if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+                            mWebViewCore.sendMessage(EventHub.ADD_PACKAGE_NAME, packageName);
+                        } else {
+                            mWebViewCore.sendMessage(EventHub.REMOVE_PACKAGE_NAME, packageName);
+                        }
+                    }
+
+                    PluginManager pm = PluginManager.getInstance(context);
+                    if (pm.containsPluginPermissionAndSignatures(packageName)) {
+                        pm.refreshPlugins(Intent.ACTION_PACKAGE_ADDED.equals(action));
+                    }
+                }
+            };
+
+            context.getApplicationContext().registerReceiver(sPackageInstallationReceiver, filter);
+        }
+
+        // check if any of the monitored apps are already installed
+        AsyncTask<Void, Void, Set<String>> task = new AsyncTask<Void, Void, Set<String>>() {
+
+            @Override
+            protected Set<String> doInBackground(Void... unused) {
+                Set<String> installedPackages = new HashSet<String>();
+                PackageManager pm = mContext.getPackageManager();
+                List<PackageInfo> packages = pm.getInstalledPackages(0);
+                for (PackageInfo p : packages) {
+                    if (sGoogleApps.contains(p.packageName)) {
+                        installedPackages.add(p.packageName);
+                    }
+                }
+                return installedPackages;
+            }
+
+            // Executes on the UI thread
+            @Override
+            protected void onPostExecute(Set<String> installedPackages) {
+                mWebViewCore.sendMessage(EventHub.ADD_PACKAGE_NAMES, installedPackages);
+            }
+        };
+        task.execute();
+    }
+
     void updateMultiTouchSupport(Context context) {
         mZoomManager.updateMultiTouchSupport(context);
     }
@@ -3076,45 +3173,6 @@
         return (mWebViewCore != null) ? mWebViewCore.getSettings() : null;
     }
 
-    /**
-     * Use this method to inform the webview about packages that are installed
-     * in the system. This information will be used by the
-     * navigator.isApplicationInstalled() API.
-     * @param packageNames is a set of package names that are known to be
-     * installed in the system.
-     *
-     * @hide not a public API
-     */
-    public void addPackageNames(Set<String> packageNames) {
-        mWebViewCore.sendMessage(EventHub.ADD_PACKAGE_NAMES, packageNames);
-    }
-
-    /**
-     * Use this method to inform the webview about single packages that are
-     * installed in the system. This information will be used by the
-     * navigator.isApplicationInstalled() API.
-     * @param packageName is the name of a package that is known to be
-     * installed in the system.
-     *
-     * @hide not a public API
-     */
-    public void addPackageName(String packageName) {
-        mWebViewCore.sendMessage(EventHub.ADD_PACKAGE_NAME, packageName);
-    }
-
-    /**
-     * Use this method to inform the webview about packages that are uninstalled
-     * in the system. This information will be used by the
-     * navigator.isApplicationInstalled() API.
-     * @param packageName is the name of a package that has been uninstalled in
-     * the system.
-     *
-     * @hide not a public API
-     */
-    public void removePackageName(String packageName) {
-        mWebViewCore.sendMessage(EventHub.REMOVE_PACKAGE_NAME, packageName);
-    }
-
    /**
     * Return the list of currently loaded plugins.
     * @return The list of currently loaded plugins.
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 860edf2..fad4323 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -441,6 +441,8 @@
      */
     private native void nativeClearContent();
 
+    private native void nativeContentInvalidateAll();
+
     /**
      * Redraw a portion of the picture set. The Point wh returns the
      * width and height of the overall picture.
@@ -1880,10 +1882,10 @@
 
             synchronized (core) {
                 core.mDrawIsPaused = false;
-                if (core.mDrawIsScheduled) {
-                    core.mDrawIsScheduled = false;
-                    core.contentDraw();
-                }
+                // always redraw on resume to reenable gif animations
+                core.mDrawIsScheduled = false;
+                core.nativeContentInvalidateAll();
+                core.contentDraw();
             }
         }
     }
@@ -2504,7 +2506,8 @@
 
     protected DeviceOrientationService getDeviceOrientationService() {
         if (mDeviceOrientationService == null) {
-            mDeviceOrientationService = new DeviceOrientationService(mDeviceOrientationManager);
+            mDeviceOrientationService =
+                    new DeviceOrientationService(mDeviceOrientationManager, mContext);
         }
         return mDeviceOrientationService;
     }
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 0f52fc8..3a4487c 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -21,8 +21,9 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
-import android.graphics.Shader;
 import android.graphics.Rect;
+import android.graphics.Shader;
+import android.graphics.drawable.Animatable;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ClipDrawable;
@@ -30,11 +31,14 @@
 import android.graphics.drawable.LayerDrawable;
 import android.graphics.drawable.ShapeDrawable;
 import android.graphics.drawable.StateListDrawable;
-import android.graphics.drawable.Animatable;
 import android.graphics.drawable.shapes.RoundRectShape;
 import android.graphics.drawable.shapes.Shape;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.view.Gravity;
+import android.view.RemotableViewMethod;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.animation.AlphaAnimation;
@@ -44,9 +48,6 @@
 import android.view.animation.LinearInterpolator;
 import android.view.animation.Transformation;
 import android.widget.RemoteViews.RemoteView;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
 
 import com.android.internal.R;
 
@@ -763,6 +764,7 @@
     }
 
     @Override
+    @RemotableViewMethod
     public void setVisibility(int v) {
         if (getVisibility() != v) {
             super.setVisibility(v);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 98ef573..957d1dd 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -7599,7 +7599,7 @@
         /**
          * Update the controller's position.
          */
-        public void updatePosition(int offset);
+        public void updatePosition(int x, int y);
 
         /**
          * The controller and the cursor's positions can be link by a fixed offset,
@@ -7634,8 +7634,8 @@
         // Vertical extension of the touch region
         int mTopExtension, mBottomExtension;
         // Position of the virtual finger position on screen
-        int mHopSpotVertcalPosition;
-        
+        int mHotSpotVerticalPosition;
+
         Handle(Drawable drawable) {
             mDrawable = drawable;
         }
@@ -7647,8 +7647,7 @@
             final int lineTop = mLayout.getLineTop(line);
             final int lineBottom = mLayout.getLineBottom(line);
 
-            mHopSpotVertcalPosition = lineTop + (bottom ? (3 * (lineBottom - lineTop)) / 4 :
-                (lineBottom - lineTop) / 4);
+            mHotSpotVerticalPosition = lineTop;
 
             final Rect bounds = sCursorControllerTempRect;
             bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - drawableWidth / 2.0);
@@ -7668,7 +7667,7 @@
 
             int boundTopBefore = bounds.top;
             convertFromViewportToContentCoordinates(bounds);
-            mHopSpotVertcalPosition += bounds.top - boundTopBefore;
+            mHotSpotVerticalPosition += bounds.top - boundTopBefore;
             mDrawable.setBounds(bounds);
             postInvalidate();
         }
@@ -7719,7 +7718,7 @@
 
         public void show() {
             updateDrawablePosition();
-            // Has to be done after updatePosition, so that previous position invalidate
+            // Has to be done after updateDrawablePosition, so that previous position invalidate
             // in only done if necessary.
             mIsVisible = true;
         }
@@ -7756,12 +7755,14 @@
             }
         }
 
-        public void updatePosition(int offset) {
-            if (offset == getSelectionStart()) {
-                return; // No change, no need to redraw
+        public void updatePosition(int x, int y) {
+            final int previousOffset = getSelectionStart();
+            int offset = getHysteresisOffset(x, y, previousOffset);
+
+            if (offset != previousOffset) {
+                Selection.setSelection((Spannable) mText, offset);
+                updateDrawablePosition();
             }
-            Selection.setSelection((Spannable) mText, offset);
-            updateDrawablePosition();
         }
 
         private void updateDrawablePosition() {
@@ -7807,7 +7808,7 @@
 
                             final Rect bounds = mHandle.mDrawable.getBounds();
                             mOffsetX = (bounds.left + bounds.right) / 2.0f - x;
-                            mOffsetY = mHandle.mHopSpotVertcalPosition - y;
+                            mOffsetY = mHandle.mHotSpotVerticalPosition - y;
 
                             mOnDownTimerStart = event.getEventTime();
                         }
@@ -7862,7 +7863,7 @@
 
         public void show() {
             updateDrawablesPositions();
-            // Has to be done after updatePosition, so that previous position invalidate
+            // Has to be done after updateDrawablePositions, so that previous position invalidate
             // in only done if necessary.
             mIsVisible = true;
             mFadeOutTimerStart = -1;
@@ -7904,10 +7905,13 @@
             }
         }
 
-        public void updatePosition(int offset) {
+        public void updatePosition(int x, int y) {
             int selectionStart = getSelectionStart();
             int selectionEnd = getSelectionEnd();
 
+            final int previousOffset = mStartIsDragged ? selectionStart : selectionEnd;
+            int offset = getHysteresisOffset(x, y, previousOffset);
+
             // Handle the case where start and end are swapped, making sure start <= end
             if (mStartIsDragged) {
                 if (offset <= selectionEnd) {
@@ -7990,7 +7994,7 @@
                                     final Handle draggedHandle = mStartIsDragged ? mStartHandle : mEndHandle;
                                     final Rect bounds = draggedHandle.mDrawable.getBounds();
                                     mOffsetX = (bounds.left + bounds.right) / 2.0f - x;
-                                    mOffsetY = draggedHandle.mHopSpotVertcalPosition - y;
+                                    mOffsetY = draggedHandle.mHotSpotVerticalPosition - y;
 
                                     ((ArrowKeyMovementMethod)mMovement).setCursorController(this);
                                 }
@@ -8060,6 +8064,15 @@
         stopSelectionActionMode();
     }
 
+    private int getOffsetForHorizontal(int line, int x) {
+        x -= getTotalPaddingLeft();
+        // Clamp the position to inside of the view.
+        x = Math.max(0, x);
+        x = Math.min(getWidth() - getTotalPaddingRight() - 1, x);
+        x += getScrollX();
+        return getLayout().getOffsetForHorizontal(line, x);
+    }
+
     /**
      * Get the offset character closest to the specified absolute position.
      *
@@ -8071,32 +8084,44 @@
      * @hide
      */
     public int getOffset(int x, int y) {
-        x -= getTotalPaddingLeft();
+        if (getLayout() == null) return -1;
+
         y -= getTotalPaddingTop();
-
         // Clamp the position to inside of the view.
-        if (x < 0) {
-            x = 0;
-        } else if (x >= (getWidth() - getTotalPaddingRight())) {
-            x = getWidth()-getTotalPaddingRight() - 1;
-        }
-        if (y < 0) {
-            y = 0;
-        } else if (y >= (getHeight() - getTotalPaddingBottom())) {
-            y = getHeight()-getTotalPaddingBottom() - 1;
-        }
-
-        x += getScrollX();
+        y = Math.max(0, y);
+        y = Math.min(getHeight() - getTotalPaddingBottom() - 1, y);
         y += getScrollY();
 
-        Layout layout = getLayout();
-        if (layout != null) {
-            final int line = layout.getLineForVertical(y);
-            final int offset = layout.getOffsetForHorizontal(line, x);
-            return offset;
-        } else {
-            return -1;
+        final int line = getLayout().getLineForVertical(y);
+        final int offset = getOffsetForHorizontal(line, x);
+        return offset;
+    }
+
+    int getHysteresisOffset(int x, int y, int previousOffset) {
+        final Layout layout = getLayout();
+        if (layout == null) return -1;
+
+        y -= getTotalPaddingTop();
+        // Clamp the position to inside of the view.
+        y = Math.max(0, y);
+        y = Math.min(getHeight() - getTotalPaddingBottom() - 1, y);
+        y += getScrollY();
+
+        int line = getLayout().getLineForVertical(y);
+
+        final int previousLine = layout.getLineForOffset(previousOffset);
+        final int previousLineTop = layout.getLineTop(previousLine);
+        final int previousLineBottom = layout.getLineBottom(previousLine);
+        final int hysteresisThreshold = (previousLineBottom - previousLineTop) / 2;
+
+        // If new line is just before or after previous line and y position is less than
+        // hysteresisThreshold away from previous line, keep cursor on previous line.
+        if (((line == previousLine + 1) && ((y - previousLineBottom) < hysteresisThreshold)) ||
+            ((line == previousLine - 1) && ((previousLineTop - y)    < hysteresisThreshold))) {
+            line = previousLine;
         }
+
+        return getOffsetForHorizontal(line, x);
     }
 
 
diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java
index d1aff2a..e07c54f 100644
--- a/core/java/com/android/internal/app/ShutdownThread.java
+++ b/core/java/com/android/internal/app/ShutdownThread.java
@@ -134,7 +134,7 @@
     private static void beginShutdownSequence(Context context) {
         synchronized (sIsStartedGuard) {
             if (sIsStarted) {
-                Log.d(TAG, "Request to shutdown already running, returning.");
+                Log.d(TAG, "Shutdown sequence already running, returning.");
                 return;
             }
             sIsStarted = true;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index a70dbf6..0a1c8ff 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -3693,8 +3693,8 @@
                 mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
                 mDischargeCurrentLevel = level;
                 if (level < mDischargeUnplugLevel) {
-                    mLowDischargeAmountSinceCharge = mDischargeUnplugLevel-level-1;
-                    mHighDischargeAmountSinceCharge = mDischargeUnplugLevel-level;
+                    mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
+                    mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
                 }
                 doPlugLocked(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
             }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 0b62a67..90423be 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -19,6 +19,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.os.FileObserver;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -33,6 +34,7 @@
 import com.android.internal.telephony.ITelephony;
 import com.google.android.collect.Lists;
 
+import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.RandomAccessFile;
@@ -40,6 +42,7 @@
 import java.security.SecureRandom;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Utilities for the lock patten and its settings.
@@ -48,8 +51,9 @@
 
     private static final String TAG = "LockPatternUtils";
 
-    private static final String LOCK_PATTERN_FILE = "/system/gesture.key";
-    private static final String LOCK_PASSWORD_FILE = "/system/password.key";
+    private static final String SYSTEM_DIRECTORY = "/system/";
+    private static final String LOCK_PATTERN_FILE = "gesture.key";
+    private static final String LOCK_PASSWORD_FILE = "password.key";
 
     /**
      * The maximum number of incorrect attempts before the user is prevented
@@ -100,6 +104,10 @@
     private static String sLockPatternFilename;
     private static String sLockPasswordFilename;
 
+    private static final AtomicBoolean sHaveNonZeroPatternFile = new AtomicBoolean(false);
+    private static final AtomicBoolean sHaveNonZeroPasswordFile = new AtomicBoolean(false);
+    private static FileObserver sPasswordObserver;
+
     public DevicePolicyManager getDevicePolicyManager() {
         if (mDevicePolicyManager == null) {
             mDevicePolicyManager =
@@ -117,14 +125,31 @@
     public LockPatternUtils(Context context) {
         mContext = context;
         mContentResolver = context.getContentResolver();
-        // Initialize the location of gesture lock file
-        if (sLockPatternFilename == null) {
-            sLockPatternFilename = android.os.Environment.getDataDirectory()
-                    .getAbsolutePath() + LOCK_PATTERN_FILE;
-            sLockPasswordFilename = android.os.Environment.getDataDirectory()
-                    .getAbsolutePath() + LOCK_PASSWORD_FILE;
-        }
 
+        // Initialize the location of gesture & PIN lock files
+        if (sLockPatternFilename == null) {
+            String dataSystemDirectory =
+                    android.os.Environment.getDataDirectory().getAbsolutePath() +
+                    SYSTEM_DIRECTORY;
+            sLockPatternFilename =  dataSystemDirectory + LOCK_PATTERN_FILE;
+            sLockPasswordFilename = dataSystemDirectory + LOCK_PASSWORD_FILE;
+            sHaveNonZeroPatternFile.set(new File(sLockPatternFilename).length() > 0);
+            sHaveNonZeroPasswordFile.set(new File(sLockPasswordFilename).length() > 0);
+            int fileObserverMask = FileObserver.CLOSE_WRITE | FileObserver.DELETE |
+                    FileObserver.MOVED_TO | FileObserver.CREATE;
+            sPasswordObserver = new FileObserver(dataSystemDirectory, fileObserverMask) {
+                    public void onEvent(int event, String path) {
+                        if (LOCK_PATTERN_FILE.equals(path)) {
+                            Log.d(TAG, "lock pattern file changed");
+                            sHaveNonZeroPatternFile.set(new File(sLockPatternFilename).length() > 0);
+                        } else if (LOCK_PASSWORD_FILE.equals(path)) {
+                            Log.d(TAG, "lock password file changed");
+                            sHaveNonZeroPasswordFile.set(new File(sLockPasswordFilename).length() > 0);
+                        }
+                    }
+                };
+            sPasswordObserver.startWatching();
+        }
     }
 
     public int getRequestedMinimumPasswordLength() {
@@ -258,32 +283,11 @@
     }
 
     /**
-     * Checks to see if the given file exists and contains any data. Returns
-     * true if it does, false otherwise.
-     *
-     * @param filename
-     * @return true if file exists and is non-empty.
-     */
-    private boolean nonEmptyFileExists(String filename) {
-        try {
-            // Check if we can read a byte from the file
-            RandomAccessFile raf = new RandomAccessFile(filename, "r");
-            raf.readByte();
-            raf.close();
-            return true;
-        } catch (FileNotFoundException fnfe) {
-            return false;
-        } catch (IOException ioe) {
-            return false;
-        }
-    }
-
-    /**
      * Check to see if the user has stored a lock pattern.
      * @return Whether a saved pattern exists.
      */
     public boolean savedPatternExists() {
-        return nonEmptyFileExists(sLockPatternFilename);
+        return sHaveNonZeroPatternFile.get();
     }
 
     /**
@@ -291,7 +295,7 @@
      * @return Whether a saved pattern exists.
      */
     public boolean savedPasswordExists() {
-        return nonEmptyFileExists(sLockPasswordFilename);
+        return sHaveNonZeroPasswordFile.get();
     }
 
     /**
diff --git a/core/res/res/drawable-hdpi/btn_check_label_background_light.9.png b/core/res/res/drawable-hdpi/btn_check_label_background_light.9.png
deleted file mode 100644
index 97e6806..0000000
--- a/core/res/res/drawable-hdpi/btn_check_label_background_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off.png b/core/res/res/drawable-hdpi/btn_check_off.png
index 911e1aa..aad9ef7 100644
--- a/core/res/res/drawable-hdpi/btn_check_off.png
+++ b/core/res/res/drawable-hdpi/btn_check_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_disable.png b/core/res/res/drawable-hdpi/btn_check_off_disable.png
index d72e2b9..eaee9e0 100644
--- a/core/res/res/drawable-hdpi/btn_check_off_disable.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_disable.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_disable_focused.png b/core/res/res/drawable-hdpi/btn_check_off_disable_focused.png
index d72e2b9..6d2c293 100644
--- a/core/res/res/drawable-hdpi/btn_check_off_disable_focused.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_disable_focused_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_off_disable_focused_holo_dark.png
new file mode 100644
index 0000000..d72e2b9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_disable_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_disable_focused_light.png b/core/res/res/drawable-hdpi/btn_check_off_disable_focused_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_off_disable_focused_light.png
rename to core/res/res/drawable-hdpi/btn_check_off_disable_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_disable_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_off_disable_holo_dark.png
new file mode 100644
index 0000000..d72e2b9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_disable_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_disable_light.png b/core/res/res/drawable-hdpi/btn_check_off_disable_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_off_disable_light.png
rename to core/res/res/drawable-hdpi/btn_check_off_disable_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_off_holo_dark.png
new file mode 100644
index 0000000..911e1aa
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_light.png b/core/res/res/drawable-hdpi/btn_check_off_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_off_light.png
rename to core/res/res/drawable-hdpi/btn_check_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_pressed.png b/core/res/res/drawable-hdpi/btn_check_off_pressed.png
index 08f41812..1c442e9 100644
--- a/core/res/res/drawable-hdpi/btn_check_off_pressed.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png
new file mode 100644
index 0000000..08f41812
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_pressed_light.png b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_off_pressed_light.png
rename to core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_selected.png b/core/res/res/drawable-hdpi/btn_check_off_selected.png
index 264f102..b852b2c 100644
--- a/core/res/res/drawable-hdpi/btn_check_off_selected.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_selected_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_off_selected_holo_dark.png
new file mode 100644
index 0000000..264f102
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_off_selected_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_selected_light.png b/core/res/res/drawable-hdpi/btn_check_off_selected_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_off_selected_light.png
rename to core/res/res/drawable-hdpi/btn_check_off_selected_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on.png b/core/res/res/drawable-hdpi/btn_check_on.png
index 5541c67..cd5c181 100644
--- a/core/res/res/drawable-hdpi/btn_check_on.png
+++ b/core/res/res/drawable-hdpi/btn_check_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_disable.png b/core/res/res/drawable-hdpi/btn_check_on_disable.png
index 7805458..b4fc51a 100644
--- a/core/res/res/drawable-hdpi/btn_check_on_disable.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_disable.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_disable_focused.png b/core/res/res/drawable-hdpi/btn_check_on_disable_focused.png
index 7805458..bf34647 100644
--- a/core/res/res/drawable-hdpi/btn_check_on_disable_focused.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_disable_focused_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_on_disable_focused_holo_dark.png
new file mode 100644
index 0000000..7805458
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_disable_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_disable_focused_light.png b/core/res/res/drawable-hdpi/btn_check_on_disable_focused_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_on_disable_focused_light.png
rename to core/res/res/drawable-hdpi/btn_check_on_disable_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_disable_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_on_disable_holo_dark.png
new file mode 100644
index 0000000..7805458
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_disable_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_disable_light.png b/core/res/res/drawable-hdpi/btn_check_on_disable_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_on_disable_light.png
rename to core/res/res/drawable-hdpi/btn_check_on_disable_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_on_holo_dark.png
new file mode 100644
index 0000000..5541c67
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_light.png b/core/res/res/drawable-hdpi/btn_check_on_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_on_light.png
rename to core/res/res/drawable-hdpi/btn_check_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_pressed.png b/core/res/res/drawable-hdpi/btn_check_on_pressed.png
index 37e3953..fa5c7a2 100644
--- a/core/res/res/drawable-hdpi/btn_check_on_pressed.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png
new file mode 100644
index 0000000..37e3953
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_pressed_light.png b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_on_pressed_light.png
rename to core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_selected.png b/core/res/res/drawable-hdpi/btn_check_on_selected.png
index a0beac4..a6a21ad 100644
--- a/core/res/res/drawable-hdpi/btn_check_on_selected.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_selected_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_on_selected_holo_dark.png
new file mode 100644
index 0000000..a0beac4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_on_selected_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_selected_light.png b/core/res/res/drawable-hdpi/btn_check_on_selected_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_on_selected_light.png
rename to core/res/res/drawable-hdpi/btn_check_on_selected_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_label_background_light.9.png b/core/res/res/drawable-hdpi/btn_radio_label_background_light.9.png
deleted file mode 100644
index 45c5c6a..0000000
--- a/core/res/res/drawable-hdpi/btn_radio_label_background_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off.png b/core/res/res/drawable-hdpi/btn_radio_off.png
index 301c97d..c0b14aa 100644
--- a/core/res/res/drawable-hdpi/btn_radio_off.png
+++ b/core/res/res/drawable-hdpi/btn_radio_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_off_holo_dark.png
new file mode 100644
index 0000000..301c97d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_light.png b/core/res/res/drawable-hdpi/btn_radio_off_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_off_light.png
rename to core/res/res/drawable-hdpi/btn_radio_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_pressed.png b/core/res/res/drawable-hdpi/btn_radio_off_pressed.png
index 5e6ef2b..3189581 100644
--- a/core/res/res/drawable-hdpi/btn_radio_off_pressed.png
+++ b/core/res/res/drawable-hdpi/btn_radio_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png
new file mode 100644
index 0000000..5e6ef2b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_pressed_light.png b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_off_pressed_light.png
rename to core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_selected.png b/core/res/res/drawable-hdpi/btn_radio_off_selected.png
index d11ae85..f337703 100644
--- a/core/res/res/drawable-hdpi/btn_radio_off_selected.png
+++ b/core/res/res/drawable-hdpi/btn_radio_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_selected_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_off_selected_holo_dark.png
new file mode 100644
index 0000000..d11ae85
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_off_selected_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_selected_light.png b/core/res/res/drawable-hdpi/btn_radio_off_selected_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_off_selected_light.png
rename to core/res/res/drawable-hdpi/btn_radio_off_selected_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on.png b/core/res/res/drawable-hdpi/btn_radio_on.png
index 5b0dbe8..c90d2eb 100644
--- a/core/res/res/drawable-hdpi/btn_radio_on.png
+++ b/core/res/res/drawable-hdpi/btn_radio_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_on_holo_dark.png
new file mode 100644
index 0000000..5b0dbe8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_light.png b/core/res/res/drawable-hdpi/btn_radio_on_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_on_light.png
rename to core/res/res/drawable-hdpi/btn_radio_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_pressed.png b/core/res/res/drawable-hdpi/btn_radio_on_pressed.png
index c3a0d48..d79450b8 100644
--- a/core/res/res/drawable-hdpi/btn_radio_on_pressed.png
+++ b/core/res/res/drawable-hdpi/btn_radio_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png
new file mode 100644
index 0000000..c3a0d48
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_pressed_light.png b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_on_pressed_light.png
rename to core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_selected.png b/core/res/res/drawable-hdpi/btn_radio_on_selected.png
index 6c05f47..db50c43 100644
--- a/core/res/res/drawable-hdpi/btn_radio_on_selected.png
+++ b/core/res/res/drawable-hdpi/btn_radio_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_selected_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_on_selected_holo_dark.png
new file mode 100644
index 0000000..6c05f47
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_on_selected_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_selected_light.png b/core/res/res/drawable-hdpi/btn_radio_on_selected_holo_light.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_on_selected_light.png
rename to core/res/res/drawable-hdpi/btn_radio_on_selected_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_label_background_light.9.png b/core/res/res/drawable-mdpi/btn_check_label_background_light.9.png
deleted file mode 100644
index 79367b8..0000000
--- a/core/res/res/drawable-mdpi/btn_check_label_background_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off.png b/core/res/res/drawable-mdpi/btn_check_off.png
index 5e44c29..56d3861 100644
--- a/core/res/res/drawable-mdpi/btn_check_off.png
+++ b/core/res/res/drawable-mdpi/btn_check_off.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_disable.png b/core/res/res/drawable-mdpi/btn_check_off_disable.png
index a603fb1..e012afd 100644
--- a/core/res/res/drawable-mdpi/btn_check_off_disable.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_disable.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_disable_focused.png b/core/res/res/drawable-mdpi/btn_check_off_disable_focused.png
index a603fb1..0837bbd 100644
--- a/core/res/res/drawable-mdpi/btn_check_off_disable_focused.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_disable_focused_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_off_disable_focused_holo_dark.png
new file mode 100644
index 0000000..a603fb1
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_disable_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_disable_focused_light.png b/core/res/res/drawable-mdpi/btn_check_off_disable_focused_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_off_disable_focused_light.png
rename to core/res/res/drawable-mdpi/btn_check_off_disable_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_disable_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_off_disable_holo_dark.png
new file mode 100644
index 0000000..a603fb1
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_disable_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_disable_light.png b/core/res/res/drawable-mdpi/btn_check_off_disable_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_off_disable_light.png
rename to core/res/res/drawable-mdpi/btn_check_off_disable_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_off_holo_dark.png
new file mode 100644
index 0000000..5e44c29
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_light.png b/core/res/res/drawable-mdpi/btn_check_off_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_off_light.png
rename to core/res/res/drawable-mdpi/btn_check_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_pressed.png b/core/res/res/drawable-mdpi/btn_check_off_pressed.png
index 611bb1d..984dfd7 100644
--- a/core/res/res/drawable-mdpi/btn_check_off_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png
new file mode 100644
index 0000000..611bb1d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_pressed_light.png b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_off_pressed_light.png
rename to core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_selected.png b/core/res/res/drawable-mdpi/btn_check_off_selected.png
index aa28df2..20842d4 100644
--- a/core/res/res/drawable-mdpi/btn_check_off_selected.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_selected_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_off_selected_holo_dark.png
new file mode 100644
index 0000000..aa28df2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_off_selected_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_selected_light.png b/core/res/res/drawable-mdpi/btn_check_off_selected_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_off_selected_light.png
rename to core/res/res/drawable-mdpi/btn_check_off_selected_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on.png b/core/res/res/drawable-mdpi/btn_check_on.png
index 130d562..791ac1d 100644
--- a/core/res/res/drawable-mdpi/btn_check_on.png
+++ b/core/res/res/drawable-mdpi/btn_check_on.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_disable.png b/core/res/res/drawable-mdpi/btn_check_on_disable.png
index f19972a..6cb02f3 100644
--- a/core/res/res/drawable-mdpi/btn_check_on_disable.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_disable.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_disable_focused.png b/core/res/res/drawable-mdpi/btn_check_on_disable_focused.png
index f19972a..8a73b33 100644
--- a/core/res/res/drawable-mdpi/btn_check_on_disable_focused.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_disable_focused_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_on_disable_focused_holo_dark.png
new file mode 100644
index 0000000..f19972a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_disable_focused_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_disable_focused_light.png b/core/res/res/drawable-mdpi/btn_check_on_disable_focused_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_on_disable_focused_light.png
rename to core/res/res/drawable-mdpi/btn_check_on_disable_focused_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_disable_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_on_disable_holo_dark.png
new file mode 100644
index 0000000..f19972a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_disable_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_disable_light.png b/core/res/res/drawable-mdpi/btn_check_on_disable_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_on_disable_light.png
rename to core/res/res/drawable-mdpi/btn_check_on_disable_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_on_holo_dark.png
new file mode 100644
index 0000000..130d562
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_light.png b/core/res/res/drawable-mdpi/btn_check_on_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_on_light.png
rename to core/res/res/drawable-mdpi/btn_check_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_pressed.png b/core/res/res/drawable-mdpi/btn_check_on_pressed.png
index df753f5..300d64a 100644
--- a/core/res/res/drawable-mdpi/btn_check_on_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png
new file mode 100644
index 0000000..df753f5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_pressed_light.png b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_on_pressed_light.png
rename to core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_selected.png b/core/res/res/drawable-mdpi/btn_check_on_selected.png
index 7586881..0b36adb 100644
--- a/core/res/res/drawable-mdpi/btn_check_on_selected.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_selected_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_on_selected_holo_dark.png
new file mode 100644
index 0000000..7586881
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_on_selected_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_selected_light.png b/core/res/res/drawable-mdpi/btn_check_on_selected_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_on_selected_light.png
rename to core/res/res/drawable-mdpi/btn_check_on_selected_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_label_background_light.9.png b/core/res/res/drawable-mdpi/btn_radio_label_background_light.9.png
deleted file mode 100644
index 16e8939..0000000
--- a/core/res/res/drawable-mdpi/btn_radio_label_background_light.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off.png b/core/res/res/drawable-mdpi/btn_radio_off.png
index 16c1c6b..407632b 100644
--- a/core/res/res/drawable-mdpi/btn_radio_off.png
+++ b/core/res/res/drawable-mdpi/btn_radio_off.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_off_holo_dark.png
new file mode 100644
index 0000000..16c1c6b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_light.png b/core/res/res/drawable-mdpi/btn_radio_off_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_off_light.png
rename to core/res/res/drawable-mdpi/btn_radio_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_pressed.png b/core/res/res/drawable-mdpi/btn_radio_off_pressed.png
index b25217b..d6d8a9d 100644
--- a/core/res/res/drawable-mdpi/btn_radio_off_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_radio_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png
new file mode 100644
index 0000000..b25217b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_pressed_light.png b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_off_pressed_light.png
rename to core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_selected.png b/core/res/res/drawable-mdpi/btn_radio_off_selected.png
index bef7572..53f3e87 100644
--- a/core/res/res/drawable-mdpi/btn_radio_off_selected.png
+++ b/core/res/res/drawable-mdpi/btn_radio_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_selected_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_off_selected_holo_dark.png
new file mode 100644
index 0000000..bef7572
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_off_selected_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_selected_light.png b/core/res/res/drawable-mdpi/btn_radio_off_selected_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_off_selected_light.png
rename to core/res/res/drawable-mdpi/btn_radio_off_selected_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on.png b/core/res/res/drawable-mdpi/btn_radio_on.png
index 4ed7471..25a3ccc 100644
--- a/core/res/res/drawable-mdpi/btn_radio_on.png
+++ b/core/res/res/drawable-mdpi/btn_radio_on.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_on_holo_dark.png
new file mode 100644
index 0000000..4ed7471
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_light.png b/core/res/res/drawable-mdpi/btn_radio_on_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_on_light.png
rename to core/res/res/drawable-mdpi/btn_radio_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_pressed.png b/core/res/res/drawable-mdpi/btn_radio_on_pressed.png
index 7cf91c6..c904a35 100644
--- a/core/res/res/drawable-mdpi/btn_radio_on_pressed.png
+++ b/core/res/res/drawable-mdpi/btn_radio_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png
new file mode 100644
index 0000000..7cf91c6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_pressed_light.png b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_on_pressed_light.png
rename to core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_selected.png b/core/res/res/drawable-mdpi/btn_radio_on_selected.png
index 56f6f5b..78e1fc0 100644
--- a/core/res/res/drawable-mdpi/btn_radio_on_selected.png
+++ b/core/res/res/drawable-mdpi/btn_radio_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_selected_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_on_selected_holo_dark.png
new file mode 100644
index 0000000..56f6f5b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_on_selected_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_selected_light.png b/core/res/res/drawable-mdpi/btn_radio_on_selected_holo_light.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_on_selected_light.png
rename to core/res/res/drawable-mdpi/btn_radio_on_selected_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_light.xml b/core/res/res/drawable/btn_check_holo_dark.xml
similarity index 72%
copy from core/res/res/drawable/btn_check_light.xml
copy to core/res/res/drawable/btn_check_holo_dark.xml
index 85f119a..fd85d72 100644
--- a/core/res/res/drawable/btn_check_light.xml
+++ b/core/res/res/drawable/btn_check_holo_dark.xml
@@ -17,49 +17,49 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
     <!-- Enabled states -->
-
+        
     <item android:state_checked="true" android:state_window_focused="false"
           android:state_enabled="true"
-          android:drawable="@drawable/btn_check_on_light" />
+          android:drawable="@drawable/btn_check_on_holo_dark" />
     <item android:state_checked="false" android:state_window_focused="false"
           android:state_enabled="true"
-          android:drawable="@drawable/btn_check_off_light" />
+          android:drawable="@drawable/btn_check_off_holo_dark" />
 
     <item android:state_checked="true" android:state_pressed="true"
           android:state_enabled="true"
-          android:drawable="@drawable/btn_check_on_pressed_light" />
+          android:drawable="@drawable/btn_check_on_pressed_holo_dark" />
     <item android:state_checked="false" android:state_pressed="true"
           android:state_enabled="true"
-          android:drawable="@drawable/btn_check_off_pressed_light" />
+          android:drawable="@drawable/btn_check_off_pressed_holo_dark" />
 
     <item android:state_checked="true" android:state_focused="true"
           android:state_enabled="true"
-          android:drawable="@drawable/btn_check_on_selected_light" />
+          android:drawable="@drawable/btn_check_on_selected_holo_dark" />
     <item android:state_checked="false" android:state_focused="true"
           android:state_enabled="true"
-          android:drawable="@drawable/btn_check_off_selected_light" />
+          android:drawable="@drawable/btn_check_off_selected_holo_dark" />
 
     <item android:state_checked="false"
           android:state_enabled="true"
-          android:drawable="@drawable/btn_check_off_light" />
+          android:drawable="@drawable/btn_check_off_holo_dark" />
     <item android:state_checked="true"
           android:state_enabled="true"
-          android:drawable="@drawable/btn_check_on_light" />
+          android:drawable="@drawable/btn_check_on_holo_dark" />
 
 
     <!-- Disabled states -->
 
     <item android:state_checked="true" android:state_window_focused="false"
-          android:drawable="@drawable/btn_check_on_disable_light" />
+          android:drawable="@drawable/btn_check_on_disable_holo_dark" />
     <item android:state_checked="false" android:state_window_focused="false"
-          android:drawable="@drawable/btn_check_off_disable_light" />
+          android:drawable="@drawable/btn_check_off_disable_holo_dark" />
 
     <item android:state_checked="true" android:state_focused="true"
-          android:drawable="@drawable/btn_check_on_disable_focused_light" />
+          android:drawable="@drawable/btn_check_on_disable_focused_holo_dark" />
     <item android:state_checked="false" android:state_focused="true"
-          android:drawable="@drawable/btn_check_off_disable_focused_light" />
+          android:drawable="@drawable/btn_check_off_disable_focused_holo_dark" />
 
-    <item android:state_checked="false" android:drawable="@drawable/btn_check_off_disable_light" />
-    <item android:state_checked="true" android:drawable="@drawable/btn_check_on_disable_light" />
+    <item android:state_checked="false" android:drawable="@drawable/btn_check_off_disable_holo_dark" />
+    <item android:state_checked="true" android:drawable="@drawable/btn_check_on_disable_holo_dark" />
 
 </selector>
diff --git a/core/res/res/drawable/btn_check_light.xml b/core/res/res/drawable/btn_check_holo_light.xml
similarity index 72%
rename from core/res/res/drawable/btn_check_light.xml
rename to core/res/res/drawable/btn_check_holo_light.xml
index 85f119a..4fb16fa 100644
--- a/core/res/res/drawable/btn_check_light.xml
+++ b/core/res/res/drawable/btn_check_holo_light.xml
@@ -17,49 +17,49 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
     <!-- Enabled states -->
-
+        
     <item android:state_checked="true" android:state_window_focused="false"
           android:state_enabled="true"
-          android:drawable="@drawable/btn_check_on_light" />
+          android:drawable="@drawable/btn_check_on_holo_light" />
     <item android:state_checked="false" android:state_window_focused="false"
           android:state_enabled="true"
-          android:drawable="@drawable/btn_check_off_light" />
+          android:drawable="@drawable/btn_check_off_holo_light" />
 
     <item android:state_checked="true" android:state_pressed="true"
           android:state_enabled="true"
-          android:drawable="@drawable/btn_check_on_pressed_light" />
+          android:drawable="@drawable/btn_check_on_pressed_holo_light" />
     <item android:state_checked="false" android:state_pressed="true"
           android:state_enabled="true"
-          android:drawable="@drawable/btn_check_off_pressed_light" />
+          android:drawable="@drawable/btn_check_off_pressed_holo_light" />
 
     <item android:state_checked="true" android:state_focused="true"
           android:state_enabled="true"
-          android:drawable="@drawable/btn_check_on_selected_light" />
+          android:drawable="@drawable/btn_check_on_selected_holo_light" />
     <item android:state_checked="false" android:state_focused="true"
           android:state_enabled="true"
-          android:drawable="@drawable/btn_check_off_selected_light" />
+          android:drawable="@drawable/btn_check_off_selected_holo_light" />
 
     <item android:state_checked="false"
           android:state_enabled="true"
-          android:drawable="@drawable/btn_check_off_light" />
+          android:drawable="@drawable/btn_check_off_holo_light" />
     <item android:state_checked="true"
           android:state_enabled="true"
-          android:drawable="@drawable/btn_check_on_light" />
+          android:drawable="@drawable/btn_check_on_holo_light" />
 
 
     <!-- Disabled states -->
 
     <item android:state_checked="true" android:state_window_focused="false"
-          android:drawable="@drawable/btn_check_on_disable_light" />
+          android:drawable="@drawable/btn_check_on_disable_holo_light" />
     <item android:state_checked="false" android:state_window_focused="false"
-          android:drawable="@drawable/btn_check_off_disable_light" />
+          android:drawable="@drawable/btn_check_off_disable_holo_light" />
 
     <item android:state_checked="true" android:state_focused="true"
-          android:drawable="@drawable/btn_check_on_disable_focused_light" />
+          android:drawable="@drawable/btn_check_on_disable_focused_holo_light" />
     <item android:state_checked="false" android:state_focused="true"
-          android:drawable="@drawable/btn_check_off_disable_focused_light" />
+          android:drawable="@drawable/btn_check_off_disable_focused_holo_light" />
 
-    <item android:state_checked="false" android:drawable="@drawable/btn_check_off_disable_light" />
-    <item android:state_checked="true" android:drawable="@drawable/btn_check_on_disable_light" />
+    <item android:state_checked="false" android:drawable="@drawable/btn_check_off_disable_holo_light" />
+    <item android:state_checked="true" android:drawable="@drawable/btn_check_on_disable_holo_light" />
 
 </selector>
diff --git a/core/res/res/drawable/btn_radio_light.xml b/core/res/res/drawable/btn_radio_holo_dark.xml
similarity index 72%
copy from core/res/res/drawable/btn_radio_light.xml
copy to core/res/res/drawable/btn_radio_holo_dark.xml
index 51c930b..8984f6d 100644
--- a/core/res/res/drawable/btn_radio_light.xml
+++ b/core/res/res/drawable/btn_radio_holo_dark.xml
@@ -16,20 +16,20 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_checked="true" android:state_window_focused="false"
-          android:drawable="@drawable/btn_radio_on_light" />
+          android:drawable="@drawable/btn_radio_on_holo_dark" />
     <item android:state_checked="false" android:state_window_focused="false"
-          android:drawable="@drawable/btn_radio_off_light" />
-
+          android:drawable="@drawable/btn_radio_off_holo_dark" />
+          
     <item android:state_checked="true" android:state_pressed="true"
-          android:drawable="@drawable/btn_radio_on_pressed_light" />
+          android:drawable="@drawable/btn_radio_on_pressed_holo_dark" />
     <item android:state_checked="false" android:state_pressed="true"
-          android:drawable="@drawable/btn_radio_off_pressed_light" />
+          android:drawable="@drawable/btn_radio_off_pressed_holo_dark" />
 
     <item android:state_checked="true" android:state_focused="true"
-          android:drawable="@drawable/btn_radio_on_selected_light" />
+          android:drawable="@drawable/btn_radio_on_selected_holo_dark" />
     <item android:state_checked="false" android:state_focused="true"
-          android:drawable="@drawable/btn_radio_off_selected_light" />
+          android:drawable="@drawable/btn_radio_off_selected_holo_dark" />
 
-    <item android:state_checked="false" android:drawable="@drawable/btn_radio_off_light" />
-    <item android:state_checked="true" android:drawable="@drawable/btn_radio_on_light" />
+    <item android:state_checked="false" android:drawable="@drawable/btn_radio_off_holo_dark" />
+    <item android:state_checked="true" android:drawable="@drawable/btn_radio_on_holo_dark" />
 </selector>
diff --git a/core/res/res/drawable/btn_radio_light.xml b/core/res/res/drawable/btn_radio_holo_light.xml
similarity index 72%
rename from core/res/res/drawable/btn_radio_light.xml
rename to core/res/res/drawable/btn_radio_holo_light.xml
index 51c930b..001508c 100644
--- a/core/res/res/drawable/btn_radio_light.xml
+++ b/core/res/res/drawable/btn_radio_holo_light.xml
@@ -16,20 +16,20 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_checked="true" android:state_window_focused="false"
-          android:drawable="@drawable/btn_radio_on_light" />
+          android:drawable="@drawable/btn_radio_on_holo_light" />
     <item android:state_checked="false" android:state_window_focused="false"
-          android:drawable="@drawable/btn_radio_off_light" />
-
+          android:drawable="@drawable/btn_radio_off_holo_light" />
+          
     <item android:state_checked="true" android:state_pressed="true"
-          android:drawable="@drawable/btn_radio_on_pressed_light" />
+          android:drawable="@drawable/btn_radio_on_pressed_holo_light" />
     <item android:state_checked="false" android:state_pressed="true"
-          android:drawable="@drawable/btn_radio_off_pressed_light" />
+          android:drawable="@drawable/btn_radio_off_pressed_holo_light" />
 
     <item android:state_checked="true" android:state_focused="true"
-          android:drawable="@drawable/btn_radio_on_selected_light" />
+          android:drawable="@drawable/btn_radio_on_selected_holo_light" />
     <item android:state_checked="false" android:state_focused="true"
-          android:drawable="@drawable/btn_radio_off_selected_light" />
+          android:drawable="@drawable/btn_radio_off_selected_holo_light" />
 
-    <item android:state_checked="false" android:drawable="@drawable/btn_radio_off_light" />
-    <item android:state_checked="true" android:drawable="@drawable/btn_radio_on_light" />
+    <item android:state_checked="false" android:drawable="@drawable/btn_radio_off_holo_light" />
+    <item android:state_checked="true" android:drawable="@drawable/btn_radio_on_holo_light" />
 </selector>
diff --git a/core/res/res/layout/select_dialog_multichoice.xml b/core/res/res/layout/select_dialog_multichoice.xml
index 5785d3b..b646a4c 100644
--- a/core/res/res/layout/select_dialog_multichoice.xml
+++ b/core/res/res/layout/select_dialog_multichoice.xml
@@ -24,7 +24,7 @@
     android:gravity="center_vertical"
     android:paddingLeft="12dip"
     android:paddingRight="7dip"
-    android:checkMark="@android:drawable/btn_check"
+    android:checkMark="?android:attr/listChoiceIndicatorMultiple"
     android:ellipsize="marquee"
 />
 
diff --git a/core/res/res/layout/select_dialog_singlechoice.xml b/core/res/res/layout/select_dialog_singlechoice.xml
index 3560fee..c3c2073 100644
--- a/core/res/res/layout/select_dialog_singlechoice.xml
+++ b/core/res/res/layout/select_dialog_singlechoice.xml
@@ -24,6 +24,6 @@
     android:gravity="center_vertical"
     android:paddingLeft="12dip"
     android:paddingRight="7dip"
-    android:checkMark="@android:drawable/btn_radio"
+    android:checkMark="?android:attr/listChoiceIndicatorSingle"
     android:ellipsize="marquee"
 />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index ea5c158..a3367e3 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1347,18 +1347,12 @@
        the base class. -->
   <public type="layout" name="list_content" />
 
-  <!-- A dark holographic theme. -->
   <public type="style" name="Theme.Holo" />
-  <!-- A light holographic theme. -->
   <public type="style" name="Theme.Light.Holo" />
-  <!-- Variant of the holographic (dark) theme with no title bar -->
-  <public type="style" name="Theme.Holo.NoTitleBar" />
-  <!-- Variant of the holographic (dark) theme that has no title bar and fills the entire screen -->
-  <public type="style" name="Theme.Holo.NoTitleBar.Fullscreen" />
-  <!-- Variant of the holographic light theme with no title bar -->
-  <public type="style" name="Theme.Light.Holo.NoTitleBar" />
-  <!-- Variant of the holographic light theme that has no title bar and fills the entire screen -->
-  <public type="style" name="Theme.Light.Holo.NoTitleBar.Fullscreen" />
+  <public type="style" name="Theme.Holo.NoActionBar" />
+  <public type="style" name="Theme.Holo.NoActionBar.Fullscreen" />
+  <public type="style" name="Theme.Light.Holo.NoActionBar" />
+  <public type="style" name="Theme.Light.Holo.NoActionBar.Fullscreen" />
 
   <public type="string" name="selectTextMode" id="0x01040030" />
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 37b66d3..840cb10 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -280,22 +280,12 @@
 
     <style name="Widget.CompoundButton.CheckBox">
         <item name="android:background">@android:drawable/btn_check_label_background</item>
-        <item name="android:button">@android:drawable/btn_check</item>
-    </style>
-
-    <style name="Widget.CompoundButton.CheckBox.Inverse">
-        <item name="android:background">@android:drawable/btn_check_label_background_light</item>
-        <item name="android:button">@android:drawable/btn_check_light</item>
+        <item name="android:button">?android:attr/listChoiceIndicatorMultiple</item>
     </style>
 
     <style name="Widget.CompoundButton.RadioButton">
         <item name="android:background">@android:drawable/btn_radio_label_background</item>
-        <item name="android:button">@android:drawable/btn_radio</item>
-    </style>
-
-    <style name="Widget.CompoundButton.RadioButton.Inverse">
-        <item name="android:background">@android:drawable/btn_radio_label_background_light</item>
-        <item name="android:button">@android:drawable/btn_radio_light</item>
+        <item name="android:button">?android:attr/listChoiceIndicatorSingle</item>
     </style>
 
     <style name="Widget.CompoundButton.Star">
@@ -503,7 +493,7 @@
     </style>
     
     <style name="Widget.DropDownItem.Spinner">
-        <item name="android:checkMark">@android:drawable/btn_radio</item>
+        <item name="android:checkMark">?android:attr/listChoiceIndicatorSingle</item>
     </style>
 
     <style name="Widget.ScrollView">
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index c78705b..75f94e8 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -92,7 +92,7 @@
         <item name="listDivider">@drawable/divider_horizontal_dark</item>
         <item name="listSeparatorTextViewStyle">@android:style/Widget.TextView.ListSeparator</item>   
 
-		    <item name="listChoiceIndicatorSingle">@android:drawable/btn_radio</item>
+        <item name="listChoiceIndicatorSingle">@android:drawable/btn_radio</item>
         <item name="listChoiceIndicatorMultiple">@android:drawable/btn_check</item>
 
         <item name="expandableListPreferredItemPaddingLeft">40dip</item>
@@ -168,8 +168,8 @@
         <item name="progressBarStyleSmallTitle">@android:style/Widget.ProgressBar.Small.Title</item>
         <item name="progressBarStyleLarge">@android:style/Widget.ProgressBar.Large</item>
         <item name="progressBarStyleInverse">@android:style/Widget.ProgressBar.Inverse</item>
-		    <item name="progressBarStyleSmallInverse">@android:style/Widget.ProgressBar.Small.Inverse</item>
-	      <item name="progressBarStyleLargeInverse">@android:style/Widget.ProgressBar.Large.Inverse</item>
+        <item name="progressBarStyleSmallInverse">@android:style/Widget.ProgressBar.Small.Inverse</item>
+        <item name="progressBarStyleLargeInverse">@android:style/Widget.ProgressBar.Large.Inverse</item>
         <item name="seekBarStyle">@android:style/Widget.SeekBar</item>
         <item name="ratingBarStyle">@android:style/Widget.RatingBar</item>
         <item name="ratingBarStyleIndicator">@android:style/Widget.RatingBar.Indicator</item>
@@ -266,24 +266,18 @@
         <item name="textCheckMark">@android:drawable/indicator_check_mark_light</item>
         <item name="textCheckMarkInverse">@android:drawable/indicator_check_mark_dark</item>
 
-        <!-- List attributes -->
-        <item name="listChoiceIndicatorSingle">@android:drawable/btn_radio_light</item>
-        <item name="listChoiceIndicatorMultiple">@android:drawable/btn_check_light</item>
-
-        <!-- Widget styles -->
-        <item name="checkboxStyle">@android:style/Widget.CompoundButton.CheckBox.Inverse</item>
         <item name="gestureOverlayViewStyle">@android:style/Widget.GestureOverlayView.White</item>
         <item name="expandableListViewStyle">@android:style/Widget.ExpandableListView.White</item>
         <item name="listViewStyle">@android:style/Widget.ListView.White</item>
         <item name="listDivider">@drawable/divider_horizontal_bright</item>
         <item name="listSeparatorTextViewStyle">@android:style/Widget.TextView.ListSeparator.White</item>
+
         <item name="progressBarStyle">@android:style/Widget.ProgressBar.Inverse</item>
         <item name="progressBarStyleSmall">@android:style/Widget.ProgressBar.Small.Inverse</item>
         <item name="progressBarStyleLarge">@android:style/Widget.ProgressBar.Large.Inverse</item>
         <item name="progressBarStyleInverse">@android:style/Widget.ProgressBar</item>
         <item name="progressBarStyleSmallInverse">@android:style/Widget.ProgressBar.Small</item>
-		    <item name="progressBarStyleLargeInverse">@android:style/Widget.ProgressBar.Large</item>
-        <item name="radioButtonStyle">@android:style/Widget.CompoundButton.RadioButton.Inverse</item>
+        <item name="progressBarStyleLargeInverse">@android:style/Widget.ProgressBar.Large</item>
     </style>
     
     <!-- Variant of the light theme with no title bar -->
@@ -575,35 +569,52 @@
         <item name="android:windowActionModeOverlay">true</item>
     </style>
     
-    <!-- New Honeycomb holographic theme. Dark version -->
+    <!-- New Honeycomb holographic theme. Dark version.  The widgets in the
+         holographic theme are translucent on their brackground, so applications
+         must ensure that any background they use with this theme is itself
+         dark; otherwise, it will be difficult to see the widgets.  The new
+         UI style also includes a full action bar by default. -->
     <style name="Theme.Holo">
         <item name="editTextBackground">@android:drawable/edit_text_holo_dark</item>
         <item name="editTextColor">?android:attr/textColorPrimary</item>
+        <item name="android:windowActionBar">true</item>
+        <item name="listChoiceIndicatorSingle">@android:drawable/btn_radio_holo_dark</item>
+        <item name="listChoiceIndicatorMultiple">@android:drawable/btn_check_holo_dark</item>
     </style>
 
-    <!-- New Honeycomb holographic theme. Light version -->
+    <!-- New Honeycomb holographic theme. Light version.  The widgets in the
+         holographic theme are translucent on their brackground, so applications
+         must ensure that any background they use with this theme is itself
+         light; otherwise, it will be difficult to see the widgets.  The new
+         UI style also includes a full action bar by default. -->
     <style name="Theme.Light.Holo">
         <item name="editTextBackground">@android:drawable/edit_text_holo_light</item>
+        <item name="listChoiceIndicatorSingle">@android:drawable/btn_radio_holo_light</item>
+        <item name="listChoiceIndicatorMultiple">@android:drawable/btn_check_holo_light</item>
     </style>
 
-    <!-- Variant of the holo (dark) theme with no title bar -->
-    <style name="Theme.Holo.NoTitleBar">
+    <!-- Variant of the holographic (dark) theme with no action bar. -->
+    <style name="Theme.Holo.NoActionBar">
+        <item name="android:windowActionBar">false</item>
         <item name="android:windowNoTitle">true</item>
     </style>
     
-    <!-- Variant of the holo (dark) theme that has no title bar and fills the entire screen -->
-    <style name="Theme.Holo.NoTitleBar.Fullscreen">
+    <!-- Variant of the holographic (dark) theme that has no title bar and fills
+         the entire screen -->
+    <style name="Theme.Holo.NoActionBar.Fullscreen">
         <item name="android:windowFullscreen">true</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
 
-    <!-- Variant of the holo light theme with no title bar -->
-    <style name="Theme.Light.Holo.NoTitleBar">
+    <!-- Variant of the holographic light theme with no action bar -->
+    <style name="Theme.Light.Holo.NoActionBar">
+        <item name="android:windowActionBar">false</item>
         <item name="android:windowNoTitle">true</item>
     </style>
 
-    <!-- Variant of the holo light theme that has no title bar and fills the entire screen -->
-    <style name="Theme.Light.Holo.NoTitleBar.Fullscreen">
+    <!-- Variant of the holographic light theme that has no title bar and fills
+         the entire screen -->
+    <style name="Theme.Light.Holo.NoActionBar.Fullscreen">
         <item name="android:windowFullscreen">true</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
index dc5613e..86eda71 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
@@ -19,8 +19,11 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
+import android.database.DatabaseErrorHandler;
 import android.database.DatabaseUtils;
+import android.database.DefaultDatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteDatabase.CursorFactory;
 import android.database.sqlite.SQLiteStatement;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
@@ -41,6 +44,7 @@
     private static final int INSERT = 1;
     private static final int UPDATE = 2;
     private static final int DELETE = 3;
+    private static final String DB_NAME = "database_test.db";
 
     @Override
     protected void setUp() throws Exception {
@@ -61,7 +65,7 @@
 
     private void dbSetUp() throws Exception {
         File dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE);
-        mDatabaseFile = new File(dbDir, "database_test.db");
+        mDatabaseFile = new File(dbDir, DB_NAME);
         if (mDatabaseFile.exists()) {
             mDatabaseFile.delete();
         }
@@ -860,7 +864,7 @@
                     "select count(*) from " + TEST_TABLE, null));
             // query in a different thread. but since the transaction is started using
             // execSQ() instead of beginTransaction(), cursor's query is considered part of
-            // the same ransaction - and hence it should see the above inserted row
+            // the same transaction - and hence it should see the above inserted row
             Thread t = new Thread() {
                 @Override public void run() {
                     c1.requery();
@@ -878,11 +882,11 @@
 
     /**
      * This test is same as {@link #testTransactionAndWalInterplay2()} except the following:
-     * instead of commiting the data, do rollback and make sure the data seen by the query
+     * instead of committing the data, do rollback and make sure the data seen by the query
      * within the transaction is now gone.
      */
     @SmallTest
-    public void testTransactionAndWalInterplay3() throws InterruptedException {
+    public void testTransactionAndWalInterplay3() {
         createTableAndClearCache();
         mDatabase.execSQL("INSERT into " + TEST_TABLE + " values(10, 999);");
         String sql = "select * from " + TEST_TABLE;
@@ -909,4 +913,36 @@
                 "select count(*) from " + TEST_TABLE, null));
         c.close();
     }
+
+    /**
+     * http://b/issue?id=2943028
+     * SQLiteOpenHelper maintains a Singleton even if it is in bad state.
+     */
+    @SmallTest
+    public void testCloseAndReopen() {
+        mDatabase.close();
+        TestOpenHelper helper = new TestOpenHelper(getContext(), DB_NAME, null,
+                CURRENT_DATABASE_VERSION, new DefaultDatabaseErrorHandler());
+        mDatabase = helper.getWritableDatabase();
+        createTableAndClearCache();
+        mDatabase.execSQL("INSERT into " + TEST_TABLE + " values(10, 999);");
+        Cursor c = mDatabase.query(TEST_TABLE, new String[]{"i", "j"}, null, null, null, null, null);
+        assertEquals(1, c.getCount());
+        c.close();
+        mDatabase.close();
+        assertFalse(mDatabase.isOpen());
+        mDatabase = helper.getReadableDatabase();
+        assertTrue(mDatabase.isOpen());
+        c = mDatabase.query(TEST_TABLE, new String[]{"i", "j"}, null, null, null, null, null);
+        assertEquals(1, c.getCount());
+        c.close();
+    }
+    private class TestOpenHelper extends SQLiteOpenHelper {
+        public TestOpenHelper(Context context, String name, CursorFactory factory, int version,
+                DatabaseErrorHandler errorHandler) {
+            super(context, name, factory, version, errorHandler);
+        }
+        @Override public void onCreate(SQLiteDatabase db) {}
+        @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
+    }
 }
diff --git a/core/tests/coretests/src/android/net/http/HttpsThroughHttpProxyTest.java b/core/tests/coretests/src/android/net/http/HttpsThroughHttpProxyTest.java
index f3b7c06..95aad91 100644
--- a/core/tests/coretests/src/android/net/http/HttpsThroughHttpProxyTest.java
+++ b/core/tests/coretests/src/android/net/http/HttpsThroughHttpProxyTest.java
@@ -22,8 +22,8 @@
 import java.io.StringWriter;
 import java.util.Arrays;
 import java.util.List;
-import javax.net.ssl.TestSSLContext;
 import junit.framework.TestCase;
+import libcore.javax.net.ssl.TestSSLContext;
 import org.apache.http.HttpHost;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.HttpClient;
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index d0318cf..35ce17e 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -220,9 +220,16 @@
             <li><a style="color:gray;">Accelerometer</a></li>
           </ul>
       </li> -->
-      <li><a href="<?cs var:toroot ?>guide/topics/location/index.html">
-            <span class="en">Location and Maps</span>
-          </a></li>
+      <li class="toggle-list">
+        <div><a href="<?cs var:toroot ?>guide/topics/location/index.html">
+               <span class="en">Location and Maps</span>
+             </a></div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>guide/topics/location/obtaining-user-location.html">
+                <span class="en">Obtaining User Location</span>
+              </a> <span class="new">new!</span></li>
+        </ul>
+      </li>
   <!--<li class="toggle-list">
         <div><a style="color:gray;">Wireless Controls</a></div>
           <ul>
diff --git a/docs/html/guide/topics/fundamentals.jd b/docs/html/guide/topics/fundamentals.jd
index f780e7c..6d6abd8 100644
--- a/docs/html/guide/topics/fundamentals.jd
+++ b/docs/html/guide/topics/fundamentals.jd
@@ -770,9 +770,9 @@
 </p>
 
 <p>
-For more on launch modes, see the description of the 
-<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
-element. 
+For more on launch modes, see the description of the <code><a 
+href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">&lt;activity&gt;</a></code>
+element.
 </p>
 
 
diff --git a/docs/html/guide/topics/location/index.jd b/docs/html/guide/topics/location/index.jd
index e988ecb..5f98902 100644
--- a/docs/html/guide/topics/location/index.jd
+++ b/docs/html/guide/topics/location/index.jd
@@ -4,94 +4,63 @@
 <div id="qv-wrapper">
 <div id="qv">
 
-  <h2>Location and Maps quickview</h2>
+  <h2>Quickview</h2>
   <ul>
-    <li>Android provides a location framework that your application can use to determine the device's location and bearing and register for updates.</li>
-    <li>A Google Maps external library is available that lets you display and manage Maps data.</li>
+    <li>Android provides a location framework that your application can use to determine the
+device's location and bearing and register for updates</li>
+    <li>A Google Maps external library is available that lets you display and manage Maps data</li>
   </ul>
-  <h2>In this document</h2>
+
+  <h2>Topics</h2>
   <ol>
-    <li><a href="#location">Location Services</a></li>
-    <li><a href="#maps">Google Maps External Library</a></li>
+    <li><a href="{@docRoot}guide/topics/location/obtaining-user-location.html">Obtaining User
+Location</a></li>
   </ol>
+  
   <h2>See Also</h2>
   <ol>
-    <li><a href="http://code.google.com/android/add-ons/google-apis/index.html">Google APIs add-on download&raquo;</a></li>
+    <li><a
+href="http://code.google.com/android/add-ons/google-apis/maps-overview.html">Google
+Maps External Library &raquo;</a></li>
   </ol>
 </div>
 </div>
 
-<p>Location- and maps-based applications and services are compelling for mobile device users. You can build these capabilities into your applications using the classes of the {@link android.location} package and the Google Maps external library. The sections below provide details. </p>
+<p>Location and maps-based applications are compelling for mobile device users. You
+can build these capabilities into your applications using the classes of the {@link
+android.location} package and the Google Maps external library. The sections below provide details.
+</p>
 
 <h2 id="location">Location Services</h2>
 
 <p>Android gives your applications access to the location services supported by
-the device through the classes in the <code>android.location</code> package. The
+the device through the classes in the {@code android.location} package. The
 central component of the location framework is the 
-{@link android.location.LocationManager} system service, which provides an API to
-determine location and bearing if the underlying device (if it supports location
-capabilities). </p>
+{@link android.location.LocationManager} system service, which provides APIs to
+determine location and bearing of the underlying device (if available). </p>
 
-<p>As with other system services, you do not instantiate a LocationManager directly. 
-Rather, you request an LocationManager instance from the system by calling 
-{@link android.content.Context#getSystemService(String) getSystemService(Context.LOCATION_SERVICE)}. 
-The method returns a handle to a new LocationManager instance.</p>
+<p>As with other system services, you do not instantiate a {@link android.location.LocationManager}
+directly. Rather, you request an instance from the system by calling
+{@link android.content.Context#getSystemService(String)
+getSystemService(Context.LOCATION_SERVICE)}. The method returns a handle to a new {@link
+android.location.LocationManager} instance.</p>
 
-<p>Once your application has a handle to a LocationManager instance, your application 
-will be able to do three things:</p>
+<p>Once your application has a {@link android.location.LocationManager}, your application
+is able to do three things:</p>
 
 <ul>
-    <li>Query for the list of all LocationProviders known to the
-    LocationManager for its last known location.</li>
-    <li>Register/unregister for periodic updates of current location from a
-    LocationProvider (specified either by Criteria or name).</li>
-    <li>Register/unregister for a given Intent to be fired if the device comes
-    within a given proximity (specified by radius in meters) of a given
-    lat/long.</li>
+    <li>Query for the list of all {@link android.location.LocationProvider}s for the last known
+user location.</li>
+    <li>Register/unregister for periodic updates of the user's current location from a
+    location provider (specified either by criteria or name).</li>
+    <li>Register/unregister for a given {@link android.content.Intent} to be fired if the device
+comes within a given proximity (specified by radius in meters) of a given lat/long.</li>
 </ul>
 
-<p>However, during initial development in the emulator, you may not have access to real 
-data from a real location provider (Network or GPS). In that case, it may be necessary to
-spoof some data for your application using a mock location provider.</p>
+<p>For more information, read the guide to <a
+href="{@docRoot}guide/topics/location/obtaining-user-location.html">Obtaining User
+Location</a>.</p>
 
-<p class="note"><strong>Note:</strong> If you've used mock LocationProviders in
-previous versions of the SDK, you can no longer provide canned LocationProviders
-in the /system/etc/location directory. These directories will be wiped during boot-up.
-Please follow the new procedures outlined below.</p>
-
-<h3>Providing Mock Location Data</h3>
-
-<p>When testing your application on the Android emulator, there are a couple different
-ways to send it some mock location data: you can use the DDMS tool or the "geo" command 
-option in the emulator console.</p>
-
-<h4 id="ddms">Using DDMS</h4>
-<p>With the DDMS tool, you can simulate location data a few different ways:</p>
-<ul>
-    <li>Manually send individual longitude/latitude coordinates to the device.</li>
-    <li>Use a GPX file describing a route for playback to the device.</li>
-    <li>Use a KML file describing individual placemarks for sequenced playback to the device.</li>
-</ul>
-<p>For more information on using DDMS to spoof location data, see the 
-<a href="{@docRoot}guide/developing/tools/ddms.html#emulator-control">Using DDMS guide</a>.
-
-<h4 id="geo">Using the "geo" command in the emulator console</h4>
-<p>Launch your application in the Android emulator and open a terminal/console in
-your SDK's <code>/tools</code> directory. Connect to the emulator console. Now you can use:</p>
-<ul><li><code>geo fix</code> to send a fixed geo-location.
-	<p>This command accepts a longitude and latitude in decimal degrees, and
-	an optional altitude in meters. For example:</p>
-	<pre>geo fix -121.45356 46.51119 4392</pre>
-    </li>
-    <li><code>geo nmea</code> to send an NMEA 0183 sentence.
-	<p>This command accepts a single NMEA sentence of type '$GPGGA' (fix data) or '$GPRMC' (transit data).
-	For example:</p>
-	<pre>geo nmea $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62</pre>
-    </li>
-</ul>
-
-<p>For information about how to connect to the emulator console, see 
-<a href="{@docRoot}guide/developing/tools/emulator.html#console">Using the Emulator Console</a>.</p>
 
 <h2 id="maps">Google Maps External Library</h2>
 
@@ -128,9 +97,9 @@
 <p style="margin-left:2em;"><a
 href="http://code.google.com/android/add-ons/google-apis">http://code.google.com/android/add-ons/google-apis</a></p>
 
-<p>For your convenience, the Google APIs add-on is also included in the Android
-SDK. <!-- To learn now to use the Maps external library in your application, see
-[[Using External Libraries]].--></p>
+<p>For your convenience, the Google APIs add-on is also available as a downloadable component from
+the Android SDK and AVD Manager (see <a href="{@docRoot}sdk/adding-components.html">Adding SDK
+Components</a>).</p>
 
 <p class="note"><strong>Note:</strong> In order to display Google Maps data in a
 MapView, you must register with the Google Maps service and obtain a Maps API
diff --git a/docs/html/guide/topics/location/obtaining-user-location.jd b/docs/html/guide/topics/location/obtaining-user-location.jd
new file mode 100644
index 0000000..bc782d2
--- /dev/null
+++ b/docs/html/guide/topics/location/obtaining-user-location.jd
@@ -0,0 +1,454 @@
+page.title=Obtaining User Location
+parent.title=Location and Maps
+parent.link=index.html
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+  <h2>Quickview</h2>
+  <ul>
+    <li>The Network Location Provider provides good location data without using GPS</li>
+    <li>Obtaining user location can consume a lot of battery, so be careful how
+long you listen for updates</li>
+  </ul>
+  <h2>In this document</h2>
+  <ol>
+    <li><a href="#Challenges">Challenges in Determining User Location</a></li>
+    <li><a href="#Updates">Requesting Location Updates</a>
+      <ol>
+        <li><a href="#Permission">Requesting User Permissions</a></li>
+      </ol>
+    </li>
+    <li><a href="#BestPerformance">Defining a Model for the Best Performance</a>
+      <ol>
+        <li><a href="#Flow">Flow for obtaining user location</a></li>
+        <li><a href="#StartListening">Deciding when to start listening for updates</a></li>
+        <li><a href="#FastFix">Getting a fast fix with the last known location</a></li>
+        <li><a href="#StopListening">Deciding when to stop listening for updates</a></li>
+        <li><a href="#BestEstimate">Maintaining a current best estimate</a></li>
+        <li><a href="#Adjusting">Adjusting the model to save battery and data exchange</a></li>
+      </ol>
+    </li>
+    <li><a href="#MockData">Providing Mock Location Data</a></li>
+  </ol>
+  <h2>Key classes</h2>
+  <ol>
+    <li>{@link android.location.LocationManager}</li>
+    <li>{@link android.location.LocationListener}</li>
+  </ol>
+</div>
+</div>
+
+  <p>Knowing where the user is allows your application to be smarter and deliver
+better information to the user. When developing a location-aware application for Android, you can
+utilize GPS and Android's Network Location Provider to acquire the user location. Although
+GPS is most accurate, it only works outdoors, it quickly consumes battery power, and doesn't return
+the location as quickly as users want. Android's Network Location Provider determines user location
+using cell tower and Wi-Fi signals, providing location information in a way that
+works indoors and outdoors, responds faster, and uses less battery power. To obtain the user
+location in your application, you can use both GPS and the Network Location Provider, or just
+one.</p>
+
+
+<h2 id="Challenges">Challenges in Determining User Location</h2>
+
+<p>Obtaining user location from a mobile device can be complicated. There are several reasons
+why a location reading (regardless of the source) can contain errors and be inaccurate.
+Some sources of error in the user location include:</p>
+
+<ul>
+  <li><b>Multitude of location sources</b>
+    <p>GPS, Cell-ID, and Wi-Fi can each provide a clue to users location. Determining which to use
+and trust is a matter of trade-offs in accuracy, speed, and battery-efficiency.</p>
+  </li>
+  <li><b>User movement</b>
+    <p>Because the user location changes, you must account for movement by re-estimating user
+location every so often.</p>
+  </li>
+  <li><b>Varying accuracy</b>
+    <p>Location estimates coming from each location source are not consistent in their
+accuracy. A location obtained 10 seconds ago from one source might be more accurate than the newest
+location from another or same source.</p>
+  </li>
+</ul>
+
+  <p>These problems can make it difficult to obtain a reliable user location reading. This
+document provides information to help you meet these challenges to obtain a reliable location
+reading. It also provides ideas that you can use in your
+application to provide the user with an accurate and responsive geo-location experience.</p>
+
+
+<h2 id="Updates">Requesting Location Updates</h2>
+
+  <p>Before addressing some of the location errors described above, here is an introduction to
+how you can obtain user location on Android.</p>
+
+  <p>Getting user location in Android works by means of callback. You indicate that you'd
+like to receive location updates from the {@link android.location.LocationManager} ("Location
+Manager") by calling {@link android.location.LocationManager#requestLocationUpdates
+requestLocationUpdates()}, passing it a
+{@link android.location.LocationListener}. Your {@link android.location.LocationListener} must
+implement several callback methods that the Location Manager calls when the user location
+changes or when the status of the service changes.</p>
+
+<p>For example, the following code shows how to define a {@link android.location.LocationListener}
+and request location updates:
+  </p>
+
+<pre>
+// Acquire a reference to the system Location Manager
+LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
+
+// Define a listener that responds to location updates
+LocationListener locationListener = new LocationListener() {
+    public void onLocationChanged(Location location) {
+      // Called when a new location is found by the network location provider.
+      makeUseOfNewLocation(location);
+    }
+
+    public void onStatusChanged(String provider, int status, Bundle extras) {}
+
+    public void onProviderEnabled(String provider) {}
+
+    public void onProviderDisabled(String provider) {}
+  };
+
+// Register the listener with the Location Manager to receive location updates
+locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
+</pre>
+
+  <p>The first parameter in {@link
+android.location.LocationManager#requestLocationUpdates requestLocationUpdates()} is the type of
+location provider to use (in this case, the Network Location Provider for cell tower and Wi-Fi
+based location). You can control the frequency at which your listener receives updates
+with the second and third parameter&mdash;the second is the minimum time interval between
+notifications and the third is the minimum change in distance between notifications&mdash;setting
+both to zero requests location notifications as frequently as possible. The last parameter is your
+{@link android.location.LocationListener}, which receives callbacks for location updates.</p>
+
+<p>To request location updates from the GPS provider,
+substitute <code>GPS_PROVIDER</code> for <code>NETWORK_PROVIDER</code>. You can also request
+location updates from both the GPS and the Network Location Provider by calling {@link
+android.location.LocationManager#requestLocationUpdates requestLocationUpdates()} twice&mdash;once
+for <code>NETWORK_PROVIDER</code> and once for <code>GPS_PROVIDER</code>.</p>
+
+
+<h3 id="Permission">Requesting User Permissions</h3>
+
+<p>In order to receive location updates from <code>NETWORK_PROVIDER</code> or
+<code>GPS_PROVIDER</code>, you must request user permission by declaring either the {@code
+ACCESS_COARSE_LOCATION} or {@code ACCESS_FINE_LOCATION} permission, respectively, in your Android
+manifest file. For example:</p>
+
+<pre>
+&lt;manifest ... &gt;
+    &lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /&gt;
+    ...
+&lt;/manifest&gt;
+</pre>
+
+<p>Without these permissions, your application will fail at runtime when requesting
+location updates.</p>
+
+<p class="note"><strong>Note:</strong> If you are using both <code>NETWORK_PROVIDER</code> and
+<code>GPS_PROVIDER</code>, then you need to request only the {@code ACCESS_FINE_LOCATION}
+permission, because it includes permission for both providers. (Permission for {@code
+ACCESS_COARSE_LOCATION} includes permission only for <code>NETWORK_PROVIDER</code>.)</p>
+
+
+<h2 id="BestPerformance">Defining a Model for the Best Performance</h2>
+
+  <p>Location-based applications are now commonplace, but due to the less than optimal
+accuracy, user movement, the multitude of methods to obtain the location, and the desire to conserve
+battery, getting user location is complicated. To overcome the obstacles of obtaining a good user
+location while preserving battery power, you must define a consistent model that specifies how your
+application obtains the user location. This model includes when you start and stop listening for
+updates and when to use cached location data.</p>
+
+
+  <h3 id="Flow">Flow for obtaining user location</h3>
+
+  <p>Here's the typical flow of procedures for obtaining the user location:</p>
+
+  <ol>
+    <li>Start application.</li>
+    <li>Sometime later, start listening for updates from desired location providers.</li>
+    <li>Maintain a "current best estimate" of location by filtering out new, but less accurate
+fixes.</li>
+    <li>Stop listening for location updates.</li>
+    <li>Take advantage of the last best location estimate.</li>
+  </ol>
+
+  <p>Figure 1 demonstrates this model in a timeline that visualizes the period in which an
+application is listening for location updates and the events that occur during that time.</p>
+
+<img src="{@docRoot}images/location/getting-location.png" alt="" />
+<p class="img-caption"><strong>Figure 1.</strong> A timeline representing the window in which an
+application listens for location updates.</p>
+    
+  <p>This model of a window&mdash;during which location updates are received&mdash;frames many of
+the decisions you need to make when adding location-based services to your application.</p>
+
+
+  <h3 id="StartListening">Deciding when to start listening for updates</h3>
+
+  <p>You might want to start listening for location updates as soon as your application starts, or
+only after users activate a certain feature. Be aware that long windows of listening for location
+fixes can consume a lot of battery power, but short periods might not allow for sufficient
+accuracy.</p>
+
+  <p>As demonstrated above, you can begin listening for updates by calling {@link
+android.location.LocationManager#requestLocationUpdates requestLocationUpdates()}:</p>
+
+<pre>
+LocationProvider locationProvider = LocationManager.NETWORK_PROVIDER;
+// Or, use GPS location data:
+// LocationProvider locationProvider = LocationManager.GPS_PROVIDER;
+
+locationManager.requestLocationUpdates(locationProvider, 0, 0, locationListener);
+</pre>
+
+
+  <h3 id="FastFix">Getting a fast fix with the last known location</h3>
+  
+  <p>The time it takes for your location listener to receive the first location fix is often too
+long for users wait. Until a more accurate location is provided to your location listener, you
+should utilize a cached location by calling {@link
+android.location.LocationManager#getLastKnownLocation}:</p>
+<pre>
+LocationProvider locationProvider = LocationManager.NETWORK_PROVIDER;
+// Or use LocationManager.GPS_PROVIDER
+
+Location lastKnownLocation = locationManager.getLastKnownLocation(locationProvider);
+</pre>
+
+
+  <h3 id="StopListening">Deciding when to stop listening for updates</h3>
+  
+  <p>The logic of deciding when new fixes are no longer necessary might range from very simple to
+very complex depending on your application. A short gap between when the location is acquired and
+when the location is used, improves the accuracy of the estimate. Always beware that listening for a
+long time consumes a lot of battery power, so as soon as you have the information you need, you
+should stop
+listening for updates by calling {@link android.location.LocationManager#removeUpdates}:</p>
+<pre>
+// Remove the listener you previously added
+locationManager.removeUpdates(locationListener);
+</pre>
+
+
+  <h3 id="BestEstimate">Maintaining a current best estimate</h3>
+
+  <p>You might expect that the most recent location fix is the most accurate.
+However, because the accuracy of a location fix varies, the most recent fix is not always the best.
+You should include logic for choosing location fixes based on several criteria. The criteria also
+varies depending on the use-cases of the application and field testing.</p>
+
+  <p>Here are a few steps you can take to validate the accuracy of a location fix:</p>
+  <ul>
+    <li>Check if the location retrieved is significantly newer than the previous estimate.</li>
+    <li>Check if the accuracy claimed by the location is better or worse than the previous
+estimate.</li>
+    <li>Check which provider the new location is from and determine if you trust it more.</li>
+  </ul>
+  
+  <p>An elaborate example of this logic can look something like this:</p>
+
+<pre>
+private static final int TWO_MINUTES = 1000 * 60 * 2;
+
+/** Determines whether one Location reading is better than the current Location fix
+  * @param location  The new Location that you want to evaluate
+  * @param currentBestLocation  The current Location fix, to which you want to compare the new one
+  */
+protected boolean isBetterLocation(Location location, Location currentBestLocation) {
+    if (currentBestLocation == null) {
+        // A new location is always better than no location
+        return true;
+    }
+
+    // Check whether the new location fix is newer or older
+    long timeDelta = location.getTime() - currentBestLocation.getTime();
+    boolean isSignificantlyNewer = timeDelta &gt; TWO_MINUTES;
+    boolean isSignificantlyOlder = timeDelta &lt; -TWO_MINUTES;
+    boolean isNewer = timeDelta > 0;
+
+    // If it's been more than two minutes since the current location, use the new location
+    // because the user has likely moved
+    if (isSignificantlyNewer) {
+        return true;
+    // If the new location is more than two minutes older, it must be worse
+    } else if (isSignificantlyOlder) {
+        return false;
+    }
+
+    // Check whether the new location fix is more or less accurate
+    int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
+    boolean isLessAccurate = accuracyDelta &gt; 0;
+    boolean isMoreAccurate = accuracyDelta &lt; 0;
+    boolean isSignificantlyLessAccurate = accuracyDelta &gt; 200;
+
+    // Check if the old and new location are from the same provider
+    boolean isFromSameProvider = isSameProvider(location.getProvider(),
+            currentBestLocation.getProvider());
+
+    // Determine location quality using a combination of timeliness and accuracy
+    if (isMoreAccurate) {
+        return true;
+    } else if (isNewer &amp;&amp; !isLessAccurate) {
+        return true;
+    } else if (isNewer &amp;&amp; !isSignificantlyLessAccurate &amp;&amp; isFromSameProvider) {
+        return true;
+    }
+    return false;
+}
+
+/** Checks whether two providers are the same */
+private boolean isSameProvider(String provider1, String provider2) {
+    if (provider1 == null) {
+      return provider2 == null;
+    }
+    return provider1.equals(provider2);
+}
+</pre>
+
+
+  <h3 id="Adjusting">Adjusting the model to save battery and data exchange</h3>
+
+  <p>As you test your application, you might find that your model for providing good location and
+good performance needs some adjustment. Here are some things you might change to find a good
+balance between the two.</p>
+
+  <h4>Reduce the size of the window</h4>
+  
+  <p>A smaller window in which you listen for location updates means less interaction with GPS and
+network location services, thus, preserving battery life. But it also allows for fewer locations
+from which to choose a best estimate.</p>
+
+  <h4>Set the location providers to return updates less frequently</h4>
+  
+  <p>Reducing the rate at which new updates appear during the window can also improve battery
+efficiency, but at the cost of accuracy. The value of the trade-off depends on how your
+application is used. You can reduce the rate of updates by increasing the parameters in {@link
+android.location.LocationManager#requestLocationUpdates requestLocationUpdates()} that specify the
+interval time and minimum distance change.</p>
+
+  <h4>Restrict a set of providers</h4>
+  
+  <p>Depending on the environment where your application is used or the desired level of accuracy,
+you might choose to use only the Network Location Provider or only GPS, instead of both. Interacting
+with only one of the services reduces battery usage at a potential cost of accuracy.</p>
+
+
+  <h2>Common application cases</h2>
+  
+  <p>There are many reasons you might want to obtain the user location in your application. Below
+are a couple scenarios in which you can use the user location to enrich your application. Each
+scenario also describes good practices for when you should start and stop listening for the
+location, in order to get a good reading and help preserve battery life.</p>
+
+
+  <h3>Tagging user-created content with a location</h3>
+  
+  <p>You might be creating an application where user-created content is tagged with a location.
+Think of users sharing their local experiences, posting a review for a restaurant, or recording some
+content that can be augmented with their current location. A model of how this
+interaction might happen, with respect to the location services, is visualized in figure 2.</p>
+
+  <img src="{@docRoot}images/location/content-tagging.png" alt="" />
+<p class="img-caption"><strong>Figure 2.</strong> A timeline representing the window in which
+the user location is obtained and listening stops when the user consumes the current location.</p>
+  
+  <p>This lines up with the previous model of how user location is obtained in code (figure 1). For
+best location accuracy, you might choose to start listening for location updates when users begin
+creating
+the content or even when the application starts, then stop listening for updates when content is
+ready to be posted or recorded. You might need to consider how long a typical task of creating the
+content takes and judge if this duration allows for efficient collection of a location estimate.</p>
+
+
+  <h3>Helping the user decide on where to go</h3>
+  
+  <p>You might be creating an application that attempts to provide users with a set
+of options about where to go. For example, you're looking to provide a list of nearby restaurants,
+stores, and entertainment and the order of recommendations changes depending on the user
+location.</p>
+
+  <p>To accommodate such a flow, you might choose to:</p>
+  <ul>
+    <li>Rearrange recommendations when a new best estimate is obtained</li>
+    <li>Stop listening for updates if the order of recommendations has stabilized</li>
+  </ul>
+
+  <p>This kind of model is visualized in figure 3.</p>
+  
+  <img src="{@docRoot}images/location/where-to-go.png" alt="" />
+<p class="img-caption"><strong>Figure 3.</strong> A timeline representing the window in which a
+dynamic set of data is updated each time the user location updates.</p>
+
+
+
+
+<h2 id="MockData">Providing Mock Location Data</h2>
+
+<p>As you develop your application, you'll certainly need to test how well your model for obtaining
+user location works. This is most easily done using a real Android-powered device. If, however, you
+don't have a device, you can still test your location-based features by mocking location data in
+the Android emulator. There are three different ways to send your application mock location
+data: using Eclipse, DDMS, or the "geo" command in the emulator console.</p>
+
+<p class="note"><strong>Note:</strong> Providing mock location data is injected as GPS location
+data, so you must request location updates from <code>GPS_PROVIDER</code> in order for mock location
+data to work.</p>
+
+<h3 id="MockEclipse">Using Eclipse</h3>
+
+<p>Select <b>Window</b> &gt; <b>Show View</b> &gt; <b>Other</b> &gt; <b>Emulator Control</b>.</p>
+
+<p>In the Emulator Control panel, enter GPS coordinates under Location Controls as individual
+lat/long coordinates, with a GPX file for route playback, or a KML file for multiple place marks.
+(Be sure that you have a device selected in the Devices panel&mdash;available from <b>Window</b>
+&gt; <b>Show View</b> &gt; <b>Other</b> &gt; <b>Devices</b>.)</p>
+
+
+<h3 id="MockDdms">Using DDMS</h3>
+
+<p>With the DDMS tool, you can simulate location data a few different ways:</p>
+<ul>
+    <li>Manually send individual longitude/latitude coordinates to the device.</li>
+    <li>Use a GPX file describing a route for playback to the device.</li>
+    <li>Use a KML file describing individual place marks for sequenced playback to the device.</li>
+</ul>
+
+<p>For more information on using DDMS to spoof location data, see the
+<a href="{@docRoot}guide/developing/tools/ddms.html#emulator-control">Using DDMS guide</a>.
+
+
+<h3 id="MockGeo">Using the "geo" command in the emulator console</h3>
+
+<p>To send mock location data from the command line:</p>
+
+<ol>
+  <li>Launch your application in the Android emulator and open a terminal/console in your SDK's
+<code>/tools</code> directory.</li>
+  <li>Connect to the emulator console:
+<pre>telnet localhost <em>&lt;console-port&gt;</em></pre></li>
+  <li>Send the location data:</p>
+    <ul><li><code>geo fix</code> to send a fixed geo-location.
+    <p>This command accepts a longitude and latitude in decimal degrees, and
+    an optional altitude in meters. For example:</p>
+    <pre>geo fix -121.45356 46.51119 4392</pre>
+      </li>
+      <li><code>geo nmea</code> to send an NMEA 0183 sentence.
+    <p>This command accepts a single NMEA sentence of type '$GPGGA' (fix data) or '$GPRMC' (transit
+  data).
+    For example:</p>
+    <pre>geo nmea $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62</pre>
+      </li>
+    </ul>
+  </li>
+</ol>
+
+<p>For information about how to connect to the emulator console, see
+<a href="{@docRoot}guide/developing/tools/emulator.html#console">Using the Emulator Console</a>.</p>
diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd
index de8ca6d..e030a4c 100644
--- a/docs/html/guide/topics/manifest/activity-element.jd
+++ b/docs/html/guide/topics/manifest/activity-element.jd
@@ -336,10 +336,10 @@
 </p></dd>
 
 <dt><a name="lmode"></a>{@code android:launchMode}</dt>
-<dd>An instruction on how the activity should be launched.  There are four modes 
+<dd>An instruction on how the activity should be launched.  There are four modes
 that work in conjunction with activity flags ({@code FLAG_ACTIVITY_*} constants) 
-in {@link android.content.Intent} objects to determine what should happen when 
-the activity is called upon to handle an intent.  They are:
+in {@link android.content.Intent} objects to determine what should happen when
+the activity is called upon to handle an intent. They are:</p>
 
 <p style="margin-left: 2em">"{@code standard}"
 <br>"{@code singleTop}"
@@ -351,56 +351,110 @@
 </p>
 
 <p>
-The modes fall into two main groups, with "{@code standard}" and 
-"{@code singleTop}" activities on one side, and "{@code singleTask}" and 
-"{@code singleInstance}" activities on the other.  An activity with the 
-"{@code standard}" or "{@code singleTop}" launch mode can be instantiated 
-multiple times.  The instances can belong to any task and can be located 
-anywhere in the activity stack.  Typically, they're launched into the task 
-that called 
+As shown in the table below, the modes fall into two main groups, with
+"{@code standard}" and "{@code singleTop}" activities on one side, and
+"{@code singleTask}" and "{@code singleInstance}" activities on the other.
+An activity with the "{@code standard}" or "{@code singleTop}" launch mode
+can be instantiated multiple times.  The instances can belong to any task
+and can be located anywhere in the activity stack.  Typically, they're
+launched into the task that called 
 <code>{@link android.content.Context#startActivity startActivity()}</code>
-(unless the Intent object contains a 
-<code>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</code> 
-instruction, in which case a different task is chosen &mdash; see the 
+(unless the Intent object contains a
+<code>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</code>
+instruction, in which case a different task is chosen &mdash; see the
 <a href="#aff">taskAffinity</a> attribute).
 </p>
 
 <p>
-In contrast, "{@code singleTask}" and "{@code singleInstance}" activities 
-can only begin a task.  They are always at the root of the activity stack. 
-Moreover, the device can hold only one instance of the activity at a time 
+In contrast, "<code>singleTask</code>" and "<code>singleInstance</code>" activities
+can only begin a task.  They are always at the root of the activity stack.
+Moreover, the device can hold only one instance of the activity at a time
 &mdash; only one such task.
 </p>
 
 <p>
 The "{@code standard}" and "{@code singleTop}" modes differ from each other 
-in just one respect:  Every time there's new intent for a "{@code standard}" 
-activity, a new instance of the class is created to respond to that intent.  
+in just one respect:  Every time there's a new intent for a "{@code standard}"
+activity, a new instance of the class is created to respond to that intent.
 Each instance handles a single intent.
-Similarly, a new instance of a "{@code singleTop}" activity may also be 
-created to handle a new intent.  However, if the target task already has an 
-existing instance of the activity at the top of its stack, that instance 
-will receive the new intent (in an 
+Similarly, a new instance of a "{@code singleTop}" activity may also be
+created to handle a new intent.  However, if the target task already has an
+existing instance of the activity at the top of its stack, that instance
+will receive the new intent (in an
 <code>{@link android.app.Activity#onNewIntent onNewIntent()}</code> call);
 a new instance is not created.
-In other circumstances &mdash; for example, if an existing instance of the 
-"{@code singleTop}" activity is in the target task, but not at the top of 
-the stack, or if it's at the top of a stack, but not in the target task 
+In other circumstances &mdash; for example, if an existing instance of the
+"{@code singleTop}" activity is in the target task, but not at the top of
+the stack, or if it's at the top of a stack, but not in the target task
 &mdash; a new instance would be created and pushed on the stack.
-</p>  
+</p>
 
 <p>
-The "{@code singleTask}" and "{@code singleInstance}" modes also differ from 
-each other in only one respect:  A "{@code singleTask}" activity allows other 
-activities to be part of its task.  It's at the root of the activity stack, 
-but other activities (necessarily "{@code standard}" and "{@code singleTop}" 
-activities) can be launched into the same task.  A "{@code singleInstance}" 
-activity, on the other hand, permits no other activities to be part of its 
-task.  It's the only activity in the task.  If it starts another activity, 
-that activity is assigned to a different task &mdash; as if {@code
+The "{@code singleTask}" and "{@code singleInstance}" modes also differ from
+each other in only one respect:  A "{@code singleTask}" activity allows other
+activities to be part of its task. It's always at the root of its task, but
+other activities (necessarily "{@code standard}" and "{@code singleTop}"
+activities) can be launched into that task.  A "{@code singleInstance}"
+activity, on the other hand, permits no other activities to be part of its task.
+It's the only activity in the task.  If it starts another activity, that
+activity is assigned to a different task &mdash; as if {@code
 FLAG_ACTIVITY_NEW_TASK} was in the intent.
 </p>
 
+<table>
+<tr>
+<th>Use Cases</th>
+<th>Launch Mode</th>
+<th>Multiple Instances?</th>
+<th>Comments</th>
+</tr>
+<tr>
+<td rowspan="2" style="width:20%;">Normal launches for most activities</td>
+<td>"<code>standard</code>"</td>
+<td>Yes</td>
+<td>Default. The system always creates a new instance of the activity in the
+target task and routes the intent to it.</td>
+</tr>
+<tr>
+<td>"<code>singleTop</code>"</td>
+<td>Conditionally</td>
+<td>If an instance of the activity already exists at the top of the target task,
+the system routes the intent to that instance through a call to its {@link
+android.app.Activity#onNewIntent onNewIntent()} method, rather than creating a
+new instance of the activity.</td>
+</tr>
+<tr>
+<td rowspan="2">Specialized launches<br>
+<em>(not recommended for general use)</em></td>
+<td>"<code>singleTask</code>"</td>
+<td>No</td>
+<td>The system creates the activity at the root of a new task and routes the
+intent to it. However, if an instance of the activity already exists, the system
+routes the intent to existing instance through a call to its {@link
+android.app.Activity#onNewIntent onNewIntent()} method, rather than creating a
+new one.</td>
+</tr>
+<tr>
+<td>"<code>singleInstance</code>"</td>
+<td>No</td>
+<td>Same as "<code>singleTask"</code>, except that the system doesn't launch any
+other activities into the task holding the instance. The activity is always the
+single and only member of its task.</td>
+</tr>
+</table>
+
+<p>As shown in the table above, <code>standard</code> is the default mode and is
+appropriate for most types of activities. <code>SingleTop</code> is also a
+common and useful launch mode for many types of activities. The other modes
+&mdash; <code>singleTask</code> and <code>singleInstance</code> &mdash; are
+<span style="color:red">not appropriate for most applications</span>,
+since they result in an interaction model that is likely to be unfamiliar to
+users and is very different from most other applications. 
+
+<p>Regardless of the launch mode that you choose, make sure to test the usability
+of the activity during launch and when navigating back to it from
+other activities and tasks using the BACK key. </p>
+
 <p>For more information on launch modes and their interaction with Intent
 flags, see the 
 <a href="{@docRoot}guide/topics/fundamentals.html#acttask">Activities and 
diff --git a/docs/html/images/location/content-tagging.png b/docs/html/images/location/content-tagging.png
new file mode 100644
index 0000000..d58bfee
--- /dev/null
+++ b/docs/html/images/location/content-tagging.png
Binary files differ
diff --git a/docs/html/images/location/getting-location.png b/docs/html/images/location/getting-location.png
new file mode 100644
index 0000000..a5905ec
--- /dev/null
+++ b/docs/html/images/location/getting-location.png
Binary files differ
diff --git a/docs/html/images/location/where-to-go.png b/docs/html/images/location/where-to-go.png
new file mode 100644
index 0000000..59f5983
--- /dev/null
+++ b/docs/html/images/location/where-to-go.png
Binary files differ
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index f1f673b..6775c08 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -395,6 +395,17 @@
     static public Allocation createFromBitmapResourceBoxed(RenderScript rs, Resources res, int id, Element dstFmt, boolean genMips)
         throws IllegalArgumentException {
 
+        mBitmapOptions.inPreferredConfig = null;
+        if (dstFmt == rs.mElement_RGBA_8888) {
+            mBitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
+        } else if (dstFmt == rs.mElement_RGB_888) {
+            mBitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
+        } else if (dstFmt == rs.mElement_RGBA_4444) {
+            mBitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_4444;
+        } else if (dstFmt == rs.mElement_RGB_565) {
+            mBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;
+        }
+
         Bitmap b = BitmapFactory.decodeResource(res, id, mBitmapOptions);
         return createFromBitmapBoxed(rs, b, dstFmt, genMips);
     }
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index 964700b..75cf5ff 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -22,8 +22,6 @@
 
 namespace android {
 
-class ISurface;
-
 /*
  * A set of bit masks for specifying how the received preview frames are
  * handled before the previewCallback() call.
@@ -152,9 +150,8 @@
 
             status_t    getStatus() { return mStatus; }
 
-            // pass the buffered ISurface to the camera service
+            // pass the buffered Surface to the camera service
             status_t    setPreviewDisplay(const sp<Surface>& surface);
-            status_t    setPreviewDisplay(const sp<ISurface>& surface);
 
             // start preview mode, must call setPreviewDisplay first
             status_t    startPreview();
diff --git a/include/camera/CameraHardwareInterface.h b/include/camera/CameraHardwareInterface.h
index 6a66e3c..515d879 100644
--- a/include/camera/CameraHardwareInterface.h
+++ b/include/camera/CameraHardwareInterface.h
@@ -18,6 +18,7 @@
 #define ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
 
 #include <binder/IMemory.h>
+#include <ui/egl/android_natives.h>
 #include <utils/RefBase.h>
 #include <surfaceflinger/ISurface.h>
 #include <camera/Camera.h>
@@ -86,8 +87,8 @@
 public:
     virtual ~CameraHardwareInterface() { }
 
-    /** Return the IMemoryHeap for the preview image heap */
-    virtual sp<IMemoryHeap>         getPreviewHeap() const = 0;
+    /** Set the ISurface from which the preview buffers should be dequeued */
+    virtual status_t setPreviewWindow(const sp<ANativeWindow>& buf) = 0;
 
     /** Return the IMemoryHeap for the raw image heap */
     virtual sp<IMemoryHeap>         getRawHeap() const = 0;
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 4bc1799..a5c7874 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -61,6 +61,7 @@
     void getSupportedPreviewSizes(Vector<Size> &sizes) const;
     void setPreviewFrameRate(int fps);
     int getPreviewFrameRate() const;
+    void getPreviewFpsRange(int *min_fps, int *max_fps) const;
     void setPreviewFormat(const char *format);
     const char *getPreviewFormat() const;
     void setPictureSize(int width, int height);
@@ -82,6 +83,20 @@
     // Supported preview frame sizes in pixels.
     // Example value: "800x600,480x320". Read only.
     static const char KEY_SUPPORTED_PREVIEW_SIZES[];
+    // The current minimum and maximum preview fps. This controls the rate of
+    // preview frames received (CAMERA_MSG_PREVIEW_FRAME). The minimum and
+    // maximum fps must be one of the elements from
+    // KEY_SUPPORTED_PREVIEW_FPS_RANGE parameter.
+    // Example value: "10500,26623"
+    static const char KEY_PREVIEW_FPS_RANGE[];
+    // The supported preview fps (frame-per-second) ranges. Each range contains
+    // a minimum fps and maximum fps. If minimum fps equals to maximum fps, the
+    // camera outputs frames in fixed frame rate. If not, the camera outputs
+    // frames in auto frame rate. The actual frame rate fluctuates between the
+    // minimum and the maximum. The list has at least one element. The list is
+    // sorted from small to large (first by maximum fps and then minimum fps).
+    // Example value: "(10500,26623),(15000,26623),(30000,30000)"
+    static const char KEY_SUPPORTED_PREVIEW_FPS_RANGE[];
     // The image format for preview frames. See CAMERA_MSG_PREVIEW_FRAME in
     // frameworks/base/include/camera/Camera.h.
     // Example value: "yuv420sp" or PIXEL_FORMAT_XXX constants. Read/write.
diff --git a/include/camera/ICamera.h b/include/camera/ICamera.h
index 6fcf9e5..8bceea5 100644
--- a/include/camera/ICamera.h
+++ b/include/camera/ICamera.h
@@ -20,7 +20,7 @@
 #include <utils/RefBase.h>
 #include <binder/IInterface.h>
 #include <binder/Parcel.h>
-#include <surfaceflinger/ISurface.h>
+#include <surfaceflinger/Surface.h>
 #include <binder/IMemory.h>
 #include <utils/String8.h>
 #include <camera/Camera.h>
@@ -45,8 +45,8 @@
     // allow other processes to use this ICamera interface
     virtual status_t        unlock() = 0;
 
-    // pass the buffered ISurface to the camera service
-    virtual status_t        setPreviewDisplay(const sp<ISurface>& surface) = 0;
+    // pass the buffered Surface to the camera service
+    virtual status_t        setPreviewDisplay(const sp<Surface>& surface) = 0;
 
     // set the preview callback flag to affect how the received frames from
     // preview are handled.
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index 54adca8..54b197c 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -22,7 +22,7 @@
 
 namespace android {
 
-class ISurface;
+class Surface;
 class ICamera;
 class IMediaRecorderClient;
 
@@ -32,7 +32,7 @@
     DECLARE_META_INTERFACE(MediaRecorder);
 
     virtual	status_t		setCamera(const sp<ICamera>& camera) = 0;
-    virtual	status_t		setPreviewSurface(const sp<ISurface>& surface) = 0;
+    virtual	status_t		setPreviewSurface(const sp<Surface>& surface) = 0;
     virtual	status_t		setVideoSource(int vs) = 0;
     virtual	status_t		setAudioSource(int as) = 0;
     virtual	status_t		setOutputFormat(int of) = 0;
@@ -68,4 +68,3 @@
 }; // namespace android
 
 #endif // ANDROID_IMEDIARECORDER_H
-
diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
index 5e9e368..e5edd29 100644
--- a/include/media/MediaRecorderBase.h
+++ b/include/media/MediaRecorderBase.h
@@ -22,7 +22,7 @@
 
 namespace android {
 
-class ISurface;
+class Surface;
 
 struct MediaRecorderBase {
     MediaRecorderBase() {}
@@ -37,7 +37,7 @@
     virtual status_t setVideoSize(int width, int height) = 0;
     virtual status_t setVideoFrameRate(int frames_per_second) = 0;
     virtual status_t setCamera(const sp<ICamera>& camera) = 0;
-    virtual status_t setPreviewSurface(const sp<ISurface>& surface) = 0;
+    virtual status_t setPreviewSurface(const sp<Surface>& surface) = 0;
     virtual status_t setOutputFile(const char *path) = 0;
     virtual status_t setOutputFile(int fd, int64_t offset, int64_t length) = 0;
     virtual status_t setParameters(const String8& params) = 0;
diff --git a/include/media/PVMediaRecorder.h b/include/media/PVMediaRecorder.h
index c091c39..4b44ccc 100644
--- a/include/media/PVMediaRecorder.h
+++ b/include/media/PVMediaRecorder.h
@@ -23,7 +23,7 @@
 
 namespace android {
 
-class ISurface;
+class Surface;
 class ICamera;
 class AuthorDriverWrapper;
 
@@ -41,7 +41,7 @@
     virtual status_t setVideoSize(int width, int height);
     virtual status_t setVideoFrameRate(int frames_per_second);
     virtual status_t setCamera(const sp<ICamera>& camera);
-    virtual status_t setPreviewSurface(const sp<ISurface>& surface);
+    virtual status_t setPreviewSurface(const sp<Surface>& surface);
     virtual status_t setOutputFile(const char *path);
     virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
     virtual status_t setParameters(const String8& params);
@@ -66,4 +66,3 @@
 }; // namespace android
 
 #endif // ANDROID_PVMEDIARECORDER_H
-
diff --git a/include/media/Visualizer.h b/include/media/Visualizer.h
index 5d51de8..b8746c2 100644
--- a/include/media/Visualizer.h
+++ b/include/media/Visualizer.h
@@ -151,7 +151,6 @@
     void *mCaptureCbkUser;
     sp<CaptureThread> mCaptureThread;
     uint32_t mCaptureFlags;
-    void *mFftTable;
 };
 
 
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index de82b38..2412f6a 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -40,6 +40,7 @@
     virtual status_t stop();
     virtual status_t pause();
     virtual bool reachedEOS();
+    virtual status_t dump(int fd, const Vector<String16>& args);
 
     void beginBox(const char *fourcc);
     void writeInt8(int8_t x);
diff --git a/include/media/stagefright/MediaWriter.h b/include/media/stagefright/MediaWriter.h
index 151bf16..5cc8dcf 100644
--- a/include/media/stagefright/MediaWriter.h
+++ b/include/media/stagefright/MediaWriter.h
@@ -44,6 +44,10 @@
         mListener = listener;
     }
 
+    virtual status_t dump(int fd, const Vector<String16>& args) {
+        return OK;
+    }
+
 protected:
     virtual ~MediaWriter() {}
     int64_t mMaxFileSizeLimitBytes;
diff --git a/include/storage/IMountService.h b/include/storage/IMountService.h
new file mode 100644
index 0000000..a2735a4
--- /dev/null
+++ b/include/storage/IMountService.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_IMOUNTSERVICE_H
+#define ANDROID_IMOUNTSERVICE_H
+
+#include <storage/IMountServiceListener.h>
+#include <storage/IMountShutdownObserver.h>
+#include <storage/IObbActionListener.h>
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class IMountService: public IInterface {
+public:
+    DECLARE_META_INTERFACE(MountService);
+
+    virtual void registerListener(const sp<IMountServiceListener>& listener) = 0;
+    virtual void
+            unregisterListener(const sp<IMountServiceListener>& listener) = 0;
+    virtual bool isUsbMassStorageConnected() = 0;
+    virtual void setUsbMassStorageEnabled(const bool enable) = 0;
+    virtual bool isUsbMassStorageEnabled() = 0;
+    virtual int32_t mountVolume(const String16& mountPoint) = 0;
+    virtual int32_t
+            unmountVolume(const String16& mountPoint, const bool force) = 0;
+    virtual int32_t formatVolume(const String16& mountPoint) = 0;
+    virtual int32_t
+            getStorageUsers(const String16& mountPoint, int32_t** users) = 0;
+    virtual int32_t getVolumeState(const String16& mountPoint) = 0;
+    virtual int32_t createSecureContainer(const String16& id,
+            const int32_t sizeMb, const String16& fstype, const String16& key,
+            const int32_t ownerUid) = 0;
+    virtual int32_t finalizeSecureContainer(const String16& id) = 0;
+    virtual int32_t destroySecureContainer(const String16& id) = 0;
+    virtual int32_t mountSecureContainer(const String16& id,
+            const String16& key, const int32_t ownerUid) = 0;
+    virtual int32_t
+            unmountSecureContainer(const String16& id, const bool force) = 0;
+    virtual bool isSecureContainerMounted(const String16& id) = 0;
+    virtual int32_t renameSecureContainer(const String16& oldId,
+            const String16& newId) = 0;
+    virtual bool getSecureContainerPath(const String16& id, String16& path) = 0;
+    virtual int32_t getSecureContainerList(const String16& id,
+            String16*& containers) = 0;
+    virtual void shutdown(const sp<IMountShutdownObserver>& observer) = 0;
+    virtual void finishMediaUpdate() = 0;
+    virtual void mountObb(const String16& filename, const String16& key,
+            const sp<IObbActionListener>& token) = 0;
+    virtual void unmountObb(const String16& filename, const bool force) = 0;
+    virtual bool isObbMounted(const String16& filename) = 0;
+    virtual bool getMountedObbPath(const String16& filename, String16& path) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnMountService: public BnInterface<IMountService> {
+public:
+    virtual status_t onTransact(uint32_t code, const Parcel& data,
+            Parcel* reply, uint32_t flags = 0);
+};
+
+}
+; // namespace android
+
+#endif // ANDROID_IMOUNTSERVICE_H
diff --git a/include/storage/IMountServiceListener.h b/include/storage/IMountServiceListener.h
new file mode 100644
index 0000000..5b1f21c
--- /dev/null
+++ b/include/storage/IMountServiceListener.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_IMOUNTSERVICELISTENER_H
+#define ANDROID_IMOUNTSERVICELISTENER_H
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class IMountServiceListener: public IInterface {
+public:
+    DECLARE_META_INTERFACE(MountServiceListener);
+
+    virtual void onUsbMassStorageConnectionChanged(const bool connected) = 0;
+    virtual void onStorageStateChanged(const String16& path,
+            const String16& oldState, const String16& newState) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnMountServiceListener: public BnInterface<IMountServiceListener> {
+public:
+    virtual status_t onTransact(uint32_t code, const Parcel& data,
+            Parcel* reply, uint32_t flags = 0);
+};
+
+}
+; // namespace android
+
+#endif // ANDROID_IMOUNTSERVICELISTENER_H
diff --git a/include/storage/IMountShutdownObserver.h b/include/storage/IMountShutdownObserver.h
new file mode 100644
index 0000000..d019e01
--- /dev/null
+++ b/include/storage/IMountShutdownObserver.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_IMOUNTSHUTDOWNOBSERVER_H
+#define ANDROID_IMOUNTSHUTDOWNOBSERVER_H
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class IMountShutdownObserver: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(MountShutdownObserver);
+
+    virtual void onShutDownComplete(const int32_t statusCode) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnMountShutdownObserver: public BnInterface<IMountShutdownObserver>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IMOUNTSHUTDOWNOBSERVER_H
diff --git a/include/storage/IObbActionListener.h b/include/storage/IObbActionListener.h
new file mode 100644
index 0000000..1bedcc6
--- /dev/null
+++ b/include/storage/IObbActionListener.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_IOBBACTIONLISTENER_H
+#define ANDROID_IOBBACTIONLISTENER_H
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+#include <utils/String16.h>
+
+namespace android {
+
+class IObbActionListener: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(ObbActionListener);
+
+    virtual void onObbResult(const String16& filename, const String16& status) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnObbActionListener: public BnInterface<IObbActionListener>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IOBBACTIONLISTENER_H
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 28ab0fd..6fdd2ae 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -94,7 +94,7 @@
     friend class SurfaceComposerClient;
 
     // camera and camcorder need access to the ISurface binder interface for preview
-    friend class Camera;
+    friend class CameraService;
     friend class MediaRecorder;
     // mediaplayer needs access to ISurface for display
     friend class MediaPlayer;
@@ -173,7 +173,7 @@
      * (eventually this should go away and be replaced by proper APIs)
      */
     // camera and camcorder need access to the ISurface binder interface for preview
-    friend class Camera;
+    friend class CameraService;
     friend class MediaRecorder;
     // MediaPlayer needs access to ISurface for display
     friend class MediaPlayer;
@@ -310,4 +310,3 @@
 }; // namespace android
 
 #endif // ANDROID_SF_SURFACE_H
-
diff --git a/libs/camera/Camera.cpp b/libs/camera/Camera.cpp
index 7efc6d7..b5f78e8 100644
--- a/libs/camera/Camera.cpp
+++ b/libs/camera/Camera.cpp
@@ -167,32 +167,20 @@
     return c->unlock();
 }
 
-// pass the buffered ISurface to the camera service
+// pass the buffered Surface to the camera service
 status_t Camera::setPreviewDisplay(const sp<Surface>& surface)
 {
-    LOGV("setPreviewDisplay");
+    LOGV("setPreviewDisplay(%p)", surface.get());
     sp <ICamera> c = mCamera;
     if (c == 0) return NO_INIT;
     if (surface != 0) {
-        return c->setPreviewDisplay(surface->getISurface());
+        return c->setPreviewDisplay(surface);
     } else {
         LOGD("app passed NULL surface");
         return c->setPreviewDisplay(0);
     }
 }
 
-status_t Camera::setPreviewDisplay(const sp<ISurface>& surface)
-{
-    LOGV("setPreviewDisplay");
-    if (surface == 0) {
-        LOGD("app passed NULL surface");
-    }
-    sp <ICamera> c = mCamera;
-    if (c == 0) return NO_INIT;
-    return c->setPreviewDisplay(surface);
-}
-
-
 // start preview mode
 status_t Camera::startPreview()
 {
@@ -375,4 +363,3 @@
 }
 
 }; // namespace android
-
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index abd418a..d0ed7df 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -30,6 +30,8 @@
 const char CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS[] = "preview-format-values";
 const char CameraParameters::KEY_PREVIEW_FRAME_RATE[] = "preview-frame-rate";
 const char CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES[] = "preview-frame-rate-values";
+const char CameraParameters::KEY_PREVIEW_FPS_RANGE[] = "preview-fps-range";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE[] = "preview-fps-range-values";
 const char CameraParameters::KEY_PICTURE_SIZE[] = "picture-size";
 const char CameraParameters::KEY_SUPPORTED_PICTURE_SIZES[] = "picture-size-values";
 const char CameraParameters::KEY_PICTURE_FORMAT[] = "picture-format";
@@ -269,20 +271,24 @@
     mMap.removeItem(String8(key));
 }
 
-static int parse_size(const char *str, int &width, int &height, char **endptr = NULL)
+// Parse string like "640x480" or "10000,20000"
+static int parse_pair(const char *str, int *first, int *second, char delim,
+                      char **endptr = NULL)
 {
-    // Find the width.
+    // Find the first integer.
     char *end;
     int w = (int)strtol(str, &end, 10);
-    // If an 'x' does not immediately follow, give up.
-    if (*end != 'x')
+    // If a delimeter does not immediately follow, give up.
+    if (*end != delim) {
+        LOGE("Cannot find delimeter (%c) in str=%s", delim, str);
         return -1;
+    }
 
-    // Find the height, immediately after the 'x'.
+    // Find the second integer, immediately after the delimeter.
     int h = (int)strtol(end+1, &end, 10);
 
-    width = w;
-    height = h;
+    *first = w;
+    *second = h;
 
     if (endptr) {
         *endptr = end;
@@ -301,7 +307,8 @@
 
     while (true) {
         int width, height;
-        int success = parse_size(sizeStartPtr, width, height, &sizeStartPtr);
+        int success = parse_pair(sizeStartPtr, &width, &height, 'x',
+                                 &sizeStartPtr);
         if (success == -1 || (*sizeStartPtr != ',' && *sizeStartPtr != '\0')) {
             LOGE("Picture sizes string \"%s\" contains invalid character.", sizesStr);
             return;
@@ -324,19 +331,11 @@
 
 void CameraParameters::getPreviewSize(int *width, int *height) const
 {
-    *width = -1;
-    *height = -1;
-
+    *width = *height = -1;
     // Get the current string, if it doesn't exist, leave the -1x-1
     const char *p = get(KEY_PREVIEW_SIZE);
-    if (p == 0)
-        return;
-
-    int w, h;
-    if (parse_size(p, w, h) == 0) {
-        *width = w;
-        *height = h;
-    }
+    if (p == 0)  return;
+    parse_pair(p, width, height, 'x');
 }
 
 void CameraParameters::getSupportedPreviewSizes(Vector<Size> &sizes) const
@@ -355,6 +354,14 @@
     return getInt(KEY_PREVIEW_FRAME_RATE);
 }
 
+void CameraParameters::getPreviewFpsRange(int *min_fps, int *max_fps) const
+{
+    *min_fps = *max_fps = -1;
+    const char *p = get(KEY_PREVIEW_FPS_RANGE);
+    if (p == 0) return;
+    parse_pair(p, min_fps, max_fps, ',');
+}
+
 void CameraParameters::setPreviewFormat(const char *format)
 {
     set(KEY_PREVIEW_FORMAT, format);
@@ -374,19 +381,11 @@
 
 void CameraParameters::getPictureSize(int *width, int *height) const
 {
-    *width = -1;
-    *height = -1;
-
+    *width = *height = -1;
     // Get the current string, if it doesn't exist, leave the -1x-1
     const char *p = get(KEY_PICTURE_SIZE);
-    if (p == 0)
-        return;
-
-    int w, h;
-    if (parse_size(p, w, h) == 0) {
-        *width = w;
-        *height = h;
-    }
+    if (p == 0) return;
+    parse_pair(p, width, height, 'x');
 }
 
 void CameraParameters::getSupportedPictureSizes(Vector<Size> &sizes) const
diff --git a/libs/camera/ICamera.cpp b/libs/camera/ICamera.cpp
index 13673b5..94dc5c1 100644
--- a/libs/camera/ICamera.cpp
+++ b/libs/camera/ICamera.cpp
@@ -64,13 +64,13 @@
         remote()->transact(DISCONNECT, data, &reply);
     }
 
-    // pass the buffered ISurface to the camera service
-    status_t setPreviewDisplay(const sp<ISurface>& surface)
+    // pass the buffered Surface to the camera service
+    status_t setPreviewDisplay(const sp<Surface>& surface)
     {
         LOGV("setPreviewDisplay");
         Parcel data, reply;
         data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
-        data.writeStrongBinder(surface->asBinder());
+        Surface::writeToParcel(surface, &data);
         remote()->transact(SET_PREVIEW_DISPLAY, data, &reply);
         return reply.readInt32();
     }
@@ -258,7 +258,7 @@
         case SET_PREVIEW_DISPLAY: {
             LOGV("SET_PREVIEW_DISPLAY");
             CHECK_INTERFACE(ICamera, data, reply);
-            sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
+            sp<Surface> surface = Surface::readFromParcel(data);
             reply->writeInt32(setPreviewDisplay(surface));
             return NO_ERROR;
         } break;
@@ -376,4 +376,3 @@
 // ----------------------------------------------------------------------------
 
 }; // namespace android
-
diff --git a/libs/storage/Android.mk b/libs/storage/Android.mk
new file mode 100644
index 0000000..1e52fa4
--- /dev/null
+++ b/libs/storage/Android.mk
@@ -0,0 +1,20 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	IMountServiceListener.cpp \
+	IMountShutdownObserver.cpp \
+	IObbActionListener.cpp \
+	IMountService.cpp
+
+LOCAL_STATIC_LIBRARIES := \
+	libutils \
+	libbinder
+
+LOCAL_MODULE:= libstorage
+
+ifeq ($(TARGET_SIMULATOR),true)
+    LOCAL_LDLIBS += -lpthread
+endif
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/libs/storage/IMountService.cpp b/libs/storage/IMountService.cpp
new file mode 100644
index 0000000..902bb27
--- /dev/null
+++ b/libs/storage/IMountService.cpp
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "IMountService"
+
+#include <storage/IMountService.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+enum {
+    TRANSACTION_registerListener = IBinder::FIRST_CALL_TRANSACTION,
+    TRANSACTION_unregisterListener,
+    TRANSACTION_isUsbMassStorageConnected,
+    TRANSACTION_setUsbMassStorageEnabled,
+    TRANSACTION_isUsbMassStorageEnabled,
+    TRANSACTION_mountVolume,
+    TRANSACTION_unmountVolume,
+    TRANSACTION_formatVolume,
+    TRANSACTION_getStorageUsers,
+    TRANSACTION_getVolumeState,
+    TRANSACTION_createSecureContainer,
+    TRANSACTION_finalizeSecureContainer,
+    TRANSACTION_destroySecureContainer,
+    TRANSACTION_mountSecureContainer,
+    TRANSACTION_unmountSecureContainer,
+    TRANSACTION_isSecureContainerMounted,
+    TRANSACTION_renameSecureContainer,
+    TRANSACTION_getSecureContainerPath,
+    TRANSACTION_getSecureContainerList,
+    TRANSACTION_shutdown,
+    TRANSACTION_finishMediaUpdate,
+    TRANSACTION_mountObb,
+    TRANSACTION_unmountObb,
+    TRANSACTION_isObbMounted,
+    TRANSACTION_getMountedObbPath,
+};
+
+class BpMountService: public BpInterface<IMountService>
+{
+public:
+    BpMountService(const sp<IBinder>& impl)
+        : BpInterface<IMountService>(impl)
+    {
+    }
+
+    virtual void registerListener(const sp<IMountServiceListener>& listener)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeStrongBinder(listener->asBinder());
+        if (remote()->transact(TRANSACTION_registerListener, data, &reply) != NO_ERROR) {
+            LOGD("registerListener could not contact remote\n");
+            return;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("registerListener caught exception %d\n", err);
+            return;
+        }
+    }
+
+    virtual void unregisterListener(const sp<IMountServiceListener>& listener)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeStrongBinder(listener->asBinder());
+        if (remote()->transact(TRANSACTION_unregisterListener, data, &reply) != NO_ERROR) {
+            LOGD("unregisterListener could not contact remote\n");
+            return;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("unregisterListener caught exception %d\n", err);
+            return;
+        }
+    }
+
+    virtual bool isUsbMassStorageConnected()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        if (remote()->transact(TRANSACTION_isUsbMassStorageConnected, data, &reply) != NO_ERROR) {
+            LOGD("isUsbMassStorageConnected could not contact remote\n");
+            return false;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("isUsbMassStorageConnected caught exception %d\n", err);
+            return false;
+        }
+        return reply.readInt32() != 0;
+    }
+
+    virtual void setUsbMassStorageEnabled(const bool enable)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeInt32(enable != 0);
+        if (remote()->transact(TRANSACTION_setUsbMassStorageEnabled, data, &reply) != NO_ERROR) {
+            LOGD("setUsbMassStorageEnabled could not contact remote\n");
+            return;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("setUsbMassStorageEnabled caught exception %d\n", err);
+            return;
+        }
+    }
+
+    virtual bool isUsbMassStorageEnabled()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        if (remote()->transact(TRANSACTION_isUsbMassStorageEnabled, data, &reply) != NO_ERROR) {
+            LOGD("isUsbMassStorageEnabled could not contact remote\n");
+            return false;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("isUsbMassStorageEnabled caught exception %d\n", err);
+            return false;
+        }
+        return reply.readInt32() != 0;
+    }
+
+    int32_t mountVolume(const String16& mountPoint)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(mountPoint);
+        if (remote()->transact(TRANSACTION_mountVolume, data, &reply) != NO_ERROR) {
+            LOGD("mountVolume could not contact remote\n");
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("mountVolume caught exception %d\n", err);
+            return err;
+        }
+        return reply.readInt32();
+    }
+
+    int32_t unmountVolume(const String16& mountPoint, const bool force)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(mountPoint);
+        data.writeInt32(force ? 1 : 0);
+        if (remote()->transact(TRANSACTION_unmountVolume, data, &reply) != NO_ERROR) {
+            LOGD("unmountVolume could not contact remote\n");
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("unmountVolume caught exception %d\n", err);
+            return err;
+        }
+        return reply.readInt32();
+    }
+
+    int32_t formatVolume(const String16& mountPoint)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(mountPoint);
+        if (remote()->transact(TRANSACTION_formatVolume, data, &reply) != NO_ERROR) {
+            LOGD("formatVolume could not contact remote\n");
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("formatVolume caught exception %d\n", err);
+            return err;
+        }
+        return reply.readInt32();
+    }
+
+    int32_t getStorageUsers(const String16& mountPoint, int32_t** users)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(mountPoint);
+        if (remote()->transact(TRANSACTION_getStorageUsers, data, &reply) != NO_ERROR) {
+            LOGD("getStorageUsers could not contact remote\n");
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("getStorageUsers caught exception %d\n", err);
+            return err;
+        }
+        const int32_t numUsers = reply.readInt32();
+        *users = (int32_t*)malloc(sizeof(int32_t)*numUsers);
+        for (int i = 0; i < numUsers; i++) {
+            **users++ = reply.readInt32();
+        }
+        return numUsers;
+    }
+
+    int32_t getVolumeState(const String16& mountPoint)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(mountPoint);
+        if (remote()->transact(TRANSACTION_getVolumeState, data, &reply) != NO_ERROR) {
+            LOGD("getVolumeState could not contact remote\n");
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("getVolumeState caught exception %d\n", err);
+            return err;
+        }
+        return reply.readInt32();
+    }
+
+    int32_t createSecureContainer(const String16& id, const int32_t sizeMb, const String16& fstype,
+            const String16& key, const int32_t ownerUid)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(id);
+        data.writeInt32(sizeMb);
+        data.writeString16(fstype);
+        data.writeString16(key);
+        data.writeInt32(ownerUid);
+        if (remote()->transact(TRANSACTION_createSecureContainer, data, &reply) != NO_ERROR) {
+            LOGD("createSecureContainer could not contact remote\n");
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("createSecureContainer caught exception %d\n", err);
+            return err;
+        }
+        return reply.readInt32();
+    }
+
+    int32_t finalizeSecureContainer(const String16& id)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(id);
+        if (remote()->transact(TRANSACTION_finalizeSecureContainer, data, &reply) != NO_ERROR) {
+            LOGD("finalizeSecureContainer couldn't call remote\n");
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("finalizeSecureContainer caught exception %d\n", err);
+            return err;
+        }
+        return reply.readInt32();
+    }
+
+    int32_t destroySecureContainer(const String16& id)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(id);
+        if (remote()->transact(TRANSACTION_destroySecureContainer, data, &reply) != NO_ERROR) {
+            LOGD("destroySecureContainer couldn't call remote");
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("destroySecureContainer caught exception %d\n", err);
+            return err;
+        }
+        return reply.readInt32();
+    }
+
+    int32_t mountSecureContainer(const String16& id, const String16& key, const int32_t ownerUid)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(id);
+        data.writeString16(key);
+        data.writeInt32(ownerUid);
+        if (remote()->transact(TRANSACTION_mountSecureContainer, data, &reply) != NO_ERROR) {
+            LOGD("mountSecureContainer couldn't call remote");
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode(); // What to do...
+        if (err < 0) {
+            LOGD("mountSecureContainer caught exception %d\n", err);
+            return err;
+        }
+        return reply.readInt32();
+    }
+
+    int32_t unmountSecureContainer(const String16& id, const bool force)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(id);
+        data.writeInt32(force ? 1 : 0);
+        if (remote()->transact(TRANSACTION_getSecureContainerPath, data, &reply) != NO_ERROR) {
+            LOGD("unmountSecureContainer couldn't call remote");
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode(); // What to do...
+        if (err < 0) {
+            LOGD("unmountSecureContainer caught exception %d\n", err);
+            return err;
+        }
+        return reply.readInt32();
+    }
+
+    bool isSecureContainerMounted(const String16& id)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(id);
+        if (remote()->transact(TRANSACTION_isSecureContainerMounted, data, &reply) != NO_ERROR) {
+            LOGD("isSecureContainerMounted couldn't call remote");
+            return false;
+        }
+        int32_t err = reply.readExceptionCode(); // What to do...
+        if (err < 0) {
+            LOGD("isSecureContainerMounted caught exception %d\n", err);
+            return false;
+        }
+        return reply.readInt32() != 0;
+    }
+
+    int32_t renameSecureContainer(const String16& oldId, const String16& newId)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(oldId);
+        data.writeString16(newId);
+        if (remote()->transact(TRANSACTION_renameSecureContainer, data, &reply) != NO_ERROR) {
+            LOGD("renameSecureContainer couldn't call remote");
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode(); // What to do...
+        if (err < 0) {
+            LOGD("renameSecureContainer caught exception %d\n", err);
+            return err;
+        }
+        return reply.readInt32();
+    }
+
+    bool getSecureContainerPath(const String16& id, String16& path)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(id);
+        if (remote()->transact(TRANSACTION_getSecureContainerPath, data, &reply) != NO_ERROR) {
+            LOGD("getSecureContainerPath couldn't call remote");
+            return false;
+        }
+        int32_t err = reply.readExceptionCode(); // What to do...
+        if (err < 0) {
+            LOGD("getSecureContainerPath caught exception %d\n", err);
+            return false;
+        }
+        path = reply.readString16();
+        return true;
+    }
+
+    int32_t getSecureContainerList(const String16& id, String16*& containers)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(id);
+        if (remote()->transact(TRANSACTION_getSecureContainerList, data, &reply) != NO_ERROR) {
+            LOGD("getSecureContainerList couldn't call remote");
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("getSecureContainerList caught exception %d\n", err);
+            return err;
+        }
+        const int32_t numStrings = reply.readInt32();
+        containers = new String16[numStrings];
+        for (int i = 0; i < numStrings; i++) {
+            containers[i] = reply.readString16();
+        }
+        return numStrings;
+    }
+
+    void shutdown(const sp<IMountShutdownObserver>& observer)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeStrongBinder(observer->asBinder());
+        if (remote()->transact(TRANSACTION_shutdown, data, &reply) != NO_ERROR) {
+            LOGD("shutdown could not contact remote\n");
+            return;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("shutdown caught exception %d\n", err);
+            return;
+        }
+        reply.readExceptionCode();
+    }
+
+    void finishMediaUpdate()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        if (remote()->transact(TRANSACTION_finishMediaUpdate, data, &reply) != NO_ERROR) {
+            LOGD("finishMediaUpdate could not contact remote\n");
+            return;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("finishMediaUpdate caught exception %d\n", err);
+            return;
+        }
+        reply.readExceptionCode();
+    }
+
+    void mountObb(const String16& filename, const String16& key, const sp<
+            IObbActionListener>& token)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(filename);
+        data.writeString16(key);
+        data.writeStrongBinder(token->asBinder());
+        if (remote()->transact(TRANSACTION_mountObb, data, &reply) != NO_ERROR) {
+            LOGD("mountObb could not contact remote\n");
+            return;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("mountObb caught exception %d\n", err);
+            return;
+        }
+    }
+
+    void unmountObb(const String16& filename, const bool force)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(filename);
+        data.writeInt32(force ? 1 : 0);
+        if (remote()->transact(TRANSACTION_unmountObb, data, &reply) != NO_ERROR) {
+            LOGD("unmountObb could not contact remote\n");
+            return;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("unmountObb caught exception %d\n", err);
+            return;
+        }
+    }
+
+    bool isObbMounted(const String16& filename)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(filename);
+        if (remote()->transact(TRANSACTION_isObbMounted, data, &reply) != NO_ERROR) {
+            LOGD("isObbMounted could not contact remote\n");
+            return false;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("isObbMounted caught exception %d\n", err);
+            return false;
+        }
+        return reply.readInt32() != 0;
+    }
+
+    bool getMountedObbPath(const String16& filename, String16& path)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
+        data.writeString16(filename);
+        if (remote()->transact(TRANSACTION_getMountedObbPath, data, &reply) != NO_ERROR) {
+            LOGD("getMountedObbPath could not contact remote\n");
+            return false;
+        }
+        int32_t err = reply.readExceptionCode();
+        if (err < 0) {
+            LOGD("getMountedObbPath caught exception %d\n", err);
+            return false;
+        }
+        path = reply.readString16();
+        return true;
+    }
+};
+
+IMPLEMENT_META_INTERFACE(MountService, "IMountService");
+
+// ----------------------------------------------------------------------
+
+};
diff --git a/libs/storage/IMountServiceListener.cpp b/libs/storage/IMountServiceListener.cpp
new file mode 100644
index 0000000..c98a424
--- /dev/null
+++ b/libs/storage/IMountServiceListener.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <storage/IMountServiceListener.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+enum {
+    TRANSACTION_onUsbMassStorageConnectionChanged = IBinder::FIRST_CALL_TRANSACTION,
+    TRANSACTION_onStorageStateChanged,
+};
+
+status_t BnMountServiceListener::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case TRANSACTION_onUsbMassStorageConnectionChanged: {
+            CHECK_INTERFACE(IMountServiceListener, data, reply);
+            bool connected = (data.readInt32() != 0);
+            onUsbMassStorageConnectionChanged(connected);
+            reply->writeNoException();
+            return NO_ERROR;
+        } break;
+        case TRANSACTION_onStorageStateChanged: {
+            CHECK_INTERFACE(IMountServiceListener, data, reply);
+            String16 path = data.readString16();
+            String16 oldState = data.readString16();
+            String16 newState = data.readString16();
+            onStorageStateChanged(path, oldState, newState);
+            reply->writeNoException();
+            return NO_ERROR;
+        }
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+// ----------------------------------------------------------------------
+
+};
diff --git a/libs/storage/IMountShutdownObserver.cpp b/libs/storage/IMountShutdownObserver.cpp
new file mode 100644
index 0000000..1a6fdee
--- /dev/null
+++ b/libs/storage/IMountShutdownObserver.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <storage/IMountShutdownObserver.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+enum {
+    TRANSACTION_onShutDownComplete = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+status_t BnMountShutdownObserver::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case TRANSACTION_onShutDownComplete: {
+            CHECK_INTERFACE(IMountShutdownObserver, data, reply);
+            int32_t statusCode = data.readInt32();
+            onShutDownComplete(statusCode);
+            reply->writeNoException();
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+// ----------------------------------------------------------------------
+
+};
diff --git a/libs/storage/IObbActionListener.cpp b/libs/storage/IObbActionListener.cpp
new file mode 100644
index 0000000..5bfece7
--- /dev/null
+++ b/libs/storage/IObbActionListener.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <storage/IObbActionListener.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+enum {
+    TRANSACTION_onObbResult = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+// This is a stub that real consumers should override.
+class BpObbActionListener: public BpInterface<IObbActionListener> {
+public:
+    BpObbActionListener(const sp<IBinder>& impl)
+        : BpInterface<IObbActionListener>(impl)
+    { }
+
+    virtual void onObbResult(const String16& filename, const String16& status) { }
+};
+
+IMPLEMENT_META_INTERFACE(ObbActionListener, "IObbActionListener");
+
+// ----------------------------------------------------------------------
+
+status_t BnObbActionListener::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case TRANSACTION_onObbResult: {
+            CHECK_INTERFACE(IObbActionListener, data, reply);
+            String16 filename = data.readString16();
+            String16 state = data.readString16();
+            onObbResult(filename, state);
+            reply->writeNoException();
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------
+
+};
diff --git a/libs/storage/MODULE_LICENSE_APACHE2 b/libs/storage/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/storage/MODULE_LICENSE_APACHE2
diff --git a/libs/storage/NOTICE b/libs/storage/NOTICE
new file mode 100644
index 0000000..5d14293
--- /dev/null
+++ b/libs/storage/NOTICE
@@ -0,0 +1,190 @@
+
+   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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp
index 156a7db..47ec78a 100644
--- a/libs/surfaceflinger_client/SharedBufferStack.cpp
+++ b/libs/surfaceflinger_client/SharedBufferStack.cpp
@@ -344,11 +344,6 @@
 {
     SharedBufferStack& stack( *mSharedStack );
 
-    if (stack.head == tail && stack.available == mNumBuffers) {
-        LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d",
-                tail, stack.head, stack.available, stack.queued);
-    }
-
     RWLock::AutoRLock _rd(mLock);
 
     const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index 5ab72cd..f524476 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -363,6 +363,13 @@
         height   = surface->mHeight;
         format   = surface->mFormat;
         flags    = surface->mFlags;
+    } else if (surface != 0 && surface->mSurface != 0) {
+        LOGW("Parceling invalid surface with non-NULL ISurface as NULL: "
+             "mSurface = %p, mIdentity = %d, mWidth = %d, mHeight = %d, "
+             "mFormat = %d, mFlags = 0x%08x, mInitCheck = %d",
+             surface->mSurface.get(), surface->mIdentity, surface->mWidth,
+             surface->mHeight, surface->mFormat, surface->mFlags,
+             surface->mInitCheck);
     }
     parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
     parcel->writeInt32(identity);
@@ -434,6 +441,9 @@
             mSharedBufferClient = new SharedBufferClient(
                     mClient.getSharedClient(), token, 2, mIdentity);
             mInitCheck = mClient.getSharedClient()->validate(token);
+        } else {
+            LOGW("Not initializing the shared buffer client because token = %d",
+                    token);
         }
     }
 }
diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp
index a4c3500..604f558 100644
--- a/libs/utils/ZipFileRO.cpp
+++ b/libs/utils/ZipFileRO.cpp
@@ -636,7 +636,7 @@
         memcpy(buffer, ptr, uncompLen);
     } else {
         if (!inflateBuffer(buffer, ptr, uncompLen, compLen))
-            goto bail;
+            goto unmap;
     }
 
     if (compLen > kSequentialMin)
@@ -644,6 +644,8 @@
 
     result = true;
 
+unmap:
+    file->release();
 bail:
     return result;
 }
@@ -667,7 +669,7 @@
 
     getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL);
 
-    const FileMap* file = createEntryFileMap(entry);
+    FileMap* file = createEntryFileMap(entry);
     if (file == NULL) {
         goto bail;
     }
@@ -678,21 +680,23 @@
         ssize_t actual = write(fd, ptr, uncompLen);
         if (actual < 0) {
             LOGE("Write failed: %s\n", strerror(errno));
-            goto bail;
+            goto unmap;
         } else if ((size_t) actual != uncompLen) {
             LOGE("Partial write during uncompress (%zd of %zd)\n",
                 (size_t)actual, (size_t)uncompLen);
-            goto bail;
+            goto unmap;
         } else {
             LOGI("+++ successful write\n");
         }
     } else {
         if (!inflateBuffer(fd, ptr, uncompLen, compLen))
-            goto bail;
+            goto unmap;
     }
 
     result = true;
 
+unmap:
+    file->release();
 bail:
     return result;
 }
diff --git a/media/jni/android_media_MtpDatabase.cpp b/media/jni/android_media_MtpDatabase.cpp
index abbea30..bf83172 100644
--- a/media/jni/android_media_MtpDatabase.cpp
+++ b/media/jni/android_media_MtpDatabase.cpp
@@ -118,6 +118,18 @@
                                             MtpObjectHandleList* references);
 };
 
+// ----------------------------------------------------------------------------
+
+static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+    if (env->ExceptionCheck()) {
+        LOGE("An exception was thrown by callback '%s'.", methodName);
+        LOGE_EX(env);
+        env->ExceptionClear();
+    }
+}
+
+// ----------------------------------------------------------------------------
+
 MyMtpDatabase::MyMtpDatabase(JNIEnv *env, jobject client)
     :   mDatabase(env->NewGlobalRef(client)),
         mIntBuffer(NULL),
@@ -165,8 +177,12 @@
                                             uint64_t size,
                                             time_t modified) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    return env->CallIntMethod(mDatabase, method_beginSendObject, env->NewStringUTF(path),
-                (jint)format, (jint)parent, (jint)storage, (jlong)size, (jlong)modified);
+    MtpObjectHandle result = env->CallIntMethod(mDatabase, method_beginSendObject,
+            env->NewStringUTF(path), (jint)format, (jint)parent, (jint)storage,
+            (jlong)size, (jlong)modified);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return result;
 }
 
 void MyMtpDatabase::endSendObject(const char* path, MtpObjectHandle handle,
@@ -174,6 +190,8 @@
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     env->CallVoidMethod(mDatabase, method_endSendObject, env->NewStringUTF(path),
                         (jint)handle, (jint)format, (jboolean)succeeded);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
 }
 
 MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID,
@@ -189,16 +207,21 @@
     jsize length = env->GetArrayLength(array);
     for (int i = 0; i < length; i++)
         list->push(handles[i]);
-   env->ReleaseIntArrayElements(array, handles, 0);
-   return list;
+    env->ReleaseIntArrayElements(array, handles, 0);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return list;
 }
 
 int MyMtpDatabase::getNumObjects(MtpStorageID storageID,
                                 MtpObjectFormat format,
                                 MtpObjectHandle parent) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    return env->CallIntMethod(mDatabase, method_getNumObjects,
+    int result = env->CallIntMethod(mDatabase, method_getNumObjects,
                 (jint)storageID, (jint)format, (jint)parent);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return result;
 }
 
 MtpObjectFormatList* MyMtpDatabase::getSupportedPlaybackFormats() {
@@ -212,8 +235,10 @@
     jsize length = env->GetArrayLength(array);
     for (int i = 0; i < length; i++)
         list->push(formats[i]);
-   env->ReleaseIntArrayElements(array, formats, 0);
-   return list;
+    env->ReleaseIntArrayElements(array, formats, 0);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return list;
 }
 
 MtpObjectFormatList* MyMtpDatabase::getSupportedCaptureFormats() {
@@ -227,8 +252,10 @@
     jsize length = env->GetArrayLength(array);
     for (int i = 0; i < length; i++)
         list->push(formats[i]);
-   env->ReleaseIntArrayElements(array, formats, 0);
-   return list;
+    env->ReleaseIntArrayElements(array, formats, 0);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return list;
 }
 
 MtpObjectPropertyList* MyMtpDatabase::getSupportedObjectProperties(MtpObjectFormat format) {
@@ -242,8 +269,10 @@
     jsize length = env->GetArrayLength(array);
     for (int i = 0; i < length; i++)
         list->push(properties[i]);
-   env->ReleaseIntArrayElements(array, properties, 0);
-   return list;
+    env->ReleaseIntArrayElements(array, properties, 0);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return list;
 }
 
 MtpDevicePropertyList* MyMtpDatabase::getSupportedDeviceProperties() {
@@ -257,8 +286,10 @@
     jsize length = env->GetArrayLength(array);
     for (int i = 0; i < length; i++)
         list->push(properties[i]);
-   env->ReleaseIntArrayElements(array, properties, 0);
-   return list;
+    env->ReleaseIntArrayElements(array, properties, 0);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return list;
 }
 
 MtpResponseCode MyMtpDatabase::getObjectProperty(MtpObjectHandle handle,
@@ -315,6 +346,8 @@
             LOGE("unsupported object type\n");
             return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
     }
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
     return MTP_RESPONSE_OK;
 }
 
@@ -368,6 +401,7 @@
     packet.putString(date);   // date modified
     packet.putEmptyString();   // keywords
 
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
     return MTP_RESPONSE_OK;
 }
 
@@ -388,12 +422,16 @@
     fileLength = longValues[0];
     env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
     
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
     return result;
 }
 
 MtpResponseCode MyMtpDatabase::deleteFile(MtpObjectHandle handle) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    return env->CallIntMethod(mDatabase, method_deleteFile, (jint)handle);
+    MtpResponseCode result = env->CallIntMethod(mDatabase, method_deleteFile, (jint)handle);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return result;
 }
 
 struct PropertyTableEntry {
@@ -433,11 +471,14 @@
     jsize length = env->GetArrayLength(array);
     for (int i = 0; i < length; i++)
         list->push(handles[i]);
-   env->ReleaseIntArrayElements(array, handles, 0);
-   return list;
+    env->ReleaseIntArrayElements(array, handles, 0);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return list;
 }
 
-MtpResponseCode MyMtpDatabase::setObjectReferences(MtpObjectHandle handle, MtpObjectHandleList* references) {
+MtpResponseCode MyMtpDatabase::setObjectReferences(MtpObjectHandle handle,
+                                                    MtpObjectHandleList* references) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     int count = references->size();
     jintArray array = env->NewIntArray(count);
@@ -449,18 +490,11 @@
      for (int i = 0; i < count; i++)
         handles[i] = (*references)[i];
     env->ReleaseIntArrayElements(array, handles, 0);
-    return env->CallIntMethod(mDatabase, method_setObjectReferences,
+    MtpResponseCode result = env->CallIntMethod(mDatabase, method_setObjectReferences,
                 (jint)handle, array);
-}
 
-// ----------------------------------------------------------------------------
-
-static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
-    if (env->ExceptionCheck()) {
-        LOGE("An exception was thrown by callback '%s'.", methodName);
-        LOGE_EX(env);
-        env->ExceptionClear();
-    }
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return result;
 }
 
 #endif // HAVE_ANDROID_OS
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 977e6be..b4d01f5 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -31,7 +31,8 @@
     IEffect.cpp \
     IEffectClient.cpp \
     AudioEffect.cpp \
-    Visualizer.cpp
+    Visualizer.cpp \
+    fixedfft.cpp.arm
 
 LOCAL_SHARED_LIBRARIES := \
 	libui libcutils libutils libbinder libsonivox libicuuc libexpat libsurfaceflinger_client libcamera_client
@@ -50,11 +51,7 @@
     $(JNI_H_INCLUDE) \
     $(call include-path-for, graphics corecg) \
     $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
-    external/speex/include \
-    external/speex/libspeex \
     external/icu4c/common \
     external/expat/lib
 
-LOCAL_STATIC_LIBRARIES := libspeex
-
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 947ff34..f55a01e 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -19,7 +19,7 @@
 #define LOG_TAG "IMediaRecorder"
 #include <utils/Log.h>
 #include <binder/Parcel.h>
-#include <surfaceflinger/ISurface.h>
+#include <surfaceflinger/Surface.h>
 #include <camera/ICamera.h>
 #include <media/IMediaRecorderClient.h>
 #include <media/IMediaRecorder.h>
@@ -69,12 +69,12 @@
         return reply.readInt32();
     }
 
-    status_t setPreviewSurface(const sp<ISurface>& surface)
+    status_t setPreviewSurface(const sp<Surface>& surface)
     {
         LOGV("setPreviewSurface(%p)", surface.get());
         Parcel data, reply;
         data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
-        data.writeStrongBinder(surface->asBinder());
+        Surface::writeToParcel(surface, &data);
         remote()->transact(SET_PREVIEW_SURFACE, data, &reply);
         return reply.readInt32();
     }
@@ -409,7 +409,7 @@
         case SET_PREVIEW_SURFACE: {
             LOGV("SET_PREVIEW_SURFACE");
             CHECK_INTERFACE(IMediaRecorder, data, reply);
-            sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
+            sp<Surface> surface = Surface::readFromParcel(data);
             reply->writeInt32(setPreviewSurface(surface));
             return NO_ERROR;
         } break;
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
index 32cdb49..39552b6 100644
--- a/media/libmedia/Visualizer.cpp
+++ b/media/libmedia/Visualizer.cpp
@@ -26,10 +26,7 @@
 
 #include <media/Visualizer.h>
 
-extern "C" {
-#define FLOATING_POINT 1
-#include "fftwrap.h"
-}
+extern void fixed_fft_real(int n, int32_t *v);
 
 namespace android {
 
@@ -47,18 +44,10 @@
         mCaptureCbkUser(NULL)
 {
     initCaptureSize();
-    if (mCaptureSize != 0) {
-        mFftTable = spx_fft_init(mCaptureSize);
-    } else {
-        mFftTable = NULL;
-    }
 }
 
 Visualizer::~Visualizer()
 {
-    if (mFftTable != NULL) {
-        spx_fft_destroy(mFftTable);
-    }
 }
 
 status_t Visualizer::setEnabled(bool enabled)
@@ -163,11 +152,6 @@
     }
     if (status == NO_ERROR) {
         mCaptureSize = size;
-        if (mFftTable != NULL) {
-            spx_fft_destroy(mFftTable);
-        }
-        mFftTable = spx_fft_init(mCaptureSize);
-        LOGV("setCaptureSize size %d mFftTable %p", mCaptureSize, mFftTable);
     }
 
     return status;
@@ -219,19 +203,24 @@
 
 status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
 {
-    if (mFftTable == NULL) {
-        return NO_INIT;
+    int32_t workspace[mCaptureSize >> 1];
+    int32_t nonzero = 0;
+
+    for (uint32_t i = 0; i < mCaptureSize; i += 2) {
+        workspace[i >> 1] = (waveform[i] ^ 0x80) << 23;
+        workspace[i >> 1] |= (waveform[i + 1] ^ 0x80) << 7;
+        nonzero |= workspace[i >> 1];
     }
 
-    float fsrc[mCaptureSize];
-    for (uint32_t i = 0; i < mCaptureSize; i++) {
-        fsrc[i] = (int16_t)(waveform[i] ^ 0x80) << 8;
+    if (nonzero) {
+        fixed_fft_real(mCaptureSize >> 1, workspace);
     }
-    float fdst[mCaptureSize];
-    spx_fft_float(mFftTable, fsrc, fdst);
-    for (uint32_t i = 0; i < mCaptureSize; i++) {
-        fft[i] = (uint8_t)((int32_t)fdst[i] >> 8);
+
+    for (uint32_t i = 0; i < mCaptureSize; i += 2) {
+        fft[i] = workspace[i >> 1] >> 23;
+        fft[i + 1] = workspace[i >> 1] >> 7;
     }
+
     return NO_ERROR;
 }
 
diff --git a/media/libmedia/fixedfft.cpp b/media/libmedia/fixedfft.cpp
new file mode 100644
index 0000000..28eb05a
--- /dev/null
+++ b/media/libmedia/fixedfft.cpp
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ */
+
+/* A Fixed point implementation of Fast Fourier Transform (FFT). Complex numbers
+ * are represented by 32-bit integers, where higher 16 bits are real part and
+ * lower ones are imaginary part. Few compromises are made between efficiency,
+ * accuracy, and maintainability. To make it fast, arithmetic shifts are used
+ * instead of divisions, and bitwise inverses are used instead of negates. To
+ * keep it small, only radix-2 Cooley-Tukey algorithm is implemented, and only
+ * half of the twiddle factors are stored. Although there are still ways to make
+ * it even faster or smaller, it costs too much on one of the aspects.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <machine/cpu-features.h>
+
+#define LOG_FFT_SIZE 10
+#define MAX_FFT_SIZE (1 << LOG_FFT_SIZE)
+
+static const int32_t twiddle[MAX_FFT_SIZE / 4] = {
+    0x00008000, 0xff378001, 0xfe6e8002, 0xfda58006, 0xfcdc800a, 0xfc13800f,
+    0xfb4a8016, 0xfa81801e, 0xf9b88027, 0xf8ef8032, 0xf827803e, 0xf75e804b,
+    0xf6958059, 0xf5cd8068, 0xf5058079, 0xf43c808b, 0xf374809e, 0xf2ac80b2,
+    0xf1e480c8, 0xf11c80de, 0xf05580f6, 0xef8d8110, 0xeec6812a, 0xedff8146,
+    0xed388163, 0xec718181, 0xebab81a0, 0xeae481c1, 0xea1e81e2, 0xe9588205,
+    0xe892822a, 0xe7cd824f, 0xe7078276, 0xe642829d, 0xe57d82c6, 0xe4b982f1,
+    0xe3f4831c, 0xe3308349, 0xe26d8377, 0xe1a983a6, 0xe0e683d6, 0xe0238407,
+    0xdf61843a, 0xde9e846e, 0xdddc84a3, 0xdd1b84d9, 0xdc598511, 0xdb998549,
+    0xdad88583, 0xda1885be, 0xd95885fa, 0xd8988637, 0xd7d98676, 0xd71b86b6,
+    0xd65c86f6, 0xd59e8738, 0xd4e1877b, 0xd42487c0, 0xd3678805, 0xd2ab884c,
+    0xd1ef8894, 0xd13488dd, 0xd0798927, 0xcfbe8972, 0xcf0489be, 0xce4b8a0c,
+    0xcd928a5a, 0xccd98aaa, 0xcc218afb, 0xcb698b4d, 0xcab28ba0, 0xc9fc8bf5,
+    0xc9468c4a, 0xc8908ca1, 0xc7db8cf8, 0xc7278d51, 0xc6738dab, 0xc5c08e06,
+    0xc50d8e62, 0xc45b8ebf, 0xc3a98f1d, 0xc2f88f7d, 0xc2488fdd, 0xc198903e,
+    0xc0e990a1, 0xc03a9105, 0xbf8c9169, 0xbedf91cf, 0xbe329236, 0xbd86929e,
+    0xbcda9307, 0xbc2f9371, 0xbb8593dc, 0xbadc9448, 0xba3394b5, 0xb98b9523,
+    0xb8e39592, 0xb83c9603, 0xb7969674, 0xb6f196e6, 0xb64c9759, 0xb5a897ce,
+    0xb5059843, 0xb46298b9, 0xb3c09930, 0xb31f99a9, 0xb27f9a22, 0xb1df9a9c,
+    0xb1409b17, 0xb0a29b94, 0xb0059c11, 0xaf689c8f, 0xaecc9d0e, 0xae319d8e,
+    0xad979e0f, 0xacfd9e91, 0xac659f14, 0xabcd9f98, 0xab36a01c, 0xaaa0a0a2,
+    0xaa0aa129, 0xa976a1b0, 0xa8e2a238, 0xa84fa2c2, 0xa7bda34c, 0xa72ca3d7,
+    0xa69ca463, 0xa60ca4f0, 0xa57ea57e, 0xa4f0a60c, 0xa463a69c, 0xa3d7a72c,
+    0xa34ca7bd, 0xa2c2a84f, 0xa238a8e2, 0xa1b0a976, 0xa129aa0a, 0xa0a2aaa0,
+    0xa01cab36, 0x9f98abcd, 0x9f14ac65, 0x9e91acfd, 0x9e0fad97, 0x9d8eae31,
+    0x9d0eaecc, 0x9c8faf68, 0x9c11b005, 0x9b94b0a2, 0x9b17b140, 0x9a9cb1df,
+    0x9a22b27f, 0x99a9b31f, 0x9930b3c0, 0x98b9b462, 0x9843b505, 0x97ceb5a8,
+    0x9759b64c, 0x96e6b6f1, 0x9674b796, 0x9603b83c, 0x9592b8e3, 0x9523b98b,
+    0x94b5ba33, 0x9448badc, 0x93dcbb85, 0x9371bc2f, 0x9307bcda, 0x929ebd86,
+    0x9236be32, 0x91cfbedf, 0x9169bf8c, 0x9105c03a, 0x90a1c0e9, 0x903ec198,
+    0x8fddc248, 0x8f7dc2f8, 0x8f1dc3a9, 0x8ebfc45b, 0x8e62c50d, 0x8e06c5c0,
+    0x8dabc673, 0x8d51c727, 0x8cf8c7db, 0x8ca1c890, 0x8c4ac946, 0x8bf5c9fc,
+    0x8ba0cab2, 0x8b4dcb69, 0x8afbcc21, 0x8aaaccd9, 0x8a5acd92, 0x8a0cce4b,
+    0x89becf04, 0x8972cfbe, 0x8927d079, 0x88ddd134, 0x8894d1ef, 0x884cd2ab,
+    0x8805d367, 0x87c0d424, 0x877bd4e1, 0x8738d59e, 0x86f6d65c, 0x86b6d71b,
+    0x8676d7d9, 0x8637d898, 0x85fad958, 0x85beda18, 0x8583dad8, 0x8549db99,
+    0x8511dc59, 0x84d9dd1b, 0x84a3dddc, 0x846ede9e, 0x843adf61, 0x8407e023,
+    0x83d6e0e6, 0x83a6e1a9, 0x8377e26d, 0x8349e330, 0x831ce3f4, 0x82f1e4b9,
+    0x82c6e57d, 0x829de642, 0x8276e707, 0x824fe7cd, 0x822ae892, 0x8205e958,
+    0x81e2ea1e, 0x81c1eae4, 0x81a0ebab, 0x8181ec71, 0x8163ed38, 0x8146edff,
+    0x812aeec6, 0x8110ef8d, 0x80f6f055, 0x80def11c, 0x80c8f1e4, 0x80b2f2ac,
+    0x809ef374, 0x808bf43c, 0x8079f505, 0x8068f5cd, 0x8059f695, 0x804bf75e,
+    0x803ef827, 0x8032f8ef, 0x8027f9b8, 0x801efa81, 0x8016fb4a, 0x800ffc13,
+    0x800afcdc, 0x8006fda5, 0x8002fe6e, 0x8001ff37,
+};
+
+/* Returns the multiplication of \conj{a} and {b}. */
+static inline int32_t mult(int32_t a, int32_t b)
+{
+#if __ARM_ARCH__ >= 6
+    int32_t t = b;
+    __asm__("smuad  %0, %0, %1"          : "+r" (t) : "r" (a));
+    __asm__("smusdx %0, %0, %1"          : "+r" (b) : "r" (a));
+    __asm__("pkhtb  %0, %0, %1, ASR #16" : "+r" (t) : "r" (b));
+    return t;
+#else
+    return (((a >> 16) * (b >> 16) + (int16_t)a * (int16_t)b) & ~0xFFFF) |
+        ((((a >> 16) * (int16_t)b - (int16_t)a * (b >> 16)) >> 16) & 0xFFFF);
+#endif
+}
+
+static inline int32_t half(int32_t a)
+{
+#if __ARM_ARCH__ >= 6
+    __asm__("shadd16 %0, %0, %1" : "+r" (a) : "r" (0));
+    return a;
+#else
+    return ((a >> 1) & ~0x8000) | (a & 0x8000);
+#endif
+}
+
+void fixed_fft(int n, int32_t *v)
+{
+    int scale = LOG_FFT_SIZE, i, p, r;
+
+    for (r = 0, i = 1; i < n; ++i) {
+        for (p = n; !(p & r); p >>= 1, r ^= p);
+        if (i < r) {
+            int32_t t = v[i];
+            v[i] = v[r];
+            v[r] = t;
+        }
+    }
+
+    for (p = 1; p < n; p <<= 1) {
+        --scale;
+
+        for (i = 0; i < n; i += p << 1) {
+            int32_t x = half(v[i]);
+            int32_t y = half(v[i + p]);
+            v[i] = x + y;
+            v[i + p] = x - y;
+        }
+
+        for (r = 1; r < p; ++r) {
+            int32_t w = MAX_FFT_SIZE / 4 - (r << scale);
+            i = w >> 31;
+            w = twiddle[(w ^ i) - i] ^ (i << 16);
+            for (i = r; i < n; i += p << 1) {
+                int32_t x = half(v[i]);
+                int32_t y = mult(w, v[i + p]);
+                v[i] = x - y;
+                v[i + p] = x + y;
+            }
+        }
+    }
+}
+
+void fixed_fft_real(int n, int32_t *v)
+{
+    int scale = LOG_FFT_SIZE, m = n >> 1, i;
+
+    fixed_fft(n, v);
+    for (i = 1; i <= n; i <<= 1, --scale);
+    v[0] = mult(~v[0], 0x80008000);
+    v[m] = half(v[m]);
+
+    for (i = 1; i < n >> 1; ++i) {
+        int32_t x = half(v[i]);
+        int32_t z = half(v[n - i]);
+        int32_t y = z - (x ^ 0xFFFF);
+        x = half(x + (z ^ 0xFFFF));
+        y = mult(y, twiddle[i << scale]);
+        v[i] = x - y;
+        v[n - i] = (x + y) ^ 0xFFFF;
+    }
+}
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 9d53c25..7f25359 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -65,7 +65,7 @@
         return INVALID_OPERATION;
     }
 
-    status_t ret = mMediaRecorder->setPreviewSurface(surface->getISurface());
+    status_t ret = mMediaRecorder->setPreviewSurface(surface);
     if (OK != ret) {
         LOGV("setPreviewSurface failed: %d", ret);
         mCurrentState = MEDIA_RECORDER_ERROR;
@@ -643,4 +643,3 @@
 }
 
 }; // namespace android
-
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 73862c3..7e05043 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -70,7 +70,7 @@
     return mRecorder->setCamera(camera);
 }
 
-status_t MediaRecorderClient::setPreviewSurface(const sp<ISurface>& surface)
+status_t MediaRecorderClient::setPreviewSurface(const sp<Surface>& surface)
 {
     LOGV("setPreviewSurface");
     Mutex::Autolock lock(mLock);
@@ -337,4 +337,3 @@
 }
 
 }; // namespace android
-
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 1d1913d..6c17217 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -29,7 +29,7 @@
 {
 public:
     virtual     status_t        setCamera(const sp<ICamera>& camera);
-    virtual     status_t        setPreviewSurface(const sp<ISurface>& surface);
+    virtual     status_t        setPreviewSurface(const sp<Surface>& surface);
     virtual     status_t        setVideoSource(int vs);
     virtual     status_t        setAudioSource(int as);
     virtual     status_t        setOutputFormat(int of);
@@ -66,4 +66,3 @@
 }; // namespace android
 
 #endif // ANDROID_MEDIARECORDERCLIENT_H
-
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 59a544c..a24e56c 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -35,7 +35,7 @@
 #include <camera/ICamera.h>
 #include <camera/Camera.h>
 #include <camera/CameraParameters.h>
-#include <surfaceflinger/ISurface.h>
+#include <surfaceflinger/Surface.h>
 #include <utils/Errors.h>
 #include <sys/types.h>
 #include <ctype.h>
@@ -201,7 +201,7 @@
     return OK;
 }
 
-status_t StagefrightRecorder::setPreviewSurface(const sp<ISurface> &surface) {
+status_t StagefrightRecorder::setPreviewSurface(const sp<Surface> &surface) {
     LOGV("setPreviewSurface: %p", surface.get());
     mPreviewSurface = surface;
 
@@ -342,10 +342,14 @@
 
 status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
     LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
-    if (timeUs <= 100000LL) {  // XXX: 100 milli-seconds
+    if (timeUs <= 0) {
+        LOGW("Max file duration is not positive: %lld us. Disabling duration limit.", timeUs);
+        timeUs = 0; // Disable the duration limit for zero or negative values.
+    } else if (timeUs <= 100000LL) {  // XXX: 100 milli-seconds
         LOGE("Max file duration is too short: %lld us", timeUs);
         return BAD_VALUE;
     }
+
     mMaxFileDurationUs = timeUs;
     return OK;
 }
@@ -1235,11 +1239,19 @@
     return OK;
 }
 
-status_t StagefrightRecorder::dump(int fd, const Vector<String16>& args) const {
+status_t StagefrightRecorder::dump(
+        int fd, const Vector<String16>& args) const {
+    LOGV("dump");
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
-    snprintf(buffer, SIZE, "   Recorder: %p", this);
+    if (mWriter != 0) {
+        mWriter->dump(fd, args);
+    } else {
+        snprintf(buffer, SIZE, "   No file writer\n");
+        result.append(buffer);
+    }
+    snprintf(buffer, SIZE, "   Recorder: %p\n", this);
     snprintf(buffer, SIZE, "   Output file (fd %d):\n", mOutputFd);
     result.append(buffer);
     snprintf(buffer, SIZE, "     File format: %d\n", mOutputFormat);
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index a8be27d..628e19b 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -42,7 +42,7 @@
     virtual status_t setVideoSize(int width, int height);
     virtual status_t setVideoFrameRate(int frames_per_second);
     virtual status_t setCamera(const sp<ICamera>& camera);
-    virtual status_t setPreviewSurface(const sp<ISurface>& surface);
+    virtual status_t setPreviewSurface(const sp<Surface>& surface);
     virtual status_t setOutputFile(const char *path);
     virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
     virtual status_t setParameters(const String8& params);
@@ -63,7 +63,7 @@
     };
 
     sp<Camera> mCamera;
-    sp<ISurface> mPreviewSurface;
+    sp<Surface> mPreviewSurface;
     sp<IMediaRecorderClient> mListener;
     sp<MediaWriter> mWriter;
     sp<AudioSource> mAudioSourceNode;
@@ -144,4 +144,3 @@
 }  // namespace android
 
 #endif  // STAGEFRIGHT_RECORDER_H_
-
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 568037e..e36d9fe 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -60,6 +60,7 @@
     bool isAudio() const { return mIsAudio; }
     bool isMPEG4() const { return mIsMPEG4; }
     void addChunkOffset(off_t offset) { mChunkOffsets.push_back(offset); }
+    status_t dump(int fd, const Vector<String16>& args) const;
 
 private:
     MPEG4Writer *mOwner;
@@ -217,6 +218,37 @@
     mTracks.clear();
 }
 
+status_t MPEG4Writer::dump(
+        int fd, const Vector<String16>& args) {
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "   MPEG4Writer %p\n", this);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     mStarted: %s\n", mStarted? "true": "false");
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    for (List<Track *>::iterator it = mTracks.begin();
+         it != mTracks.end(); ++it) {
+        (*it)->dump(fd, args);
+    }
+    return OK;
+}
+
+status_t MPEG4Writer::Track::dump(
+        int fd, const Vector<String16>& args) const {
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "     %s track\n", mIsAudio? "Audio": "Video");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "       reached EOS: %s\n",
+            mReachedEOS? "true": "false");
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return OK;
+}
+
 status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
     Track *track = new Track(this, source);
     mTracks.push_back(track);
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 4741b1d..b39157e 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -146,29 +146,36 @@
 
 static const CodecInfo kDecoderInfo[] = {
     { MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" },
+    { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.Nvidia.mp3.decoder" },
 //    { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
     { MEDIA_MIMETYPE_AUDIO_MPEG, "MP3Decoder" },
 //    { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.PV.mp3dec" },
 //    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.Nvidia.amr.decoder" },
     { MEDIA_MIMETYPE_AUDIO_AMR_NB, "AMRNBDecoder" },
 //    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrdec" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.Nvidia.amrwb.decoder" },
     { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" },
     { MEDIA_MIMETYPE_AUDIO_AMR_WB, "AMRWBDecoder" },
 //    { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.PV.amrdec" },
+    { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.Nvidia.aac.decoder" },
     { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" },
     { MEDIA_MIMETYPE_AUDIO_AAC, "AACDecoder" },
 //    { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacdec" },
     { MEDIA_MIMETYPE_AUDIO_G711_ALAW, "G711Decoder" },
     { MEDIA_MIMETYPE_AUDIO_G711_MLAW, "G711Decoder" },
+    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.Nvidia.mp4.decode" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.decoder.mpeg4" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.decoder.mpeg4" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "M4vH263Decoder" },
 //    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4dec" },
+    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.Nvidia.h263.decode" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.7x30.video.decoder.h263" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.decoder.h263" },
     { MEDIA_MIMETYPE_VIDEO_H263, "M4vH263Decoder" },
 //    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263dec" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.Nvidia.h264.decode" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.decoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.decoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.Decoder" },
@@ -199,6 +206,7 @@
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.encoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.encoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.Nvidia.h264.encoder" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "AVCEncoder" },
 //    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
 };
@@ -337,6 +345,13 @@
 uint32_t OMXCodec::getComponentQuirks(const char *componentName) {
     uint32_t quirks = 0;
 
+    if (!strcmp(componentName, "OMX.Nvidia.amr.decoder") ||
+         !strcmp(componentName, "OMX.Nvidia.amrwb.decoder") ||
+         !strcmp(componentName, "OMX.Nvidia.aac.decoder") ||
+         !strcmp(componentName, "OMX.Nvidia.mp3.decoder")) {
+        quirks |= kDecoderLiesAboutNumberOfChannels;
+    }
+
     if (!strcmp(componentName, "OMX.PV.avcdec")) {
         quirks |= kWantsNALFragments;
     }
@@ -854,6 +869,10 @@
     OMX_COLOR_FORMATTYPE colorFormat;
     CHECK_EQ(OK, findTargetColorFormat(meta, &colorFormat));
 
+    if (!strcasecmp("OMX.Nvidia.h264.encoder", mComponentName)) {
+        colorFormat = OMX_COLOR_FormatYUV420Planar;
+    }
+
     status_t err;
     OMX_PARAM_PORTDEFINITIONTYPE def;
     OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
@@ -1193,6 +1212,10 @@
     h264type.bMBAFF = OMX_FALSE;
     h264type.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterEnable;
 
+    if (!strcasecmp("OMX.Nvidia.h264.encoder", mComponentName)) {
+        h264type.eLevel = OMX_VIDEO_AVCLevelMax;
+    }
+
     err = mOMX->setParameter(
             mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type));
     CHECK_EQ(err, OK);
diff --git a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
index 389180c..52a391f 100644
--- a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
+++ b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
@@ -338,10 +338,15 @@
 
     MediaBuffer *outputBuffer;
     CHECK_EQ(OK, mGroup->acquire_buffer(&outputBuffer));
+    uint8_t *outPtr = (uint8_t *) outputBuffer->data();
+    uint32_t dataLength = outputBuffer->size();
 
-    // Add 4 bytes for the start code 0x00000001
-    uint8_t *outPtr = (uint8_t *) outputBuffer->data() + 4;
-    uint32_t dataLength = outputBuffer->size() - 4;
+    if (!mSpsPpsHeaderReceived && mNumInputFrames < 0) {
+        // 4 bytes are reserved for holding the start code 0x00000001
+        // of the sequence parameter set at the beginning.
+        outPtr += 4;
+        dataLength -= 4;
+    }
 
     int32_t type;
     AVCEnc_Status encoderStatus = AVCENC_SUCCESS;
@@ -358,7 +363,7 @@
             switch (type) {
                 case AVC_NALTYPE_SPS:
                     ++mNumInputFrames;
-                    memcpy(outputBuffer->data(), "\x00\x00\x00\x01", 4);
+                    memcpy((uint8_t *)outputBuffer->data(), "\x00\x00\x00\x01", 4);
                     outputBuffer->set_range(0, dataLength + 4);
                     outPtr += (dataLength + 4);  // 4 bytes for next start code
                     dataLength = outputBuffer->size() -
diff --git a/media/libstagefright/colorconversion/Android.mk b/media/libstagefright/colorconversion/Android.mk
index 4a924c8..2b63235 100644
--- a/media/libstagefright/colorconversion/Android.mk
+++ b/media/libstagefright/colorconversion/Android.mk
@@ -6,7 +6,8 @@
         SoftwareRenderer.cpp
 
 LOCAL_C_INCLUDES := \
-        $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
+        $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
+        $(TOP)/hardware/msm7k
 
 LOCAL_SHARED_LIBRARIES :=       \
         libbinder               \
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 6d1dd25..507fa5a 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -26,6 +26,9 @@
 #include <ui/android_native_buffer.h>
 #include <ui/GraphicBufferMapper.h>
 
+// XXX: Temporary hack to allow referencing the _ADRENO pixel format here.
+#include <libgralloc-qsd8k/gralloc_priv.h>
+
 namespace android {
 
 SoftwareRenderer::SoftwareRenderer(
diff --git a/media/libstagefright/include/ARTSPController.h b/media/libstagefright/include/ARTSPController.h
index 55efd41..2542e4e 100644
--- a/media/libstagefright/include/ARTSPController.h
+++ b/media/libstagefright/include/ARTSPController.h
@@ -19,6 +19,7 @@
 #define A_RTSP_CONTROLLER_H_
 
 #include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AHandlerReflector.h>
 #include <media/stagefright/MediaExtractor.h>
 
 namespace android {
@@ -38,12 +39,32 @@
     virtual sp<MetaData> getTrackMetaData(
             size_t index, uint32_t flags);
 
+    void onMessageReceived(const sp<AMessage> &msg);
+
 protected:
     virtual ~ARTSPController();
 
 private:
+    enum {
+        kWhatConnectDone    = 'cdon',
+        kWhatDisconnectDone = 'ddon',
+    };
+
+    enum State {
+        DISCONNECTED,
+        CONNECTED,
+        CONNECTING,
+    };
+
+    Mutex mLock;
+    Condition mCondition;
+
+    State mState;
+    status_t mConnectionResult;
+
     sp<ALooper> mLooper;
     sp<MyHandler> mHandler;
+    sp<AHandlerReflector<ARTSPController> > mReflector;
 
     DISALLOW_EVIL_CONSTRUCTORS(ARTSPController);
 };
diff --git a/media/libstagefright/rtsp/ARTSPController.cpp b/media/libstagefright/rtsp/ARTSPController.cpp
index 195323e..ceae3a6 100644
--- a/media/libstagefright/rtsp/ARTSPController.cpp
+++ b/media/libstagefright/rtsp/ARTSPController.cpp
@@ -26,31 +26,57 @@
 namespace android {
 
 ARTSPController::ARTSPController(const sp<ALooper> &looper)
-    : mLooper(looper) {
+    : mState(DISCONNECTED),
+      mLooper(looper) {
+    mReflector = new AHandlerReflector<ARTSPController>(this);
+    looper->registerHandler(mReflector);
 }
 
 ARTSPController::~ARTSPController() {
+    disconnect();
+    mLooper->unregisterHandler(mReflector->id());
 }
 
 status_t ARTSPController::connect(const char *url) {
-    if (mHandler != NULL) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mState != DISCONNECTED) {
         return ERROR_ALREADY_CONNECTED;
     }
 
+    sp<AMessage> msg = new AMessage(kWhatConnectDone, mReflector->id());
+
     mHandler = new MyHandler(url, mLooper);
-    mHandler->connect();
 
-    sleep(10);
+    mState = CONNECTING;
 
-    return OK;
+    mHandler->connect(msg);
+
+    while (mState == CONNECTING) {
+        mCondition.wait(mLock);
+    }
+
+    if (mState != CONNECTED) {
+        mHandler.clear();
+    }
+
+    return mConnectionResult;
 }
 
 void ARTSPController::disconnect() {
-    if (mHandler == NULL) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mState != CONNECTED) {
         return;
     }
 
-    mHandler->disconnect();
+    sp<AMessage> msg = new AMessage(kWhatDisconnectDone, mReflector->id());
+    mHandler->disconnect(msg);
+
+    while (mState == CONNECTED) {
+        mCondition.wait(mLock);
+    }
+
     mHandler.clear();
 }
 
@@ -75,4 +101,31 @@
     return mHandler->getPacketSource(index)->getFormat();
 }
 
+void ARTSPController::onMessageReceived(const sp<AMessage> &msg) {
+    switch (msg->what()) {
+        case kWhatConnectDone:
+        {
+            Mutex::Autolock autoLock(mLock);
+
+            CHECK(msg->findInt32("result", &mConnectionResult));
+            mState = (mConnectionResult == OK) ? CONNECTED : DISCONNECTED;
+
+            mCondition.signal();
+            break;
+        }
+
+        case kWhatDisconnectDone:
+        {
+            Mutex::Autolock autoLock(mLock);
+            mState = DISCONNECTED;
+            mCondition.signal();
+            break;
+        }
+
+        default:
+            TRESPASS();
+            break;
+    }
+}
+
 }  // namespace android
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 3e75ffe..b2419bf 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -45,18 +45,21 @@
                           PRIORITY_HIGHEST);
     }
 
-    void connect() {
+    void connect(const sp<AMessage> &doneMsg) {
+        mDoneMsg = doneMsg;
+
         mLooper->registerHandler(this);
         mLooper->registerHandler(mConn);
         (1 ? mNetLooper : mLooper)->registerHandler(mRTPConn);
-        sp<AMessage> reply = new AMessage('conn', id());
 
+        sp<AMessage> reply = new AMessage('conn', id());
         mConn->connect(mSessionURL.c_str(), reply);
     }
 
-    void disconnect() {
-        sp<AMessage> reply = new AMessage('disc', id());
-        mConn->disconnect(reply);
+    void disconnect(const sp<AMessage> &doneMsg) {
+        mDoneMsg = doneMsg;
+
+        (new AMessage('abor', id()))->post();
     }
 
     virtual void onMessageReceived(const sp<AMessage> &msg) {
@@ -250,8 +253,9 @@
 
                     CHECK_EQ(response->mStatusCode, 200u);
 
-                    sp<AMessage> msg = new AMessage('abor', id());
-                    msg->post(60000000ll);
+                    mDoneMsg->setInt32("result", OK);
+                    mDoneMsg->post();
+                    mDoneMsg = NULL;
                 } else {
                     sp<AMessage> reply = new AMessage('disc', id());
                     mConn->disconnect(reply);
@@ -301,6 +305,11 @@
 
             case 'quit':
             {
+                if (mDoneMsg != NULL) {
+                    mDoneMsg->setInt32("result", UNKNOWN_ERROR);
+                    mDoneMsg->post();
+                    mDoneMsg = NULL;
+                }
                 break;
             }
 
@@ -380,6 +389,8 @@
     };
     Vector<TrackInfo> mTracks;
 
+    sp<AMessage> mDoneMsg;
+
     void setupTrack(size_t index) {
         sp<APacketSource> source =
             new APacketSource(mSessionDesc, index);
diff --git a/native/android/Android.mk b/native/android/Android.mk
index bd2b27a..cc35a3a 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -12,7 +12,8 @@
     looper.cpp \
     native_activity.cpp \
     native_window.cpp \
-    sensor.cpp
+    sensor.cpp \
+    storage_manager.cpp
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
@@ -23,6 +24,9 @@
     libsurfaceflinger_client \
     libandroid_runtime
 
+LOCAL_STATIC_LIBRARIES := \
+    libstorage
+
 LOCAL_C_INCLUDES += \
     frameworks/base/native/include \
     frameworks/base/core/jni/android \
diff --git a/native/android/storage_manager.cpp b/native/android/storage_manager.cpp
new file mode 100644
index 0000000..6dbe746
--- /dev/null
+++ b/native/android/storage_manager.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "NStorage"
+
+#include <android/storage_manager.h>
+#include <storage/IMountService.h>
+
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+
+using namespace android;
+
+struct ObbActionListener : public BnObbActionListener {
+private:
+    sp<AStorageManager> mStorageManager;
+
+public:
+    ObbActionListener(AStorageManager* mgr) :
+            mStorageManager(mgr)
+    {}
+
+    virtual void onObbResult(const android::String16& filename, const android::String16& state) {
+        LOGD("Got obb result (%s, %s)\n", String8(filename).string(), String8(state).string());
+    }
+};
+
+struct AStorageManager : public RefBase {
+protected:
+    void* mObbCallback;
+    sp<ObbActionListener> mObbActionListener;
+    sp<IMountService> mMountService;
+
+public:
+    AStorageManager() :
+            mObbCallback(NULL)
+    {
+    }
+
+    bool initialize() {
+        sp<IServiceManager> sm = defaultServiceManager();
+        if (sm == NULL) {
+            LOGE("Couldn't get default ServiceManager\n");
+            return false;
+        }
+
+        mMountService = interface_cast<IMountService>(sm->getService(String16("mount")));
+        if (mMountService == NULL) {
+            LOGE("Couldn't get connection to MountService\n");
+            return false;
+        }
+
+        mObbActionListener = new ObbActionListener(this);
+
+        return true;
+    }
+
+    void setObbCallback(void* cb) {
+        mObbCallback = cb;
+    }
+
+    void mountObb(const char* filename, const char* key) {
+        String16 filename16(filename);
+        String16 key16(key);
+        mMountService->mountObb(filename16, key16, mObbActionListener);
+    }
+
+    void unmountObb(const char* filename, const bool force) {
+        String16 filename16(filename);
+        mMountService->unmountObb(filename16, force);
+    }
+
+    int isObbMounted(const char* filename) {
+        String16 filename16(filename);
+        return mMountService->isObbMounted(filename16);
+    }
+
+    const char* getMountedObbPath(const char* filename) {
+        String16 filename16(filename);
+        String16 path16;
+        if (mMountService->getMountedObbPath(filename16, path16)) {
+            return String8(path16).string();
+        } else {
+            return NULL;
+        }
+    }
+};
+
+
+AStorageManager* AStorageManager_new() {
+    sp<AStorageManager> mgr = new AStorageManager();
+    if (mgr == NULL || !mgr->initialize()) {
+        return NULL;
+    }
+    mgr->incStrong((void*)AStorageManager_new);
+    return static_cast<AStorageManager*>(mgr.get());
+}
+
+void AStorageManager_delete(AStorageManager* mgr) {
+    if (mgr) {
+        mgr->decStrong((void*)AStorageManager_new);
+    }
+}
+
+void AStorageManager_setObbCallback(AStorageManager* mgr, void* cb) {
+    mgr->setObbCallback(cb);
+}
+
+void AStorageManager_mountObb(AStorageManager* mgr, const char* filename, const char* key) {
+    mgr->mountObb(filename, key);
+}
+
+void AStorageManager_unmountObb(AStorageManager* mgr, const char* filename, const int force) {
+    mgr->unmountObb(filename, force != 0);
+}
+
+int AStorageManager_isObbMounted(AStorageManager* mgr, const char* filename) {
+    return mgr->isObbMounted(filename) != 0;
+}
+
+const char* AStorageManager_getMountedObbPath(AStorageManager* mgr, const char* filename) {
+    return mgr->getMountedObbPath(filename);
+}
diff --git a/native/include/android/storage_manager.h b/native/include/android/storage_manager.h
new file mode 100644
index 0000000..bbed8a4
--- /dev/null
+++ b/native/include/android/storage_manager.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef ANDROID_STORAGE_MANAGER_H
+#define ANDROID_STORAGE_MANAGER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AStorageManager;
+typedef struct AStorageManager AStorageManager;
+
+
+/**
+ * Obtains a new instance of AStorageManager.
+ */
+AStorageManager* AStorageManager_new();
+
+/**
+ * Release AStorageManager instance.
+ */
+void AStorageManager_delete(AStorageManager* mgr);
+
+/**
+ * Callback to call when requested OBB is complete.
+ */
+void AStorageManager_setObbCallback(AStorageManager* mgr, void* cb);
+
+/**
+ * Attempts to mount an OBB file.
+ */
+void AStorageManager_mountObb(AStorageManager* mgr, const char* filename, const char* key);
+
+/**
+ * Attempts to unmount an OBB file.
+ */
+void AStorageManager_unmountObb(AStorageManager* mgr, const char* filename, const int force);
+
+/**
+ * Check whether an OBB is mounted.
+ */
+int AStorageManager_isObbMounted(AStorageManager* mgr, const char* filename);
+
+/**
+ * Get the mounted path for an OBB.
+ */
+const char* AStorageManager_getMountedObbPath(AStorageManager* mgr, const char* filename);
+
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif      // ANDROID_PACKAGE_MANAGER_H
diff --git a/packages/SystemUI/res/drawable-mdpi/battery_0.png b/packages/SystemUI/res/drawable-mdpi/battery_0.png
index b5d36cc..77162c8 100644
--- a/packages/SystemUI/res/drawable-mdpi/battery_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/battery_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/battery_100.png b/packages/SystemUI/res/drawable-mdpi/battery_100.png
index 75cc409..588a74b 100644
--- a/packages/SystemUI/res/drawable-mdpi/battery_100.png
+++ b/packages/SystemUI/res/drawable-mdpi/battery_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/battery_20.png b/packages/SystemUI/res/drawable-mdpi/battery_20.png
deleted file mode 100644
index c0d0030..0000000
--- a/packages/SystemUI/res/drawable-mdpi/battery_20.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/battery_25.png b/packages/SystemUI/res/drawable-mdpi/battery_25.png
new file mode 100644
index 0000000..b11570b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/battery_25.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/battery_40.png b/packages/SystemUI/res/drawable-mdpi/battery_40.png
deleted file mode 100644
index e301c08..0000000
--- a/packages/SystemUI/res/drawable-mdpi/battery_40.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/battery_50.png b/packages/SystemUI/res/drawable-mdpi/battery_50.png
new file mode 100644
index 0000000..94d7eca
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/battery_50.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/battery_60.png b/packages/SystemUI/res/drawable-mdpi/battery_60.png
deleted file mode 100644
index 0fde1fa..0000000
--- a/packages/SystemUI/res/drawable-mdpi/battery_60.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/battery_75.png b/packages/SystemUI/res/drawable-mdpi/battery_75.png
new file mode 100644
index 0000000..3cb3591
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/battery_75.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/battery_80.png b/packages/SystemUI/res/drawable-mdpi/battery_80.png
deleted file mode 100644
index 15c4e1c..0000000
--- a/packages/SystemUI/res/drawable-mdpi/battery_80.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/signal_0.png b/packages/SystemUI/res/drawable-mdpi/signal_0.png
index 6533677..cf436ad 100644
--- a/packages/SystemUI/res/drawable-mdpi/signal_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/signal_100.png b/packages/SystemUI/res/drawable-mdpi/signal_100.png
index e8976a2..0011a1b 100644
--- a/packages/SystemUI/res/drawable-mdpi/signal_100.png
+++ b/packages/SystemUI/res/drawable-mdpi/signal_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/signal_20.png b/packages/SystemUI/res/drawable-mdpi/signal_20.png
deleted file mode 100644
index 651e2a9..0000000
--- a/packages/SystemUI/res/drawable-mdpi/signal_20.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/signal_25.png b/packages/SystemUI/res/drawable-mdpi/signal_25.png
new file mode 100644
index 0000000..69c643f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/signal_25.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/signal_40.png b/packages/SystemUI/res/drawable-mdpi/signal_40.png
deleted file mode 100644
index 6ba7906..0000000
--- a/packages/SystemUI/res/drawable-mdpi/signal_40.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/signal_50.png b/packages/SystemUI/res/drawable-mdpi/signal_50.png
new file mode 100644
index 0000000..c8acd72
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/signal_50.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/signal_60.png b/packages/SystemUI/res/drawable-mdpi/signal_60.png
deleted file mode 100644
index 6d2e812..0000000
--- a/packages/SystemUI/res/drawable-mdpi/signal_60.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/signal_75.png b/packages/SystemUI/res/drawable-mdpi/signal_75.png
new file mode 100644
index 0000000..9650dfa
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/signal_75.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/signal_80.png b/packages/SystemUI/res/drawable-mdpi/signal_80.png
deleted file mode 100644
index a152623..0000000
--- a/packages/SystemUI/res/drawable-mdpi/signal_80.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_back_default.png b/packages/SystemUI/res/drawable-mdpi/status_bar_back_default.png
index dd64746..5c57802 100644
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_back_default.png
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_back_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_back_pressed.png b/packages/SystemUI/res/drawable-mdpi/status_bar_back_pressed.png
index 66a3677..5c57802 100644
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_back_pressed.png
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_back_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_expand_default.png b/packages/SystemUI/res/drawable-mdpi/status_bar_expand_default.png
index 4d19717..b2a94b6 100644
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_expand_default.png
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_expand_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_expand_pressed.png b/packages/SystemUI/res/drawable-mdpi/status_bar_expand_pressed.png
index 830cbd5..b2a94b6 100644
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_expand_pressed.png
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_expand_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_home_default.png b/packages/SystemUI/res/drawable-mdpi/status_bar_home_default.png
index b129210..f219ded 100644
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_home_default.png
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_home_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_home_pressed.png b/packages/SystemUI/res/drawable-mdpi/status_bar_home_pressed.png
index dcb2447..f219ded 100644
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_home_pressed.png
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_home_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_icon_tray.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_icon_tray.9.png
index 07d00cb..502acce 100644
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_icon_tray.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_icon_tray.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_recent_default.png b/packages/SystemUI/res/drawable-mdpi/status_bar_recent_default.png
new file mode 100644
index 0000000..4dd8dc7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_recent_default.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_recent_pressed.png b/packages/SystemUI/res/drawable-mdpi/status_bar_recent_pressed.png
new file mode 100644
index 0000000..4dd8dc7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/status_bar_recent_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/battery.xml b/packages/SystemUI/res/drawable/battery.xml
index c2294d1..f4a720d 100644
--- a/packages/SystemUI/res/drawable/battery.xml
+++ b/packages/SystemUI/res/drawable/battery.xml
@@ -23,13 +23,12 @@
     <item android:maxLevel="5">
         <animation-list android:oneshot="false">
             <item android:drawable="@drawable/battery_0" android:duration="250" />
-            <item android:drawable="@drawable/battery_20" android:duration="250" />
+            <item android:drawable="@drawable/battery_25" android:duration="250" />
         </animation-list>
     </item>
-    <item android:maxLevel="20" android:drawable="@drawable/battery_20" />
-    <item android:maxLevel="40" android:drawable="@drawable/battery_40" />
-    <item android:maxLevel="60" android:drawable="@drawable/battery_60" />
-    <item android:maxLevel="80" android:drawable="@drawable/battery_80" />
+    <item android:maxLevel="25" android:drawable="@drawable/battery_25" />
+    <item android:maxLevel="50" android:drawable="@drawable/battery_50" />
+    <item android:maxLevel="75" android:drawable="@drawable/battery_75" />
     <item android:maxLevel="101" android:drawable="@drawable/battery_100" />
 </level-list>
 
diff --git a/packages/SystemUI/res/drawable/battery_charging.xml b/packages/SystemUI/res/drawable/battery_charging.xml
index 2fd0c6d..c9b77dd 100644
--- a/packages/SystemUI/res/drawable/battery_charging.xml
+++ b/packages/SystemUI/res/drawable/battery_charging.xml
@@ -19,33 +19,27 @@
 -->
 
 <level-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:maxLevel="20">
+    <item android:maxLevel="25">
         <animation-list android:oneshot="false">
             <item android:drawable="@drawable/battery_0" android:duration="1000" />
-            <item android:drawable="@drawable/battery_20" android:duration="1000" />
+            <item android:drawable="@drawable/battery_25" android:duration="1000" />
         </animation-list>
     </item>
-    <item android:maxLevel="40">
+    <item android:maxLevel="50">
         <animation-list android:oneshot="false">
-            <item android:drawable="@drawable/battery_20" android:duration="1000" />
-            <item android:drawable="@drawable/battery_40" android:duration="1000" />
+            <item android:drawable="@drawable/battery_25" android:duration="1000" />
+            <item android:drawable="@drawable/battery_50" android:duration="1000" />
         </animation-list>
     </item>
-    <item android:maxLevel="60">
+    <item android:maxLevel="75">
         <animation-list android:oneshot="false">
-            <item android:drawable="@drawable/battery_40" android:duration="1000" />
-            <item android:drawable="@drawable/battery_60" android:duration="1000" />
-        </animation-list>
-    </item>
-    <item android:maxLevel="80">
-        <animation-list android:oneshot="false">
-            <item android:drawable="@drawable/battery_60" android:duration="1000" />
-            <item android:drawable="@drawable/battery_80" android:duration="1000" />
+            <item android:drawable="@drawable/battery_50" android:duration="1000" />
+            <item android:drawable="@drawable/battery_75" android:duration="1000" />
         </animation-list>
     </item>
     <item android:maxLevel="92">
         <animation-list android:oneshot="false">
-            <item android:drawable="@drawable/battery_80" android:duration="1000" />
+            <item android:drawable="@drawable/battery_75" android:duration="1000" />
             <item android:drawable="@drawable/battery_100" android:duration="1000" />
         </animation-list>
     </item>
diff --git a/packages/SystemUI/res/drawable/signal.xml b/packages/SystemUI/res/drawable/signal.xml
index 8b4f56b..5aa211a 100644
--- a/packages/SystemUI/res/drawable/signal.xml
+++ b/packages/SystemUI/res/drawable/signal.xml
@@ -20,10 +20,9 @@
 
 <level-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:maxLevel="01" android:drawable="@drawable/signal_0" />
-    <item android:maxLevel="20" android:drawable="@drawable/signal_20" />
-    <item android:maxLevel="40" android:drawable="@drawable/signal_40" />
-    <item android:maxLevel="60" android:drawable="@drawable/signal_60" />
-    <item android:maxLevel="80" android:drawable="@drawable/signal_80" />
+    <item android:maxLevel="25" android:drawable="@drawable/signal_25" />
+    <item android:maxLevel="50" android:drawable="@drawable/signal_50" />
+    <item android:maxLevel="75" android:drawable="@drawable/signal_75" />
     <item android:maxLevel="101" android:drawable="@drawable/signal_100" />
 
 </level-list>
diff --git a/services/camera/libcameraservice/CameraHardwareStub.cpp b/services/camera/libcameraservice/CameraHardwareStub.cpp
index b3e0ee6..07b5a37 100644
--- a/services/camera/libcameraservice/CameraHardwareStub.cpp
+++ b/services/camera/libcameraservice/CameraHardwareStub.cpp
@@ -101,9 +101,9 @@
     mFakeCamera = 0; // paranoia
 }
 
-sp<IMemoryHeap> CameraHardwareStub::getPreviewHeap() const
+status_t CameraHardwareStub::setPreviewWindow(const sp<ANativeWindow>& buf)
 {
-    return mPreviewHeap;
+    return NO_ERROR;
 }
 
 sp<IMemoryHeap> CameraHardwareStub::getRawHeap() const
diff --git a/services/camera/libcameraservice/CameraHardwareStub.h b/services/camera/libcameraservice/CameraHardwareStub.h
index d3427ba..9b66a76 100644
--- a/services/camera/libcameraservice/CameraHardwareStub.h
+++ b/services/camera/libcameraservice/CameraHardwareStub.h
@@ -29,7 +29,7 @@
 
 class CameraHardwareStub : public CameraHardwareInterface {
 public:
-    virtual sp<IMemoryHeap> getPreviewHeap() const;
+    virtual status_t setPreviewWindow(const sp<ANativeWindow>& buf);
     virtual sp<IMemoryHeap> getRawHeap() const;
 
     virtual void        setCallbacks(notify_callback notify_cb,
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index ea2c5d4..c6a9909 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -336,16 +336,9 @@
     int callingPid = getCallingPid();
     LOG1("Client::~Client E (pid %d, this %p)", callingPid, this);
 
-    if (mSurface != 0 && !mUseOverlay) {
-        pthread_t thr;
-        // We unregister the buffers in a different thread because binder does
-        // not let us make sychronous transactions in a binder destructor (that
-        // is, upon our reaching a refcount of zero.)
-        pthread_create(&thr,
-                       NULL,  // attr
-                       unregister_surface,
-                       mSurface.get());
-        pthread_join(thr, NULL);
+    // Clean up the ANativeWindow
+    if (mSurface != 0) {
+        setPreviewDisplay(0);
     }
 
     // set mClientPid to let disconnet() tear down the hardware
@@ -465,6 +458,11 @@
     if (mUseOverlay) {
         mOverlayRef = 0;
     }
+    // Release the held ANativeWindow resources.
+    if (mPreviewWindow != 0) {
+        mPreviewWindow = 0;
+        mHardware->setPreviewWindow(mPreviewWindow);
+    }
     mHardware.clear();
 
     mCameraService->removeClient(mCameraClient);
@@ -475,8 +473,8 @@
 
 // ----------------------------------------------------------------------------
 
-// set the ISurface that the preview will use
-status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface) {
+// set the Surface that the preview will use
+status_t CameraService::Client::setPreviewDisplay(const sp<Surface>& surface) {
     LOG1("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid());
     Mutex::Autolock lock(mLock);
     status_t result = checkPidAndHardware();
@@ -486,7 +484,7 @@
 
     // return if no change in surface.
     // asBinder() is safe on NULL (returns NULL)
-    if (surface->asBinder() == mSurface->asBinder()) {
+    if (getISurface(surface)->asBinder() == mSurface->asBinder()) {
         return result;
     }
 
@@ -496,44 +494,28 @@
             // Force the destruction of any previous overlay
             sp<Overlay> dummy;
             mHardware->setOverlay(dummy);
-        } else {
-            mSurface->unregisterBuffers();
         }
     }
-    mSurface = surface;
+    if (surface != 0) {
+        mSurface = getISurface(surface);
+    } else {
+        mSurface = 0;
+    }
+    mPreviewWindow = surface;
     mOverlayRef = 0;
     // If preview has been already started, set overlay or register preview
     // buffers now.
     if (mHardware->previewEnabled()) {
         if (mUseOverlay) {
             result = setOverlay();
-        } else if (mSurface != 0) {
-            result = registerPreviewBuffers();
+        } else if (mPreviewWindow != 0) {
+            result = mHardware->setPreviewWindow(mPreviewWindow);
         }
     }
 
     return result;
 }
 
-status_t CameraService::Client::registerPreviewBuffers() {
-    int w, h;
-    CameraParameters params(mHardware->getParameters());
-    params.getPreviewSize(&w, &h);
-
-    // FIXME: don't use a hardcoded format here.
-    ISurface::BufferHeap buffers(w, h, w, h,
-                                 HAL_PIXEL_FORMAT_YCrCb_420_SP,
-                                 mOrientation,
-                                 0,
-                                 mHardware->getPreviewHeap());
-
-    status_t result = mSurface->registerBuffers(buffers);
-    if (result != NO_ERROR) {
-        LOGE("registerBuffers failed with status %d", result);
-    }
-    return result;
-}
-
 status_t CameraService::Client::setOverlay() {
     int w, h;
     CameraParameters params(mHardware->getParameters());
@@ -624,14 +606,14 @@
 
     switch(mode) {
         case CAMERA_PREVIEW_MODE:
-            if (mSurface == 0) {
+            if (mSurface == 0 && mPreviewWindow == 0) {
                 LOG1("mSurface is not set yet.");
                 // still able to start preview in this case.
             }
             return startPreviewMode();
         case CAMERA_RECORDING_MODE:
-            if (mSurface == 0) {
-                LOGE("mSurface must be set before startRecordingMode.");
+            if (mSurface == 0 && mPreviewWindow == 0) {
+                LOGE("mSurface or mPreviewWindow must be set before startRecordingMode.");
                 return INVALID_OPERATION;
             }
             return startRecordingMode();
@@ -657,16 +639,10 @@
         if (result != NO_ERROR) return result;
         result = mHardware->startPreview();
     } else {
+        // XXX: Set the orientation of the ANativeWindow.
+        mHardware->setPreviewWindow(mPreviewWindow);
         enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
         result = mHardware->startPreview();
-        if (result != NO_ERROR) return result;
-        // If preview display has been set, register preview buffers now.
-        if (mSurface != 0) {
-           // Unregister here because the surface may be previously registered
-           // with the raw (snapshot) heap.
-           mSurface->unregisterBuffers();
-           result = registerPreviewBuffers();
-        }
     }
     return result;
 }
@@ -704,13 +680,10 @@
     Mutex::Autolock lock(mLock);
     if (checkPidAndHardware() != NO_ERROR) return;
 
+
     disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
     mHardware->stopPreview();
 
-    if (mSurface != 0 && !mUseOverlay) {
-        mSurface->unregisterBuffers();
-    }
-
     mPreviewBuffer.clear();
 }
 
@@ -998,11 +971,6 @@
 void CameraService::Client::handleShutter(image_rect_type *size) {
     mCameraService->playSound(SOUND_SHUTTER);
 
-    // Screen goes black after the buffer is unregistered.
-    if (mSurface != 0 && !mUseOverlay) {
-        mSurface->unregisterBuffers();
-    }
-
     sp<ICameraClient> c = mCameraClient;
     if (c != 0) {
         mLock.unlock();
@@ -1030,7 +998,6 @@
             HAL_PIXEL_FORMAT_YCrCb_420_SP, mOrientation, 0,
             mHardware->getRawHeap());
 
-        mSurface->registerBuffers(buffers);
         IPCThreadState::self()->flushCommands();
     }
 
@@ -1043,12 +1010,6 @@
     size_t size;
     sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
 
-    if (!mUseOverlay) {
-        if (mSurface != 0) {
-            mSurface->postBuffer(offset);
-        }
-    }
-
     // local copy of the callback flags
     int flags = mPreviewCallbackFlag;
 
@@ -1108,11 +1069,6 @@
     size_t size;
     sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
 
-    // Put the YUV version of the snapshot in the preview display.
-    if (mSurface != 0 && !mUseOverlay) {
-        mSurface->postBuffer(offset);
-    }
-
     sp<ICameraClient> c = mCameraClient;
     mLock.unlock();
     if (c != 0) {
@@ -1270,4 +1226,12 @@
     return NO_ERROR;
 }
 
+sp<ISurface> CameraService::getISurface(const sp<Surface>& surface) {
+    if (surface != 0) {
+        return surface->getISurface();
+    } else {
+        return sp<ISurface>(0);
+    }
+}
+
 }; // namespace android
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 0d69836..7ed192e 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -79,6 +79,12 @@
     sp<MediaPlayer>     mSoundPlayer[NUM_SOUNDS];
     int                 mSoundRef;  // reference count (release all MediaPlayer when 0)
 
+    // Used by Client objects to extract the ISurface from a Surface object.
+    // This is used because making Client a friend class of Surface would
+    // require including this header in Surface.h since Client is a nested
+    // class.
+    static sp<ISurface> getISurface(const sp<Surface>& surface);
+
     class Client : public BnCamera
     {
     public:
@@ -87,7 +93,7 @@
         virtual status_t        connect(const sp<ICameraClient>& client);
         virtual status_t        lock();
         virtual status_t        unlock();
-        virtual status_t        setPreviewDisplay(const sp<ISurface>& surface);
+        virtual status_t        setPreviewDisplay(const sp<Surface>& surface);
         virtual void            setPreviewCallbackFlag(int flag);
         virtual status_t        startPreview();
         virtual void            stopPreview();
@@ -169,6 +175,7 @@
         // Ensures atomicity among the public methods
         mutable Mutex                   mLock;
         sp<ISurface>                    mSurface;
+        sp<ANativeWindow>               mPreviewWindow;
 
         // If the user want us to return a copy of the preview frame (instead
         // of the original one), we allocate mPreviewBuffer and reuse it if possible.
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 9f8557f..8b02355 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -357,7 +357,7 @@
      */
     public boolean pingSupplicant() {
         enforceAccessPermission();
-        return mWifiStateMachine.pingSupplicant();
+        return mWifiStateMachine.syncPingSupplicant();
     }
 
     /**
@@ -436,7 +436,7 @@
      */
     public int getWifiEnabledState() {
         enforceAccessPermission();
-        return mWifiStateMachine.getWifiState();
+        return mWifiStateMachine.syncGetWifiState();
     }
 
     /**
@@ -481,7 +481,7 @@
      */
     public int getWifiApEnabledState() {
         enforceAccessPermission();
-        return mWifiStateMachine.getWifiApState();
+        return mWifiStateMachine.syncGetWifiApState();
     }
 
     /**
@@ -555,7 +555,7 @@
      */
     public List<WifiConfiguration> getConfiguredNetworks() {
         enforceAccessPermission();
-        return mWifiStateMachine.getConfiguredNetworks();
+        return mWifiStateMachine.syncGetConfiguredNetworks();
     }
 
     /**
@@ -565,7 +565,7 @@
      */
     public int addOrUpdateNetwork(WifiConfiguration config) {
         enforceChangePermission();
-        return mWifiStateMachine.addOrUpdateNetwork(config);
+        return mWifiStateMachine.syncAddOrUpdateNetwork(config);
     }
 
      /**
@@ -576,7 +576,7 @@
      */
     public boolean removeNetwork(int netId) {
         enforceChangePermission();
-        return mWifiStateMachine.removeNetwork(netId);
+        return mWifiStateMachine.syncRemoveNetwork(netId);
     }
 
     /**
@@ -588,7 +588,7 @@
      */
     public boolean enableNetwork(int netId, boolean disableOthers) {
         enforceChangePermission();
-        return mWifiStateMachine.enableNetwork(netId, disableOthers);
+        return mWifiStateMachine.syncEnableNetwork(netId, disableOthers);
     }
 
     /**
@@ -599,7 +599,7 @@
      */
     public boolean disableNetwork(int netId) {
         enforceChangePermission();
-        return mWifiStateMachine.disableNetwork(netId);
+        return mWifiStateMachine.syncDisableNetwork(netId);
     }
 
     /**
@@ -612,7 +612,7 @@
          * Make sure we have the latest information, by sending
          * a status request to the supplicant.
          */
-        return mWifiStateMachine.requestConnectionInfo();
+        return mWifiStateMachine.syncRequestConnectionInfo();
     }
 
     /**
@@ -622,7 +622,7 @@
      */
     public List<ScanResult> getScanResults() {
         enforceAccessPermission();
-        return mWifiStateMachine.getScanResultsList();
+        return mWifiStateMachine.syncGetScanResultsList();
     }
 
     /**
@@ -634,7 +634,7 @@
     public boolean saveConfiguration() {
         boolean result = true;
         enforceChangePermission();
-        return mWifiStateMachine.saveConfig();
+        return mWifiStateMachine.syncSaveConfig();
     }
 
     /**
@@ -723,7 +723,7 @@
      */
     public DhcpInfo getDhcpInfo() {
         enforceAccessPermission();
-        return mWifiStateMachine.getDhcpInfo();
+        return mWifiStateMachine.syncGetDhcpInfo();
     }
 
     /**
@@ -823,7 +823,7 @@
                  * or plugged in to AC).
                  */
                 if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) {
-                    WifiInfo info = mWifiStateMachine.requestConnectionInfo();
+                    WifiInfo info = mWifiStateMachine.syncRequestConnectionInfo();
                     if (info.getSupplicantState() != SupplicantState.COMPLETED) {
                         // we used to go to sleep immediately, but this caused some race conditions
                         // we don't have time to track down for this release.  Delay instead,
@@ -1002,7 +1002,7 @@
                     + ", uid=" + Binder.getCallingUid());
             return;
         }
-        pw.println("Wi-Fi is " + mWifiStateMachine.getWifiStateByName());
+        pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
         pw.println("Stay-awake conditions: " +
                 Settings.System.getInt(mContext.getContentResolver(),
                                        Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0));
@@ -1012,7 +1012,7 @@
         pw.println(mWifiStateMachine);
         pw.println();
         pw.println("Latest scan results:");
-        List<ScanResult> scanResults = mWifiStateMachine.getScanResultsList();
+        List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
         if (scanResults != null && scanResults.size() != 0) {
             pw.println("  BSSID              Frequency   RSSI  Flags             SSID");
             for (ScanResult r : scanResults) {
@@ -1320,7 +1320,7 @@
         if ((state == NetworkInfo.State.DISCONNECTED)
                 || (state == NetworkInfo.State.UNKNOWN)) {
             // Look for an open network
-            List<ScanResult> scanResults = mWifiStateMachine.getScanResultsList();
+            List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
             if (scanResults != null) {
                 int numOpenNetworks = 0;
                 for (int i = scanResults.size() - 1; i >= 0; i--) {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 57f93c4..d5750c6 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -16,11 +16,6 @@
 
 package com.android.server;
 
-import static android.os.LocalPowerManager.CHEEK_EVENT;
-import static android.os.LocalPowerManager.OTHER_EVENT;
-import static android.os.LocalPowerManager.TOUCH_EVENT;
-import static android.os.LocalPowerManager.LONG_TOUCH_EVENT;
-import static android.os.LocalPowerManager.TOUCH_UP_EVENT;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
@@ -76,7 +71,6 @@
 import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.LatencyTimer;
 import android.os.LocalPowerManager;
 import android.os.Looper;
 import android.os.Message;
@@ -109,13 +103,11 @@
 import android.view.InputChannel;
 import android.view.InputDevice;
 import android.view.InputEvent;
-import android.view.InputQueue;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.SurfaceSession;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
@@ -127,9 +119,13 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Transformation;
 
+import java.io.BufferedReader;
 import java.io.BufferedWriter;
+import java.io.DataInputStream;
 import java.io.File;
 import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
@@ -164,8 +160,6 @@
     static final boolean DEBUG_WALLPAPER = false;
     static final boolean SHOW_TRANSACTIONS = false;
     static final boolean HIDE_STACK_CRAWLS = true;
-    static final boolean MEASURE_LATENCY = false;
-    static private LatencyTimer lt;
 
     static final boolean PROFILE_ORIENTATION = false;
     static final boolean BLUR = true;
@@ -603,10 +597,6 @@
 
     private WindowManagerService(Context context, PowerManagerService pm,
             boolean haveInputMethods) {
-        if (MEASURE_LATENCY) {
-            lt = new LatencyTimer(100, 1000);
-        }
-
         mContext = context;
         mHaveInputMethods = haveInputMethods;
         mLimitedAlphaCompositing = context.getResources().getBoolean(
@@ -9582,6 +9572,10 @@
         
         Surface.closeTransaction();
 
+        if (mWatermark != null) {
+            mWatermark.drawIfNeeded();
+        }
+
         if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
                 "With display frozen, orientationChangeComplete="
                 + orientationChangeComplete);
@@ -10067,12 +10061,17 @@
         mScreenFrozenLock.release();
     }
 
-    static int getPropertyInt(String name, int defUnits, int defDps, DisplayMetrics dm) {
-        String str = SystemProperties.get(name);
-        try {
-            int val = Integer.parseInt(str);
-            return val;
-        } catch (Exception e) {
+    static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
+            DisplayMetrics dm) {
+        if (index < tokens.length) {
+            String str = tokens[index];
+            if (str != null && str.length() > 0) {
+                try {
+                    int val = Integer.parseInt(str);
+                    return val;
+                } catch (Exception e) {
+                }
+            }
         }
         if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
             return defDps;
@@ -10082,62 +10081,142 @@
     }
 
     class Watermark {
-        Surface mSurface;
-        int mWidth;
-        int mHeight;
-        int mXPercent;
-        int mYPercent;
+        final String[] mTokens;
+        final String mText;
+        final Paint mTextPaint;
+        final int mTextWidth;
+        final int mTextHeight;
+        final int mTextAscent;
+        final int mTextDescent;
+        final int mDeltaX;
+        final int mDeltaY;
 
-        Watermark(SurfaceSession session, String text) {
+        Surface mSurface;
+        int mLastDW;
+        int mLastDH;
+        boolean mDrawNeeded;
+
+        Watermark(SurfaceSession session, String[] tokens) {
             final DisplayMetrics dm = new DisplayMetrics();
             mDisplay.getMetrics(dm);
 
-            int fontSize = getPropertyInt("ro.watermark.height",
-                    TypedValue.COMPLEX_UNIT_DIP, 48, dm);
-            mXPercent = getPropertyInt("ro.watermark.x",
-                    TypedValue.COMPLEX_UNIT_PX, 50, dm);
-            mYPercent = getPropertyInt("ro.watermark.y",
-                    TypedValue.COMPLEX_UNIT_PX, 99, dm);
-            int color = getPropertyInt("ro.watermark.color",
-                    TypedValue.COMPLEX_UNIT_PX, 0x80ffffff, dm);
-            int shadowRadius = getPropertyInt("ro.watermark.shadow.radius",
-                    TypedValue.COMPLEX_UNIT_PX, 5, dm);
-            int shadowDx = getPropertyInt("ro.watermark.shadow.dx",
-                    TypedValue.COMPLEX_UNIT_PX, 0, dm);
-            int shadowDy = getPropertyInt("ro.watermark.shadow.dy",
-                    TypedValue.COMPLEX_UNIT_PX, 0, dm);
-            int shadowColor = getPropertyInt("ro.watermark.shadow.color",
-                    TypedValue.COMPLEX_UNIT_PX, 0xff000000, dm);
+            if (false) {
+                Log.i(TAG, "*********************** WATERMARK");
+                for (int i=0; i<tokens.length; i++) {
+                    Log.i(TAG, "  TOKEN #" + i + ": " + tokens[i]);
+                }
+            }
 
-            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
-            paint.setTextSize(fontSize);
-            paint.setColor(color);
-            paint.setShadowLayer(shadowRadius, shadowDx, shadowDy, shadowColor);
-            paint.setTypeface(Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD));
+            mTokens = tokens;
 
-            FontMetricsInt fm = paint.getFontMetricsInt();
-            mHeight = fm.descent - fm.ascent + 20;
-            mWidth = (int)paint.measureText(text) + 20;
+            StringBuilder builder = new StringBuilder(32);
+            int len = mTokens[0].length();
+            len = len & ~1;
+            for (int i=0; i<len; i+=2) {
+                int c1 = mTokens[0].charAt(i);
+                int c2 = mTokens[0].charAt(i+1);
+                if (c1 >= 'a' && c1 <= 'f') c1 = c1 - 'a' + 10;
+                else if (c1 >= 'A' && c1 <= 'F') c1 = c1 - 'A' + 10;
+                else c1 -= '0';
+                if (c2 >= 'a' && c2 <= 'f') c2 = c2 - 'a' + 10;
+                else if (c2 >= 'A' && c2 <= 'F') c2 = c2 - 'A' + 10;
+                else c2 -= '0';
+                builder.append((char)(255-((c1*16)+c2)));
+            }
+            mText = builder.toString();
+            if (false) {
+                Log.i(TAG, "Final text: " + mText);
+            }
+
+            int fontSize = getPropertyInt(tokens, 1,
+                    TypedValue.COMPLEX_UNIT_DIP, 20, dm);
+
+            mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+            mTextPaint.setTextSize(fontSize);
+            mTextPaint.setTypeface(Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD));
+
+            FontMetricsInt fm = mTextPaint.getFontMetricsInt();
+            mTextWidth = (int)mTextPaint.measureText(mText);
+            mTextAscent = fm.ascent;
+            mTextDescent = fm.descent;
+            mTextHeight = fm.descent - fm.ascent;
+
+            mDeltaX = getPropertyInt(tokens, 2,
+                    TypedValue.COMPLEX_UNIT_PX, mTextWidth*2, dm);
+            mDeltaY = getPropertyInt(tokens, 3,
+                    TypedValue.COMPLEX_UNIT_PX, mTextHeight*3, dm);
+            int shadowColor = getPropertyInt(tokens, 4,
+                    TypedValue.COMPLEX_UNIT_PX, 0xb0000000, dm);
+            int color = getPropertyInt(tokens, 5,
+                    TypedValue.COMPLEX_UNIT_PX, 0x60ffffff, dm);
+            int shadowRadius = getPropertyInt(tokens, 6,
+                    TypedValue.COMPLEX_UNIT_PX, 7, dm);
+            int shadowDx = getPropertyInt(tokens, 8,
+                    TypedValue.COMPLEX_UNIT_PX, 0, dm);
+            int shadowDy = getPropertyInt(tokens, 9,
+                    TypedValue.COMPLEX_UNIT_PX, 0, dm);
+
+            mTextPaint.setColor(color);
+            mTextPaint.setShadowLayer(shadowRadius, shadowDx, shadowDy, shadowColor);
 
             try {
                 mSurface = new Surface(session, 0,
-                        "WatermarkSurface",
-                        -1, mWidth, mHeight, PixelFormat.TRANSLUCENT, 0);
+                        "WatermarkSurface", -1, 1, 1, PixelFormat.TRANSLUCENT, 0);
                 mSurface.setLayer(TYPE_LAYER_MULTIPLIER*100);
-                Rect dirty = new Rect(0, 0, mWidth, mHeight);
-                Canvas c = mSurface.lockCanvas(dirty);
-                c.drawText(text, 10, -fm.ascent+10, paint);
-                mSurface.unlockCanvasAndPost(c);
+                mSurface.setPosition(0, 0);
                 mSurface.show();
             } catch (OutOfResourcesException e) {
             }
         }
 
         void positionSurface(int dw, int dh) {
-            int availW = dw - mWidth;
-            int availH = dh - mHeight;
-            mSurface.setPosition((availW*mXPercent)/100,
-                    (availH*mYPercent)/100);
+            if (mLastDW != dw || mLastDH != dh) {
+                mLastDW = dw;
+                mLastDH = dh;
+                mSurface.setSize(dw, dh);
+                mDrawNeeded = true;
+            }
+        }
+
+        void drawIfNeeded() {
+            if (mDrawNeeded) {
+                final int dw = mLastDW;
+                final int dh = mLastDH;
+
+                mDrawNeeded = false;
+                Rect dirty = new Rect(0, 0, dw, dh);
+                Canvas c = null;
+                try {
+                    c = mSurface.lockCanvas(dirty);
+                } catch (IllegalArgumentException e) {
+                } catch (OutOfResourcesException e) {
+                }
+                if (c != null) {
+                    int deltaX = mDeltaX;
+                    int deltaY = mDeltaY;
+
+                    // deltaX shouldn't be close to a round fraction of our
+                    // x step, or else things will line up too much.
+                    int div = (dw+mTextWidth)/deltaX;
+                    int rem = (dw+mTextWidth) - (div*deltaX);
+                    int qdelta = deltaX/4;
+                    if (rem < qdelta || rem > (deltaX-qdelta)) {
+                        deltaX += deltaX/3;
+                    }
+
+                    int y = -mTextHeight;
+                    int x = -mTextWidth;
+                    while (y < (dh+mTextHeight)) {
+                        c.drawText(mText, x, y, mTextPaint);
+                        x += deltaX;
+                        if (x >= dw) {
+                            x -= (dw+mTextWidth);
+                            y += deltaY;
+                        }
+                    }
+                    mSurface.unlockCanvasAndPost(c);
+                }
+            }
         }
     }
 
@@ -10146,12 +10225,28 @@
             return;
         }
 
-        String text = SystemProperties.get("ro.watermark.text");
-        if (text == null || text.length() <= 0) {
-            return;
+        File file = new File("/system/etc/setup.conf");
+        FileInputStream in = null;
+        try {
+            in = new FileInputStream(file);
+            DataInputStream ind = new DataInputStream(in);
+            String line = ind.readLine();
+            if (line != null) {
+                String[] toks = line.split("%");
+                if (toks != null && toks.length > 0) {
+                    mWatermark = new Watermark(mFxSession, toks);
+                }
+            }
+        } catch (FileNotFoundException e) {
+        } catch (IOException e) {
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException e) {
+                }
+            }
         }
-
-        mWatermark = new Watermark(mFxSession, text);
     }
 
     @Override
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 63746e7b..56159b5 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4100,16 +4100,23 @@
         }
     }
 
-    void grantUriPermissionLocked(int callingUid,
-            String targetPkg, Uri uri, int modeFlags, ActivityRecord activity) {
+    /**
+     * Check if the targetPkg can be granted permission to access uri by
+     * the callingUid using the given modeFlags.  Throws a security exception
+     * if callingUid is not allowed to do this.  Returns the uid of the target
+     * if the URI permission grant should be performed; returns -1 if it is not
+     * needed (for example targetPkg already has permission to access the URI).
+     */
+    int checkGrantUriPermissionLocked(int callingUid, String targetPkg,
+            Uri uri, int modeFlags) {
         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
         if (modeFlags == 0) {
-            return;
+            return -1;
         }
 
         if (DEBUG_URI_PERMISSION) Slog.v(TAG, 
-                "Requested grant " + targetPkg + " permission to " + uri);
+                "Checking grant " + targetPkg + " permission to " + uri);
         
         final IPackageManager pm = AppGlobals.getPackageManager();
 
@@ -4117,7 +4124,7 @@
         if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
             if (DEBUG_URI_PERMISSION) Slog.v(TAG, 
                     "Can't grant URI permission for non-content URI: " + uri);
-            return;
+            return -1;
         }
 
         String name = uri.getAuthority();
@@ -4134,7 +4141,7 @@
         }
         if (pi == null) {
             Slog.w(TAG, "No content provider found for: " + name);
-            return;
+            return -1;
         }
 
         int targetUid;
@@ -4143,10 +4150,10 @@
             if (targetUid < 0) {
                 if (DEBUG_URI_PERMISSION) Slog.v(TAG, 
                         "Can't grant URI permission no uid for: " + targetPkg);
-                return;
+                return -1;
             }
         } catch (RemoteException ex) {
-            return;
+            return -1;
         }
 
         // First...  does the target actually need this permission?
@@ -4154,7 +4161,7 @@
             // No need to grant the target this permission.
             if (DEBUG_URI_PERMISSION) Slog.v(TAG, 
                     "Target " + targetPkg + " already has full permission to " + uri);
-            return;
+            return -1;
         }
 
         // Second...  is the provider allowing granting of URI permissions?
@@ -4191,12 +4198,23 @@
             }
         }
 
-        // Okay!  So here we are: the caller has the assumed permission
+        return targetUid;
+    }
+
+    void grantUriPermissionUncheckedLocked(int targetUid, String targetPkg,
+            Uri uri, int modeFlags, UriPermissionOwner owner) {
+        modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+        if (modeFlags == 0) {
+            return;
+        }
+
+        // So here we are: the caller has the assumed permission
         // to the uri, and the target doesn't.  Let's now give this to
         // the target.
 
         if (DEBUG_URI_PERMISSION) Slog.v(TAG, 
-                "Granting " + targetPkg + " permission to " + uri);
+                "Granting " + targetPkg + "/" + targetUid + " permission to " + uri);
         
         HashMap<Uri, UriPermission> targetUris
                 = mGrantedUriPermissions.get(targetUid);
@@ -4212,39 +4230,65 @@
         }
 
         perm.modeFlags |= modeFlags;
-        if (activity == null) {
+        if (owner == null) {
             perm.globalModeFlags |= modeFlags;
         } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
-            perm.readActivities.add(activity);
-            if (activity.readUriPermissions == null) {
-                activity.readUriPermissions = new HashSet<UriPermission>();
-            }
-            activity.readUriPermissions.add(perm);
+            perm.readOwners.add(owner);
+            owner.addReadPermission(perm);
         } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
-            perm.writeActivities.add(activity);
-            if (activity.writeUriPermissions == null) {
-                activity.writeUriPermissions = new HashSet<UriPermission>();
-            }
-            activity.writeUriPermissions.add(perm);
+            perm.writeOwners.add(owner);
+            owner.addWritePermission(perm);
         }
     }
 
-    void grantUriPermissionFromIntentLocked(int callingUid,
-            String targetPkg, Intent intent, ActivityRecord activity) {
+    void grantUriPermissionLocked(int callingUid,
+            String targetPkg, Uri uri, int modeFlags, UriPermissionOwner owner) {
+        int targetUid = checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags);
+        if (targetUid < 0) {
+            return;
+        }
+
+        grantUriPermissionUncheckedLocked(targetUid, targetPkg, uri, modeFlags, owner);
+    }
+
+    /**
+     * Like checkGrantUriPermissionLocked, but takes an Intent.
+     */
+    int checkGrantUriPermissionFromIntentLocked(int callingUid,
+            String targetPkg, Intent intent) {
         if (DEBUG_URI_PERMISSION) Slog.v(TAG,
-                "Grant URI perm to " + (intent != null ? intent.getData() : null)
+                "Checking URI perm to " + (intent != null ? intent.getData() : null)
                 + " from " + intent + "; flags=0x"
                 + Integer.toHexString(intent != null ? intent.getFlags() : 0));
 
         if (intent == null) {
-            return;
+            return -1;
         }
         Uri data = intent.getData();
         if (data == null) {
+            return -1;
+        }
+        return checkGrantUriPermissionLocked(callingUid, targetPkg, data,
+                intent.getFlags());
+    }
+
+    /**
+     * Like grantUriPermissionUncheckedLocked, but takes an Intent.
+     */
+    void grantUriPermissionUncheckedFromIntentLocked(int targetUid,
+            String targetPkg, Intent intent, UriPermissionOwner owner) {
+        grantUriPermissionUncheckedLocked(targetUid, targetPkg, intent.getData(),
+                intent.getFlags(), owner);
+    }
+
+    void grantUriPermissionFromIntentLocked(int callingUid,
+            String targetPkg, Intent intent, UriPermissionOwner owner) {
+        int targetUid = checkGrantUriPermissionFromIntentLocked(callingUid, targetPkg, intent);
+        if (targetUid < 0) {
             return;
         }
-        grantUriPermissionLocked(callingUid, targetPkg, data,
-                intent.getFlags(), activity);
+
+        grantUriPermissionUncheckedFromIntentLocked(targetUid, targetPkg, intent, owner);
     }
 
     public void grantUriPermission(IApplicationThread caller, String targetPkg,
@@ -8215,18 +8259,23 @@
             return;
         }
 
-        int i = 0;
-        while (i < N) {
+        while (r.pendingStarts.size() > 0) {
             try {
-                ServiceRecord.StartItem si = r.pendingStarts.get(i);
+                ServiceRecord.StartItem si = r.pendingStarts.remove(0);
                 if (DEBUG_SERVICE) Slog.v(TAG, "Sending arguments to service: "
                         + r.name + " " + r.intent + " args=" + si.intent);
-                if (si.intent == null && N > 1) {
+                if (si.intent == null) {
                     // If somehow we got a dummy start at the front, then
                     // just drop it here.
-                    i++;
                     continue;
                 }
+                si.deliveredTime = SystemClock.uptimeMillis();
+                r.deliveredStarts.add(si);
+                si.deliveryCount++;
+                if (si.targetPermissionUid >= 0) {
+                    grantUriPermissionUncheckedFromIntentLocked(si.targetPermissionUid,
+                            r.packageName, si.intent, si);
+                }
                 bumpServiceExecutingLocked(r);
                 if (!oomAdjusted) {
                     oomAdjusted = true;
@@ -8240,10 +8289,6 @@
                     flags |= Service.START_FLAG_REDELIVERY;
                 }
                 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
-                si.deliveredTime = SystemClock.uptimeMillis();
-                r.deliveredStarts.add(si);
-                si.deliveryCount++;
-                i++;
             } catch (RemoteException e) {
                 // Remote process gone...  we'll let the normal cleanup take
                 // care of this.
@@ -8253,14 +8298,6 @@
                 break;
             }
         }
-        if (i == N) {
-            r.pendingStarts.clear();
-        } else {
-            while (i > 0) {
-                i--;
-                r.pendingStarts.remove(i);
-            }
-        }
     }
 
     private final boolean requestServiceBindingLocked(ServiceRecord r,
@@ -8343,7 +8380,7 @@
             if (r.lastStartId < 1) {
                 r.lastStartId = 1;
             }
-            r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
+            r.pendingStarts.add(new ServiceRecord.StartItem(r, r.lastStartId, null, -1));
         }
         
         sendServiceArgsLocked(r, true);
@@ -8363,6 +8400,7 @@
         if (N > 0) {
             for (int i=N-1; i>=0; i--) {
                 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
+                si.removeUriPermissionsLocked();
                 if (si.intent == null) {
                     // We'll generate this again if needed.
                 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
@@ -8602,7 +8640,7 @@
         r.foregroundNoti = null;
         
         // Clear start entries.
-        r.deliveredStarts.clear();
+        r.clearDeliveredStartsLocked();
         r.pendingStarts.clear();
         
         if (r.app != null) {
@@ -8662,6 +8700,8 @@
                         ? res.permission : "private to package");
             }
             ServiceRecord r = res.record;
+            int targetPermissionUid = checkGrantUriPermissionFromIntentLocked(
+                    callingUid, r.packageName, service);
             if (unscheduleServiceRestartLocked(r)) {
                 if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: "
                         + r.shortName);
@@ -8672,7 +8712,8 @@
             if (r.lastStartId < 1) {
                 r.lastStartId = 1;
             }
-            r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
+            r.pendingStarts.add(new ServiceRecord.StartItem(r, r.lastStartId,
+                    service, targetPermissionUid));
             r.lastActivity = SystemClock.uptimeMillis();
             synchronized (r.stats.getBatteryStats()) {
                 r.stats.startRunningLocked();
@@ -8797,7 +8838,9 @@
                     ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
                     if (si != null) {
                         while (r.deliveredStarts.size() > 0) {
-                            if (r.deliveredStarts.remove(0) == si) {
+                            ServiceRecord.StartItem cur = r.deliveredStarts.remove(0);
+                            cur.removeUriPermissionsLocked();
+                            if (cur == si) {
                                 break;
                             }
                         }
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 79756a7..80a41b7 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -29,6 +29,7 @@
 import android.os.Bundle;
 import android.os.Message;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.EventLog;
 import android.util.Log;
@@ -43,7 +44,7 @@
 /**
  * An entry in the history stack, representing an activity.
  */
-class ActivityRecord extends IApplicationToken.Stub {
+class ActivityRecord extends IApplicationToken.Stub implements UriPermissionOwner {
     final ActivityManagerService service; // owner
     final ActivityStack stack; // owner
     final ActivityInfo info; // all about me
@@ -340,16 +341,22 @@
      * Deliver a new Intent to an existing activity, so that its onNewIntent()
      * method will be called at the proper time.
      */
-    final void deliverNewIntentLocked(Intent intent) {
+    final void deliverNewIntentLocked(int callingUid, Intent intent) {
         boolean sent = false;
         if (state == ActivityState.RESUMED
                 && app != null && app.thread != null) {
             try {
                 ArrayList<Intent> ar = new ArrayList<Intent>();
-                ar.add(new Intent(intent));
+                intent = new Intent(intent);
+                ar.add(intent);
+                service.grantUriPermissionFromIntentLocked(callingUid, packageName,
+                        intent, this);
                 app.thread.scheduleNewIntent(ar, this);
                 sent = true;
-            } catch (Exception e) {
+            } catch (RemoteException e) {
+                Slog.w(ActivityManagerService.TAG,
+                        "Exception thrown sending new intent to " + this, e);
+            } catch (NullPointerException e) {
                 Slog.w(ActivityManagerService.TAG,
                         "Exception thrown sending new intent to " + this, e);
             }
@@ -362,23 +369,25 @@
     void removeUriPermissionsLocked() {
         if (readUriPermissions != null) {
             for (UriPermission perm : readUriPermissions) {
-                perm.readActivities.remove(this);
-                if (perm.readActivities.size() == 0 && (perm.globalModeFlags
+                perm.readOwners.remove(this);
+                if (perm.readOwners.size() == 0 && (perm.globalModeFlags
                         &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
                     perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
-                   service.removeUriPermissionIfNeededLocked(perm);
+                    service.removeUriPermissionIfNeededLocked(perm);
                 }
             }
+            readUriPermissions = null;
         }
         if (writeUriPermissions != null) {
             for (UriPermission perm : writeUriPermissions) {
-                perm.writeActivities.remove(this);
-                if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
+                perm.writeOwners.remove(this);
+                if (perm.writeOwners.size() == 0 && (perm.globalModeFlags
                         &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
                     perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
                     service.removeUriPermissionIfNeededLocked(perm);
                 }
             }
+            writeUriPermissions = null;
         }
     }
 
@@ -569,6 +578,37 @@
                 state == ActivityState.RESUMED;
      }
     
+    @Override
+    public void addReadPermission(UriPermission perm) {
+        if (readUriPermissions == null) {
+            readUriPermissions = new HashSet<UriPermission>();
+        }
+        readUriPermissions.add(perm);
+    }
+
+    @Override
+    public void addWritePermission(UriPermission perm) {
+        if (writeUriPermissions == null) {
+            writeUriPermissions = new HashSet<UriPermission>();
+        }
+        writeUriPermissions.add(perm);
+    }
+
+    @Override
+    public void removeReadPermission(UriPermission perm) {
+        readUriPermissions.remove(perm);
+        if (readUriPermissions.size() == 0) {
+            readUriPermissions = null;
+        }
+    }
+
+    @Override
+    public void removeWritePermission(UriPermission perm) {
+        writeUriPermissions.remove(perm);
+        if (writeUriPermissions.size() == 0) {
+            writeUriPermissions = null;
+        }
+    }
     
     public String toString() {
         if (stringName != null) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index de7b15c..a5f7e96 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -2033,16 +2033,6 @@
             }
         }
 
-        if (grantedUriPermissions != null && callingUid > 0) {
-            for (int i=0; i<grantedUriPermissions.length; i++) {
-                mService.grantUriPermissionLocked(callingUid, r.packageName,
-                        grantedUriPermissions[i], grantedMode, r);
-            }
-        }
-
-        mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
-                intent, r);
-
         if (sourceRecord == null) {
             // This activity is not being started from another...  in this
             // case we -always- start a new task.
@@ -2150,7 +2140,7 @@
                                 top.task.setIntent(r.intent, r.info);
                             }
                             logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
-                            top.deliverNewIntentLocked(r.intent);
+                            top.deliverNewIntentLocked(callingUid, r.intent);
                         } else {
                             // A special case: we need to
                             // start the activity because it is not currently
@@ -2175,7 +2165,7 @@
                             if (taskTop.frontOfTask) {
                                 taskTop.task.setIntent(r.intent, r.info);
                             }
-                            taskTop.deliverNewIntentLocked(r.intent);
+                            taskTop.deliverNewIntentLocked(callingUid, r.intent);
                         } else if (!r.intent.filterEquals(taskTop.task.intent)) {
                             // In this case we are launching the root activity
                             // of the task, but with a different intent.  We
@@ -2243,7 +2233,7 @@
                                 // is the case, so this is it!
                                 return START_RETURN_INTENT_TO_CALLER;
                             }
-                            top.deliverNewIntentLocked(r.intent);
+                            top.deliverNewIntentLocked(callingUid, r.intent);
                             return START_DELIVERED_TO_TOP;
                         }
                     }
@@ -2288,7 +2278,7 @@
                         sourceRecord.task.taskId, r, launchFlags, true);
                 if (top != null) {
                     logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
-                    top.deliverNewIntentLocked(r.intent);
+                    top.deliverNewIntentLocked(callingUid, r.intent);
                     // For paranoia, make sure we have correctly
                     // resumed the top activity.
                     if (doResume) {
@@ -2305,7 +2295,7 @@
                 if (where >= 0) {
                     ActivityRecord top = moveActivityToFrontLocked(where);
                     logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
-                    top.deliverNewIntentLocked(r.intent);
+                    top.deliverNewIntentLocked(callingUid, r.intent);
                     if (doResume) {
                         resumeTopActivityLocked(null);
                     }
@@ -2333,6 +2323,17 @@
             if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                     + " in new guessed " + r.task);
         }
+
+        if (grantedUriPermissions != null && callingUid > 0) {
+            for (int i=0; i<grantedUriPermissions.length; i++) {
+                mService.grantUriPermissionLocked(callingUid, r.packageName,
+                        grantedUriPermissions[i], grantedMode, r);
+            }
+        }
+
+        mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
+                intent, r);
+
         if (newTask) {
             EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
         }
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index c3f0b3e..bac21b1 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -26,6 +26,7 @@
 import android.os.IBinder;
 import android.os.SystemClock;
 import android.util.PrintWriterPrinter;
+import android.util.TimeUtils;
 
 import java.io.PrintWriter;
 import java.util.List;
@@ -73,61 +74,65 @@
     ActivityInfo curReceiver;   // info about the receiver that is currently running.
 
     void dump(PrintWriter pw, String prefix) {
-        pw.println(prefix + this);
-        pw.println(prefix + intent);
+        final long now = SystemClock.uptimeMillis();
+
+        pw.print(prefix); pw.println(this);
+        pw.print(prefix); pw.println(intent);
         if (sticky) {
             Bundle bundle = intent.getExtras();
             if (bundle != null) {
-                pw.println(prefix + "extras: " + bundle.toString());
+                pw.print(prefix); pw.print("extras: "); pw.println(bundle.toString());
             }
         }
-        pw.println(prefix + "proc=" + callerApp);
-        pw.println(prefix + "caller=" + callerPackage
-                + " callingPid=" + callingPid
-                + " callingUid=" + callingUid);
+        pw.print(prefix); pw.print("caller="); pw.print(callerPackage); pw.println(" ");
+                pw.println(callerApp != null ? callerApp.toShortString() : "null");
+                pw.print(" pid="); pw.print(callingPid);
+                pw.print(" uid="); pw.println(callingUid);
         if (requiredPermission != null) {
-            pw.println(prefix + "requiredPermission=" + requiredPermission);
+            pw.print(prefix); pw.print("requiredPermission="); pw.println(requiredPermission);
         }
-        pw.println(prefix + "dispatchTime=" + dispatchTime + " ("
-                + (SystemClock.uptimeMillis()-dispatchTime) + "ms since now)");
+        pw.print(prefix); pw.print("dispatchTime=");
+                TimeUtils.formatDuration(dispatchTime, now, pw);
         if (finishTime != 0) {
-            pw.println(prefix + "finishTime=" + finishTime + " ("
-                    + (SystemClock.uptimeMillis()-finishTime) + "ms since now)");
+            pw.print(" finishTime="); TimeUtils.formatDuration(finishTime, now, pw);
         } else {
-            pw.println(prefix + "receiverTime=" + receiverTime + " ("
-                    + (SystemClock.uptimeMillis()-receiverTime) + "ms since now)");
+            pw.print(" receiverTime="); TimeUtils.formatDuration(receiverTime, now, pw);
         }
+        pw.println("");
         if (anrCount != 0) {
-            pw.println(prefix + "anrCount=" + anrCount);
+            pw.print(prefix); pw.print("anrCount="); pw.println(anrCount);
         }
         if (resultTo != null || resultCode != -1 || resultData != null) {
-            pw.println(prefix + "resultTo=" + resultTo
-                  + " resultCode=" + resultCode + " resultData=" + resultData);
+            pw.print(prefix); pw.print("resultTo="); pw.print(resultTo);
+                    pw.print(" resultCode="); pw.print(resultCode);
+                    pw.print(" resultData="); pw.println(resultData);
         }
         if (resultExtras != null) {
-            pw.println(prefix + "resultExtras=" + resultExtras);
+            pw.print(prefix); pw.print("resultExtras="); pw.println(resultExtras);
         }
         if (resultAbort || ordered || sticky || initialSticky) {
-            pw.println(prefix + "resultAbort=" + resultAbort
-                    + " ordered=" + ordered + " sticky=" + sticky
-                    + " initialSticky=" + initialSticky);
+            pw.print(prefix); pw.print("resultAbort="); pw.print(resultAbort);
+                    pw.print(" ordered="); pw.print(ordered);
+                    pw.print(" sticky="); pw.print(sticky);
+                    pw.print(" initialSticky="); pw.println(initialSticky);
         }
         if (nextReceiver != 0 || receiver != null) {
-            pw.println(prefix + "nextReceiver=" + nextReceiver
-                  + " receiver=" + receiver);
+            pw.print(prefix); pw.print("nextReceiver="); pw.print(nextReceiver);
+                    pw.print(" receiver="); pw.println(receiver);
         }
         if (curFilter != null) {
-            pw.println(prefix + "curFilter=" + curFilter);
+            pw.print(prefix); pw.print("curFilter="); pw.println(curFilter);
         }
         if (curReceiver != null) {
-            pw.println(prefix + "curReceiver=" + curReceiver);
+            pw.print(prefix); pw.print("curReceiver="); pw.println(curReceiver);
         }
         if (curApp != null) {
-            pw.println(prefix + "curApp=" + curApp);
-            pw.println(prefix + "curComponent="
-                    + (curComponent != null ? curComponent.toShortString() : "--"));
+            pw.print(prefix); pw.print("curApp="); pw.println(curApp);
+            pw.print(prefix); pw.print("curComponent=");
+                    pw.println((curComponent != null ? curComponent.toShortString() : "--"));
             if (curReceiver != null && curReceiver.applicationInfo != null) {
-                pw.println(prefix + "curSourceDir=" + curReceiver.applicationInfo.sourceDir);
+                pw.print(prefix); pw.print("curSourceDir=");
+                        pw.println(curReceiver.applicationInfo.sourceDir);
             }
         }
         String stateStr = " (?)";
@@ -137,13 +142,14 @@
             case CALL_IN_RECEIVE:   stateStr=" (CALL_IN_RECEIVE)"; break;
             case CALL_DONE_RECEIVE: stateStr=" (CALL_DONE_RECEIVE)"; break;
         }
-        pw.println(prefix + "state=" + state + stateStr);
+        pw.print(prefix); pw.print("state="); pw.print(state); pw.println(stateStr);
         final int N = receivers != null ? receivers.size() : 0;
         String p2 = prefix + "  ";
         PrintWriterPrinter printer = new PrintWriterPrinter(pw);
         for (int i=0; i<N; i++) {
             Object o = receivers.get(i);
-            pw.println(prefix + "Receiver #" + i + ": " + o);
+            pw.print(prefix); pw.print("Receiver #"); pw.print(i);
+                    pw.print(": "); pw.println(o);
             if (o instanceof BroadcastFilter)
                 ((BroadcastFilter)o).dumpBrief(pw, p2);
             else if (o instanceof ResolveInfo)
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index ab5a78d..255fbe3 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -36,6 +36,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 
@@ -43,6 +44,12 @@
  * A running application service.
  */
 class ServiceRecord extends Binder {
+    // Maximum number of delivery attempts before giving up.
+    static final int MAX_DELIVERY_COUNT = 3;
+
+    // Maximum number of times it can fail during execution before giving up.
+    static final int MAX_DONE_EXECUTING_COUNT = 6;
+
     final ActivityManagerService ams;
     final BatteryStatsImpl.Uid.Pkg.Serv stats;
     final ComponentName name; // service component.
@@ -68,29 +75,6 @@
     final HashMap<IBinder, ConnectionRecord> connections
             = new HashMap<IBinder, ConnectionRecord>();
                             // IBinder -> ConnectionRecord of all bound clients
-    
-    // Maximum number of delivery attempts before giving up.
-    static final int MAX_DELIVERY_COUNT = 3;
-    
-    // Maximum number of times it can fail during execution before giving up.
-    static final int MAX_DONE_EXECUTING_COUNT = 6;
-    
-    static class StartItem {
-        final int id;
-        final Intent intent;
-        long deliveredTime;
-        int deliveryCount;
-        int doneExecutingCount;
-        
-        StartItem(int _id, Intent _intent) {
-            id = _id;
-            intent = _intent;
-        }
-    }
-    final ArrayList<StartItem> deliveredStarts = new ArrayList<StartItem>();
-                            // start() arguments which been delivered.
-    final ArrayList<StartItem> pendingStarts = new ArrayList<StartItem>();
-                            // start() arguments that haven't yet been delivered.
 
     ProcessRecord app;      // where this service is running or null.
     boolean isForeground;   // is service currently in foreground mode?
@@ -112,6 +96,104 @@
 
     String stringName;      // caching of toString
     
+    static class StartItem implements UriPermissionOwner {
+        final ServiceRecord sr;
+        final int id;
+        final Intent intent;
+        final int targetPermissionUid;
+        long deliveredTime;
+        int deliveryCount;
+        int doneExecutingCount;
+
+        String stringName;      // caching of toString
+
+        HashSet<UriPermission> readUriPermissions; // special access to reading uris.
+        HashSet<UriPermission> writeUriPermissions; // special access to writing uris.
+
+        StartItem(ServiceRecord _sr, int _id, Intent _intent, int _targetPermissionUid) {
+            sr = _sr;
+            id = _id;
+            intent = _intent;
+            targetPermissionUid = _targetPermissionUid;
+        }
+
+        void removeUriPermissionsLocked() {
+            if (readUriPermissions != null) {
+                for (UriPermission perm : readUriPermissions) {
+                    perm.readOwners.remove(this);
+                    if (perm.readOwners.size() == 0 && (perm.globalModeFlags
+                            &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
+                        perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
+                        sr.ams.removeUriPermissionIfNeededLocked(perm);
+                    }
+                }
+                readUriPermissions = null;
+            }
+            if (writeUriPermissions != null) {
+                for (UriPermission perm : writeUriPermissions) {
+                    perm.writeOwners.remove(this);
+                    if (perm.writeOwners.size() == 0 && (perm.globalModeFlags
+                            &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
+                        perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+                        sr.ams.removeUriPermissionIfNeededLocked(perm);
+                    }
+                }
+                writeUriPermissions = null;
+            }
+        }
+
+        @Override
+        public void addReadPermission(UriPermission perm) {
+            if (readUriPermissions == null) {
+                readUriPermissions = new HashSet<UriPermission>();
+            }
+            readUriPermissions.add(perm);
+        }
+
+        @Override
+        public void addWritePermission(UriPermission perm) {
+            if (writeUriPermissions == null) {
+                writeUriPermissions = new HashSet<UriPermission>();
+            }
+            writeUriPermissions.add(perm);
+        }
+
+        @Override
+        public void removeReadPermission(UriPermission perm) {
+            readUriPermissions.remove(perm);
+            if (readUriPermissions.size() == 0) {
+                readUriPermissions = null;
+            }
+        }
+
+        @Override
+        public void removeWritePermission(UriPermission perm) {
+            writeUriPermissions.remove(perm);
+            if (writeUriPermissions.size() == 0) {
+                writeUriPermissions = null;
+            }
+        }
+
+        public String toString() {
+            if (stringName != null) {
+                return stringName;
+            }
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("ServiceRecord{")
+                .append(Integer.toHexString(System.identityHashCode(sr)))
+                .append(' ').append(sr.shortName)
+                .append(" StartItem ")
+                .append(Integer.toHexString(System.identityHashCode(this)))
+                .append(" id=").append(id).append('}');
+            return stringName = sb.toString();
+        }
+    }
+
+    final ArrayList<StartItem> deliveredStarts = new ArrayList<StartItem>();
+                            // start() arguments which been delivered.
+    final ArrayList<StartItem> pendingStarts = new ArrayList<StartItem>();
+                            // start() arguments that haven't yet been delivered.
+
     void dumpStartList(PrintWriter pw, String prefix, List<StartItem> list, long now) {
         final int N = list.size();
         for (int i=0; i<N; i++) {
@@ -128,9 +210,22 @@
                     if (si.doneExecutingCount != 0) {
                         pw.print(" dxc="); pw.print(si.doneExecutingCount);
                     }
-                    pw.print(" ");
+                    pw.println("");
+            pw.print(prefix); pw.print("  intent=");
                     if (si.intent != null) pw.println(si.intent.toString());
                     else pw.println("null");
+            if (si.targetPermissionUid >= 0) {
+                pw.print(prefix); pw.print("  targetPermissionUid=");
+                        pw.println(si.targetPermissionUid);
+            }
+            if (si.readUriPermissions != null) {
+                pw.print(prefix); pw.print("  readUriPermissions=");
+                        pw.println(si.readUriPermissions);
+            }
+            if (si.writeUriPermissions != null) {
+                pw.print(prefix); pw.print("  writeUriPermissions=");
+                        pw.println(si.writeUriPermissions);
+            }
         }
     }
     
@@ -324,6 +419,13 @@
         }
     }
     
+    public void clearDeliveredStartsLocked() {
+        for (int i=deliveredStarts.size()-1; i>=0; i--) {
+            deliveredStarts.get(i).removeUriPermissionsLocked();
+        }
+        deliveredStarts.clear();
+    }
+
     public String toString() {
         if (stringName != null) {
             return stringName;
diff --git a/services/java/com/android/server/am/UriPermission.java b/services/java/com/android/server/am/UriPermission.java
index 81450c5..93c59cc 100644
--- a/services/java/com/android/server/am/UriPermission.java
+++ b/services/java/com/android/server/am/UriPermission.java
@@ -22,13 +22,20 @@
 import java.io.PrintWriter;
 import java.util.HashSet;
 
+interface UriPermissionOwner {
+    void addReadPermission(UriPermission perm);
+    void addWritePermission(UriPermission perm);
+    void removeReadPermission(UriPermission perm);
+    void removeWritePermission(UriPermission perm);
+}
+
 class UriPermission {
     final int uid;
     final Uri uri;
     int modeFlags = 0;
     int globalModeFlags = 0;
-    final HashSet<ActivityRecord> readActivities = new HashSet<ActivityRecord>();
-    final HashSet<ActivityRecord> writeActivities = new HashSet<ActivityRecord>();
+    final HashSet<UriPermissionOwner> readOwners = new HashSet<UriPermissionOwner>();
+    final HashSet<UriPermissionOwner> writeOwners = new HashSet<UriPermissionOwner>();
     
     String stringName;
     
@@ -41,27 +48,21 @@
         if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
             globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
             modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
-            if (readActivities.size() > 0) {
-                for (ActivityRecord r : readActivities) {
-                    r.readUriPermissions.remove(this);
-                    if (r.readUriPermissions.size() == 0) {
-                        r.readUriPermissions = null;
-                    }
+            if (readOwners.size() > 0) {
+                for (UriPermissionOwner r : readOwners) {
+                    r.removeReadPermission(this);
                 }
-                readActivities.clear();
+                readOwners.clear();
             }
         }
         if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
             globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
             modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
-            if (readActivities.size() > 0) {
-                for (ActivityRecord r : readActivities) {
-                    r.writeUriPermissions.remove(this);
-                    if (r.writeUriPermissions.size() == 0) {
-                        r.writeUriPermissions = null;
-                    }
+            if (readOwners.size() > 0) {
+                for (UriPermissionOwner r : writeOwners) {
+                    r.removeWritePermission(this);
                 }
-                readActivities.clear();
+                readOwners.clear();
             }
         }
     }
@@ -85,11 +86,17 @@
                 pw.print(" uid="); pw.print(uid); 
                 pw.print(" globalModeFlags=0x");
                 pw.println(Integer.toHexString(globalModeFlags));
-        if (readActivities.size() != 0) {
-            pw.print(prefix); pw.print("readActivities="); pw.println(readActivities);
+        if (readOwners.size() != 0) {
+            pw.print(prefix); pw.println("readOwners:");
+            for (UriPermissionOwner owner : readOwners) {
+                pw.print(prefix); pw.print("  * "); pw.println(owner);
+            }
         }
-        if (writeActivities.size() != 0) {
-            pw.print(prefix); pw.print("writeActivities="); pw.println(writeActivities);
+        if (writeOwners.size() != 0) {
+            pw.print(prefix); pw.println("writeOwners:");
+            for (UriPermissionOwner owner : writeOwners) {
+                pw.print(prefix); pw.print("  * "); pw.println(owner);
+            }
         }
     }
 }
diff --git a/services/java/com/android/server/sip/SipSessionGroup.java b/services/java/com/android/server/sip/SipSessionGroup.java
index db3f536..d33558b 100644
--- a/services/java/com/android/server/sip/SipSessionGroup.java
+++ b/services/java/com/android/server/sip/SipSessionGroup.java
@@ -381,14 +381,29 @@
                     : listener);
         }
 
+        // process the command in a new thread
+        private void doCommandAsync(final EventObject command) {
+            new Thread(new Runnable() {
+                    public void run() {
+                        try {
+                            processCommand(command);
+                        } catch (SipException e) {
+                            // TODO: find a better way to do this
+                            if ((command instanceof RegisterCommand)
+                                    || (command == DEREGISTER)) {
+                                onRegistrationFailed(e);
+                            } else {
+                                onError(e);
+                            }
+                        }
+                    }
+            }).start();
+        }
+
         public void makeCall(SipProfile peerProfile,
                 SessionDescription sessionDescription) {
-            try {
-                processCommand(
-                        new MakeCallCommand(peerProfile, sessionDescription));
-            } catch (SipException e) {
-                onError(e);
-            }
+            doCommandAsync(
+                    new MakeCallCommand(peerProfile, sessionDescription));
         }
 
         public void answerCall(SessionDescription sessionDescription) {
@@ -401,36 +416,20 @@
         }
 
         public void endCall() {
-            try {
-                processCommand(END_CALL);
-            } catch (SipException e) {
-                onError(e);
-            }
+            doCommandAsync(END_CALL);
         }
 
         public void changeCall(SessionDescription sessionDescription) {
-            try {
-                processCommand(
-                        new MakeCallCommand(mPeerProfile, sessionDescription));
-            } catch (SipException e) {
-                onError(e);
-            }
+            doCommandAsync(
+                    new MakeCallCommand(mPeerProfile, sessionDescription));
         }
 
         public void register(int duration) {
-            try {
-                processCommand(new RegisterCommand(duration));
-            } catch (SipException e) {
-                onRegistrationFailed(e);
-            }
+            doCommandAsync(new RegisterCommand(duration));
         }
 
         public void unregister() {
-            try {
-                processCommand(DEREGISTER);
-            } catch (SipException e) {
-                onRegistrationFailed(e);
-            }
+            doCommandAsync(DEREGISTER);
         }
 
         public boolean isReRegisterRequired() {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index af7c3bf..a78d9b9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1745,12 +1745,15 @@
 {
     int32_t name = NAME_NOT_FOUND;
     sp<Layer> layer(mFlinger->getLayer(sur));
-    if (layer == 0) return name;
+    if (layer == 0) {
+        return name;
+    }
 
     // if this layer already has a token, just return it
     name = layer->getToken();
-    if ((name >= 0) && (layer->getClient() == this))
+    if ((name >= 0) && (layer->getClient() == this)) {
         return name;
+    }
 
     name = 0;
     do {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 92bed8d..2370add 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -177,7 +177,7 @@
 
     /**
      * Returns the unique device ID, for example, the IMEI for GSM and the MEID
-     * for CDMA phones. Return null if device ID is not available.
+     * or ESN for CDMA phones. Return null if device ID is not available.
      *
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 8e08592..980affa 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -322,7 +322,9 @@
                 }
                 break;
         }
-        audioManager.setMode(mode);
+        // calling audioManager.setMode() multiple times in a short period of
+        // time seems to break the audio recorder in in-call mode
+        if (audioManager.getMode() != mode) audioManager.setMode(mode);
     }
 
     private Context getContext() {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 0c3c534..b39556a 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -452,9 +452,14 @@
         return mMeid;
     }
 
-    //returns MEID in CDMA
+    //returns MEID or ESN in CDMA
     public String getDeviceId() {
-        return getMeid();
+        String id = getMeid();
+        if ((id == null) || id.matches("^0*$")) {
+            Log.d(LOG_TAG, "getDeviceId(): MEID is not initialized use ESN");
+            id = getEsn();
+        }
+        return id;
     }
 
     public String getDeviceSvn() {
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
index aa16fa3..fe7a5cb 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
@@ -44,6 +44,13 @@
 
     //***** Constants
 
+    // Max Size of the Short Code (aka Short String from TS 22.030 6.5.2)
+    static final int MAX_LENGTH_SHORT_CODE = 2;
+
+    // TS 22.030 6.5.2 Every Short String USSD command will end with #-key
+    // (known as #-String)
+    static final char END_OF_USSD_COMMAND = '#';
+
     // From TS 22.030 6.5.2
     static final String ACTION_ACTIVATE = "*";
     static final String ACTION_DEACTIVATE = "#";
@@ -446,22 +453,69 @@
     }
 
     /**
-     * Helper function for newFromDialString.  Returns true if dialString appears to be a short code
-     * AND conditions are correct for it to be treated as such.
+     * Helper function for newFromDialString. Returns true if dialString appears
+     * to be a short code AND conditions are correct for it to be treated as
+     * such.
      */
     static private boolean isShortCode(String dialString, GSMPhone phone) {
         // Refer to TS 22.030 Figure 3.5.3.2:
-        // A 1 or 2 digit "short code" is treated as USSD if it is entered while on a call or
-        // does not satisfy the condition (exactly 2 digits && starts with '1').
-        return ((dialString != null && dialString.length() <= 2)
-                && !PhoneNumberUtils.isEmergencyNumber(dialString)
-                && (phone.isInCall()
-                    || !((dialString.length() == 2 && dialString.charAt(0) == '1')
-                         /* While contrary to TS 22.030, there is strong precedence
-                          * for treating "0" and "00" as call setup strings.
-                          */
-                         || dialString.equals("0")
-                         || dialString.equals("00"))));
+        if (dialString == null) {
+            return false;
+        }
+
+        // Illegal dial string characters will give a ZERO length.
+        // At this point we do not want to crash as any application with
+        // call privileges may send a non dial string.
+        // It return false as when the dialString is equal to NULL.
+        if (dialString.length() == 0) {
+            return false;
+        }
+
+        if (PhoneNumberUtils.isEmergencyNumber(dialString)) {
+            return false;
+        } else {
+            return isShortCodeUSSD(dialString, phone);
+        }
+    }
+
+    /**
+     * Helper function for isShortCode. Returns true if dialString appears to be
+     * a short code and it is a USSD structure
+     *
+     * According to the 3PGG TS 22.030 specification Figure 3.5.3.2: A 1 or 2
+     * digit "short code" is treated as USSD if it is entered while on a call or
+     * does not satisfy the condition (exactly 2 digits && starts with '1'), there
+     * are however exceptions to this rule (see below)
+     *
+     * Exception (1) to Call initiation is: If the user of the device is already in a call
+     * and enters a Short String without any #-key at the end and the length of the Short String is
+     * equal or less then the MAX_LENGTH_SHORT_CODE [constant that is equal to 2]
+     *
+     * The phone shall initiate a USSD/SS commands.
+     *
+     * Exception (2) to Call initiation is: If the user of the device enters one
+     * Digit followed by the #-key. This rule defines this String as the
+     * #-String which is a USSD/SS command.
+     *
+     * The phone shall initiate a USSD/SS command.
+     */
+    static private boolean isShortCodeUSSD(String dialString, GSMPhone phone) {
+        if (dialString != null) {
+            if (phone.isInCall()) {
+                // The maximum length of a Short Code (aka Short String) is 2
+                if (dialString.length() <= MAX_LENGTH_SHORT_CODE) {
+                    return true;
+                }
+            }
+
+            // The maximum length of a Short Code (aka Short String) is 2
+            if (dialString.length() <= MAX_LENGTH_SHORT_CODE) {
+                if (dialString.charAt(dialString.length() - 1) == END_OF_USSD_COMMAND) {
+                    return true;
+                }
+            }
+        }
+        return false;
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java b/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java
index ad05b82..f5d84eb 100644
--- a/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java
@@ -85,8 +85,10 @@
     protected void setState(Call.State state) {
         switch (state) {
             case ACTIVE:
-                connectTimeReal = SystemClock.elapsedRealtime();
-                connectTime = System.currentTimeMillis();
+                if (connectTime == 0) {
+                    connectTimeReal = SystemClock.elapsedRealtime();
+                    connectTime = System.currentTimeMillis();
+                }
                 break;
             case DISCONNECTED:
                 duration = SystemClock.elapsedRealtime() - connectTimeReal;
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index 81dfaeb..9a45d3a 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -107,7 +107,7 @@
     }
 
     public String getPhoneName() {
-        return mProfile.getProfileName();
+        return "SIP:" + getUriString(mProfile);
     }
 
     public String getSipUri() {
@@ -225,21 +225,25 @@
     }
 
     public void conference() throws CallStateException {
-        if ((foregroundCall.getState() != SipCall.State.ACTIVE)
-                || (foregroundCall.getState() != SipCall.State.ACTIVE)) {
-            throw new CallStateException("wrong state to merge calls: fg="
-                    + foregroundCall.getState() + ", bg="
-                    + backgroundCall.getState());
+        synchronized (SipPhone.class) {
+            if ((foregroundCall.getState() != SipCall.State.ACTIVE)
+                    || (foregroundCall.getState() != SipCall.State.ACTIVE)) {
+                throw new CallStateException("wrong state to merge calls: fg="
+                        + foregroundCall.getState() + ", bg="
+                        + backgroundCall.getState());
+            }
+            foregroundCall.merge(backgroundCall);
         }
-        foregroundCall.merge(backgroundCall);
     }
 
     public void conference(Call that) throws CallStateException {
-        if (!(that instanceof SipCall)) {
-            throw new CallStateException("expect " + SipCall.class
-                    + ", cannot merge with " + that.getClass());
+        synchronized (SipPhone.class) {
+            if (!(that instanceof SipCall)) {
+                throw new CallStateException("expect " + SipCall.class
+                        + ", cannot merge with " + that.getClass());
+            }
+            foregroundCall.merge((SipCall) that);
         }
-        foregroundCall.merge((SipCall) that);
     }
 
     public boolean canTransfer() {
@@ -251,12 +255,14 @@
     }
 
     public void clearDisconnected() {
-        ringingCall.clearDisconnected();
-        foregroundCall.clearDisconnected();
-        backgroundCall.clearDisconnected();
+        synchronized (SipPhone.class) {
+            ringingCall.clearDisconnected();
+            foregroundCall.clearDisconnected();
+            backgroundCall.clearDisconnected();
 
-        updatePhoneState();
-        notifyPreciseCallStateChanged();
+            updatePhoneState();
+            notifyPreciseCallStateChanged();
+        }
     }
 
     public void sendDtmf(char c) {
@@ -264,7 +270,9 @@
             Log.e(LOG_TAG,
                     "sendDtmf called with invalid character '" + c + "'");
         } else if (foregroundCall.getState().isAlive()) {
-            foregroundCall.sendDtmf(c);
+            synchronized (SipPhone.class) {
+                foregroundCall.sendDtmf(c);
+            }
         }
     }
 
@@ -310,7 +318,9 @@
     }
 
     public void setMute(boolean muted) {
-        foregroundCall.setMute(muted);
+        synchronized (SipPhone.class) {
+            foregroundCall.setMute(muted);
+        }
     }
 
     public boolean getMute() {
@@ -413,18 +423,20 @@
 
         @Override
         public void hangup() throws CallStateException {
-            Log.v(LOG_TAG, "hang up call: " + getState() + ": " + this
-                    + " on phone " + getPhone());
-            CallStateException excp = null;
-            for (Connection c : connections) {
-                try {
-                    c.hangup();
-                } catch (CallStateException e) {
-                    excp = e;
+            synchronized (SipPhone.class) {
+                Log.v(LOG_TAG, "hang up call: " + getState() + ": " + this
+                        + " on phone " + getPhone());
+                CallStateException excp = null;
+                for (Connection c : connections) {
+                    try {
+                        c.hangup();
+                    } catch (CallStateException e) {
+                        excp = e;
+                    }
                 }
+                if (excp != null) throw excp;
+                setState(State.DISCONNECTING);
             }
-            if (excp != null) throw excp;
-            setState(State.DISCONNECTING);
         }
 
         void initIncomingCall(SipAudioCall sipAudioCall, boolean makeCallWait) {
@@ -457,19 +469,20 @@
         }
 
         void hold() throws CallStateException {
-            AudioGroup audioGroup = getAudioGroup();
-            if (audioGroup == null) return;
-            audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
             setState(State.HOLDING);
+            AudioGroup audioGroup = getAudioGroup();
+            if (audioGroup != null) {
+                audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
+            }
             for (Connection c : connections) ((SipConnection) c).hold();
         }
 
         void unhold() throws CallStateException {
-            AudioGroup audioGroup = getAudioGroup();
-            if (audioGroup == null) return;
-            audioGroup.setMode(AudioGroup.MODE_NORMAL);
             setState(State.ACTIVE);
-            for (Connection c : connections) ((SipConnection) c).unhold();
+            AudioGroup audioGroup = new AudioGroup();
+            for (Connection c : connections) {
+                ((SipConnection) c).unhold(audioGroup);
+            }
         }
 
         void setMute(boolean muted) {
@@ -486,17 +499,26 @@
         }
 
         void merge(SipCall that) throws CallStateException {
-            AudioGroup myGroup = getAudioGroup();
+            AudioGroup audioGroup = getAudioGroup();
             for (Connection c : that.connections) {
                 SipConnection conn = (SipConnection) c;
-                conn.mergeTo(myGroup);
-                connections.add(conn);
-                conn.changeOwner(this);
+                add(conn);
+                if (conn.getState() == Call.State.HOLDING) {
+                    conn.unhold(audioGroup);
+                }
             }
-            that.connections.clear();
             that.setState(Call.State.IDLE);
         }
 
+        private void add(SipConnection conn) {
+            SipCall call = conn.getCall();
+            if (call == this) return;
+            if (call != null) call.connections.remove(conn);
+
+            connections.add(conn);
+            conn.changeOwner(this);
+        }
+
         void sendDtmf(char c) {
             AudioGroup audioGroup = getAudioGroup();
             if (audioGroup == null) return;
@@ -571,7 +593,6 @@
     private class SipConnection extends SipConnectionBase {
         private SipCall mOwner;
         private SipAudioCall mSipAudioCall;
-        private AudioGroup mOriginalGroup;
         private Call.State mState = Call.State.IDLE;
         private SipProfile mPeer;
         private boolean mIncoming = false;
@@ -676,6 +697,7 @@
         }
 
         void hold() throws CallStateException {
+            setState(Call.State.HOLDING);
             try {
                 mSipAudioCall.holdCall();
             } catch (SipException e) {
@@ -683,7 +705,9 @@
             }
         }
 
-        void unhold() throws CallStateException {
+        void unhold(AudioGroup audioGroup) throws CallStateException {
+            mSipAudioCall.setAudioGroup(audioGroup);
+            setState(Call.State.ACTIVE);
             try {
                 mSipAudioCall.continueCall();
             } catch (SipException e) {
@@ -691,16 +715,6 @@
             }
         }
 
-        void mergeTo(AudioGroup group) throws CallStateException {
-            AudioStream stream = mSipAudioCall.getAudioStream();
-            if (stream == null) {
-                throw new CallStateException("wrong state to merge: "
-                        + mSipAudioCall.getState());
-            }
-            if (mOriginalGroup == null) mOriginalGroup = getAudioGroup();
-            stream.join(group);
-        }
-
         @Override
         protected void setState(Call.State state) {
             if (state == mState) return;
@@ -735,29 +749,36 @@
 
         @Override
         public void hangup() throws CallStateException {
-            // TODO: need to pull AudioStream out of the AudioGroup in case
-            // this conn was part of a conf call
-            Log.v(LOG_TAG, "hangup conn: " + mPeer.getUriString() + ": "
-                    + ": on phone " + getPhone());
-            try {
-                mSipAudioCall.endCall();
-                setState(Call.State.DISCONNECTING);
-                setDisconnectCause(DisconnectCause.LOCAL);
-            } catch (SipException e) {
-                throw new CallStateException("hangup(): " + e);
+            synchronized (SipPhone.class) {
+                Log.v(LOG_TAG, "hangup conn: " + mPeer.getUriString() + ": "
+                        + ": on phone " + getPhone().getPhoneName());
+                try {
+                    mSipAudioCall.endCall();
+                    setState(Call.State.DISCONNECTING);
+                    setDisconnectCause(DisconnectCause.LOCAL);
+                } catch (SipException e) {
+                    throw new CallStateException("hangup(): " + e);
+                }
             }
         }
 
         @Override
         public void separate() throws CallStateException {
-            // TODO: what's this for SIP?
-            /*
-            if (!disconnected) {
-                owner.separate(this);
-            } else {
-                throw new CallStateException ("disconnected");
+            synchronized (SipPhone.class) {
+                SipCall call = (SipCall) SipPhone.this.getBackgroundCall();
+                if (call.getState() != Call.State.IDLE) {
+                    throw new CallStateException(
+                            "cannot put conn back to a call in non-idle state: "
+                            + call.getState());
+                }
+                Log.v(LOG_TAG, "separate conn: " + mPeer.getUriString()
+                        + " from " + mOwner + " back to " + call);
+
+                AudioGroup audioGroup = call.getAudioGroup(); // may be null
+                call.add(this);
+                mSipAudioCall.setAudioGroup(audioGroup);
+                call.hold();
             }
-            */
         }
 
     }
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
index 721b8af..1d33be9 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
@@ -174,10 +174,6 @@
         return state;
     }
 
-    public String getPhoneName() {
-        return "SIP";
-    }
-
     public int getPhoneType() {
         // FIXME: add SIP phone type
         return Phone.PHONE_TYPE_GSM;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index 9f580a3..4cff3de 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -95,6 +95,7 @@
         ignoreResultList.add("http/tests/appcache/fallback.html"); // http://b/issue?id=2713004
         ignoreResultList.add("http/tests/appcache/foreign-iframe-main.html"); // flaky - skips states
         ignoreResultList.add("http/tests/appcache/manifest-with-empty-file.html"); // flaky
+        ignoreResultList.add("http/tests/appcache/origin-quota.html"); // needs clearAllApplicationCaches(), see http://b/issue?id=2944196
         ignoreResultList.add("storage/database-lock-after-reload.html"); // Succeeds but DumpRenderTree does not read result correctly
         ignoreResultList.add("storage/hash-change-with-xhr.html"); // Succeeds but DumpRenderTree does not read result correctly
         ignoreResultList.add("storage/open-database-creation-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld()
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index c40af80..abccf9b 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -338,6 +338,7 @@
     SMALL_SCREEN_ATTR = 0x01010284,
     NORMAL_SCREEN_ATTR = 0x01010285,
     LARGE_SCREEN_ATTR = 0x01010286,
+    XLARGE_SCREEN_ATTR = 0x010102bf,
     REQUIRED_ATTR = 0x0101028e,
 };
 
@@ -572,6 +573,7 @@
             int smallScreen = 1;
             int normalScreen = 1;
             int largeScreen = 1;
+            int xlargeScreen = 1;
             String8 pkg;
             String8 activityName;
             String8 activityLabel;
@@ -754,6 +756,8 @@
                                 NORMAL_SCREEN_ATTR, NULL, 1);
                         largeScreen = getIntegerAttribute(tree,
                                 LARGE_SCREEN_ATTR, NULL, 1);
+                        xlargeScreen = getIntegerAttribute(tree,
+                                XLARGE_SCREEN_ATTR, NULL, 1);
                     } else if (tag == "uses-feature") {
                         String8 name = getAttribute(tree, NAME_ATTR, &error);
 
@@ -1082,10 +1086,15 @@
             if (largeScreen > 0) {
                 largeScreen = targetSdk >= 4 ? -1 : 0;
             }
+            if (xlargeScreen > 0) {
+                // Introduced in Honeycomb.
+                xlargeScreen = targetSdk >= 10 ? -1 : 0;
+            }
             printf("supports-screens:");
             if (smallScreen != 0) printf(" 'small'");
             if (normalScreen != 0) printf(" 'normal'");
             if (largeScreen != 0) printf(" 'large'");
+            if (xlargeScreen != 0) printf(" 'xlarge'");
             printf("\n");
 
             printf("locales:");
diff --git a/voip/java/android/net/sip/SipAudioCall.java b/voip/java/android/net/sip/SipAudioCall.java
index f4be839..3cdd114 100644
--- a/voip/java/android/net/sip/SipAudioCall.java
+++ b/voip/java/android/net/sip/SipAudioCall.java
@@ -244,7 +244,8 @@
      * Also, the {@code AudioStream} may change its group during a call (e.g.,
      * after the call is held/un-held). Finally, the {@code AudioGroup} object
      * returned by this method is undefined after the call ends or the
-     * {@link #close} method is called.
+     * {@link #close} method is called. If a group object is set by
+     * {@link #setAudioGroup(AudioGroup)}, then this method returns that object.
      *
      * @return the {@link AudioGroup} object or null if the RTP stream has not
      *      yet been set up
@@ -253,6 +254,15 @@
     AudioGroup getAudioGroup();
 
     /**
+     * Sets the {@link AudioGroup} object which the {@link AudioStream} object
+     * joins. If {@code audioGroup} is null, then the {@code AudioGroup} object
+     * will be dynamically created when needed.
+     *
+     * @see #getAudioStream
+     */
+    void setAudioGroup(AudioGroup audioGroup);
+
+    /**
      * Checks if the call is established.
      *
      * @return true if the call is established
diff --git a/voip/java/android/net/sip/SipAudioCallImpl.java b/voip/java/android/net/sip/SipAudioCallImpl.java
index 7161309..b8ac6d7 100644
--- a/voip/java/android/net/sip/SipAudioCallImpl.java
+++ b/voip/java/android/net/sip/SipAudioCallImpl.java
@@ -70,7 +70,8 @@
     private ISipSession mSipSession;
     private SdpSessionDescription mPeerSd;
 
-    private AudioStream mRtpSession;
+    private AudioStream mAudioStream;
+    private AudioGroup mAudioGroup;
     private SdpSessionDescription.AudioCodec mCodec;
     private long mSessionId = -1L; // SDP session ID
     private boolean mInCall = false;
@@ -505,11 +506,19 @@
     }
 
     public synchronized AudioStream getAudioStream() {
-        return mRtpSession;
+        return mAudioStream;
     }
 
     public synchronized AudioGroup getAudioGroup() {
-        return ((mRtpSession == null) ? null : mRtpSession.getAudioGroup());
+        if (mAudioGroup != null) return mAudioGroup;
+        return ((mAudioStream == null) ? null : mAudioStream.getAudioGroup());
+    }
+
+    public synchronized void setAudioGroup(AudioGroup group) {
+        if ((mAudioStream != null) && (mAudioStream.getAudioGroup() != null)) {
+            mAudioStream.join(group);
+        }
+        mAudioGroup = group;
     }
 
     private SdpSessionDescription.AudioCodec getCodec(SdpSessionDescription sd) {
@@ -561,7 +570,7 @@
             // TODO: get sample rate from sdp
             mCodec = getCodec(peerSd);
 
-            AudioStream audioStream = mRtpSession;
+            AudioStream audioStream = mAudioStream;
             audioStream.associate(InetAddress.getByName(peerMediaAddress),
                     peerMediaPort);
             audioStream.setCodec(convert(mCodec), mCodec.payloadType);
@@ -580,7 +589,7 @@
                     Log.d(TAG, "   not sending");
                     audioStream.setMode(RtpStream.MODE_RECEIVE_ONLY);
                 }
-            } else {
+
                 /* The recorder volume will be very low if the device is in
                  * IN_CALL mode. Therefore, we have to set the mode to NORMAL
                  * in order to have the normal microphone level.
@@ -590,14 +599,22 @@
                         .setMode(AudioManager.MODE_NORMAL);
             }
 
-            AudioGroup audioGroup = new AudioGroup();
-            audioStream.join(audioGroup);
+            // AudioGroup logic:
+            AudioGroup audioGroup = getAudioGroup();
             if (mHold) {
-                audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
-            } else if (mMuted) {
-                audioGroup.setMode(AudioGroup.MODE_MUTED);
+                if (audioGroup != null) {
+                    audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
+                }
+                // don't create an AudioGroup here; doing so will fail if
+                // there's another AudioGroup out there that's active
             } else {
-                audioGroup.setMode(AudioGroup.MODE_NORMAL);
+                if (audioGroup == null) audioGroup = new AudioGroup();
+                audioStream.join(audioGroup);
+                if (mMuted) {
+                    audioGroup.setMode(AudioGroup.MODE_MUTED);
+                } else {
+                    audioGroup.setMode(AudioGroup.MODE_NORMAL);
+                }
             }
         } catch (Exception e) {
             Log.e(TAG, "call()", e);
@@ -606,20 +623,20 @@
 
     private void stopCall(boolean releaseSocket) {
         Log.d(TAG, "stop audiocall");
-        if (mRtpSession != null) {
-            mRtpSession.join(null);
+        if (mAudioStream != null) {
+            mAudioStream.join(null);
 
             if (releaseSocket) {
-                mRtpSession.release();
-                mRtpSession = null;
+                mAudioStream.release();
+                mAudioStream = null;
             }
         }
     }
 
     private int getLocalMediaPort() {
-        if (mRtpSession != null) return mRtpSession.getLocalPort();
+        if (mAudioStream != null) return mAudioStream.getLocalPort();
         try {
-            AudioStream s = mRtpSession =
+            AudioStream s = mAudioStream =
                     new AudioStream(InetAddress.getByName(getLocalIp()));
             return s.getLocalPort();
         } catch (IOException e) {
diff --git a/voip/jni/rtp/Android.mk b/voip/jni/rtp/Android.mk
index a364355..3bd85aa 100644
--- a/voip/jni/rtp/Android.mk
+++ b/voip/jni/rtp/Android.mk
@@ -32,10 +32,11 @@
 	libutils \
 	libmedia
 
-LOCAL_STATIC_LIBRARIES :=
+LOCAL_STATIC_LIBRARIES := libspeex
 
 LOCAL_C_INCLUDES += \
-	$(JNI_H_INCLUDE)
+	$(JNI_H_INCLUDE) \
+	external/speex/include
 
 LOCAL_CFLAGS += -fvisibility=hidden
 
diff --git a/voip/jni/rtp/AudioGroup.cpp b/voip/jni/rtp/AudioGroup.cpp
index 08a8d1c..b5a4e22 100644
--- a/voip/jni/rtp/AudioGroup.cpp
+++ b/voip/jni/rtp/AudioGroup.cpp
@@ -40,6 +40,8 @@
 #include <media/AudioTrack.h>
 #include <media/mediarecorder.h>
 
+#include <speex/speex_echo.h>
+
 #include "jni.h"
 #include "JNIHelp.h"
 
@@ -445,6 +447,8 @@
     int mDeviceSocket;
     AudioTrack mTrack;
     AudioRecord mRecord;
+    
+    SpeexEchoState *mEchoState;
 
     bool networkLoop();
     bool deviceLoop();
@@ -506,6 +510,7 @@
     mEventQueue = -1;
     mDtmfEvent = -1;
     mDeviceSocket = -1;
+    mEchoState = NULL;
     mNetworkThread = new NetworkThread(this);
     mDeviceThread = new DeviceThread(this);
 }
@@ -518,6 +523,9 @@
     mRecord.stop();
     close(mEventQueue);
     close(mDeviceSocket);
+    if (mEchoState) {
+        speex_echo_state_destroy(mEchoState);
+    }
     while (mChain) {
         AudioStream *next = mChain->mNext;
         delete mChain;
@@ -548,10 +556,11 @@
     }
     LOGD("reported frame count: output %d, input %d", output, input);
 
-    output = (output + sampleCount - 1) / sampleCount * sampleCount;
-    input = (input + sampleCount - 1) / sampleCount * sampleCount;
-    if (input < output * 2) {
-        input = output * 2;
+    if (output < sampleCount * 2) {
+        output = sampleCount * 2;
+    }
+    if (input < sampleCount * 2) {
+        input = sampleCount * 2;
     }
     LOGD("adjusted frame count: output %d, input %d", output, input);
 
@@ -565,7 +574,8 @@
     }
     LOGD("latency: output %d, input %d", mTrack.latency(), mRecord.latency());
 
-    // TODO: initialize echo canceler here.
+    // Initialize echo canceller.
+    mEchoState = speex_echo_state_init(sampleCount, sampleRate);
 
     // Create device socket.
     int pair[2];
@@ -587,7 +597,7 @@
     // Give device socket a reasonable timeout and buffer size.
     timeval tv;
     tv.tv_sec = 0;
-    tv.tv_usec = 1000 * sampleCount / sampleRate * 500;
+    tv.tv_usec = 1000 * sampleCount / sampleRate * 1000;
     if (setsockopt(pair[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) ||
         setsockopt(pair[0], SOL_SOCKET, SO_RCVBUF, &output, sizeof(output)) ||
         setsockopt(pair[1], SOL_SOCKET, SO_SNDBUF, &output, sizeof(output))) {
@@ -632,6 +642,7 @@
     if (mode == MUTED) {
         mRecord.stop();
     } else {
+        speex_echo_state_reset(mEchoState);
         mRecord.start();
     }
 
@@ -764,38 +775,63 @@
     if (recv(mDeviceSocket, output, sizeof(output), 0) <= 0) {
         memset(output, 0, sizeof(output));
     }
-    if (mTrack.write(output, sizeof(output)) != (int)sizeof(output)) {
-        LOGE("cannot write to AudioTrack");
+
+    int16_t input[mSampleCount];
+    int toWrite = mSampleCount;
+    int toRead = (mMode == MUTED) ? 0 : mSampleCount;
+    int chances = 100;
+
+    while (--chances > 0 && (toWrite > 0 || toRead > 0)) {
+        if (toWrite > 0) {
+            AudioTrack::Buffer buffer;
+            buffer.frameCount = toWrite;
+
+            status_t status = mTrack.obtainBuffer(&buffer, 1);
+            if (status == NO_ERROR) {
+                memcpy(buffer.i8, &output[mSampleCount - toWrite], buffer.size);
+                toWrite -= buffer.frameCount;
+                mTrack.releaseBuffer(&buffer);
+            } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
+                LOGE("cannot write to AudioTrack");
+                return false;
+            }
+        }
+
+        if (toRead > 0) {
+            AudioRecord::Buffer buffer;
+            buffer.frameCount = mRecord.frameCount();
+
+            status_t status = mRecord.obtainBuffer(&buffer, 1);
+            if (status == NO_ERROR) {
+                int count = ((int)buffer.frameCount < toRead) ?
+                        buffer.frameCount : toRead;
+                memcpy(&input[mSampleCount - toRead], buffer.i8, count * 2);
+                toRead -= count;
+                if (buffer.frameCount < mRecord.frameCount()) {
+                    buffer.frameCount = count;
+                }
+                mRecord.releaseBuffer(&buffer);
+            } else if (status != TIMED_OUT && status != WOULD_BLOCK) {
+                LOGE("cannot read from AudioRecord");
+                return false;
+            }
+        }
+    }
+
+    if (!chances) {
+        LOGE("device loop timeout");
         return false;
     }
 
     if (mMode != MUTED) {
-        uint32_t frameCount = mRecord.frameCount();
-        AudioRecord::Buffer input;
-        input.frameCount = frameCount;
-
-        if (mRecord.obtainBuffer(&input, -1) != NO_ERROR) {
-            LOGE("cannot read from AudioRecord");
-            return false;
-        }
-
-        if (input.frameCount < (uint32_t)mSampleCount) {
-            input.frameCount = 0;
+        if (mMode == NORMAL) {
+            send(mDeviceSocket, input, sizeof(input), MSG_DONTWAIT);
         } else {
-            if (mMode == NORMAL) {
-                send(mDeviceSocket, input.i8, sizeof(output), MSG_DONTWAIT);
-            } else {
-                // TODO: Echo canceller runs here.
-                send(mDeviceSocket, input.i8, sizeof(output), MSG_DONTWAIT);
-            }
-            if (input.frameCount < frameCount) {
-                input.frameCount = mSampleCount;
-            }
+            int16_t result[mSampleCount];
+            speex_echo_cancellation(mEchoState, input, output, result);
+            send(mDeviceSocket, result, sizeof(result), MSG_DONTWAIT);
         }
-
-        mRecord.releaseBuffer(&input);
     }
-
     return true;
 }
 
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 01bc919..559be85 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -432,6 +432,38 @@
         return 0;
     }
 
+    /**
+     * Returns a copy of this WifiConfiguration.
+     *
+     * @return a copy of this WifiConfiguration.
+     * @hide
+     */
+    public WifiConfiguration clone() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.networkId = networkId;
+        config.status = status;
+        config.SSID = SSID;
+        config.BSSID = BSSID;
+        config.preSharedKey = preSharedKey;
+
+        for (int i = 0; i < wepKeys.length; i++)
+            config.wepKeys[i] = wepKeys[i];
+
+        config.wepTxKeyIndex = wepTxKeyIndex;
+        config.priority = priority;
+        config.hiddenSSID = hiddenSSID;
+        config.allowedKeyManagement   = (BitSet) allowedKeyManagement.clone();
+        config.allowedProtocols       = (BitSet) allowedProtocols.clone();
+        config.allowedAuthAlgorithms  = (BitSet) allowedAuthAlgorithms.clone();
+        config.allowedPairwiseCiphers = (BitSet) allowedPairwiseCiphers.clone();
+        config.allowedGroupCiphers    = (BitSet) allowedGroupCiphers.clone();
+
+        for (int i = 0; i < enterpriseFields.length; i++) {
+            config.enterpriseFields[i].setValue(enterpriseFields[i].value());
+        }
+        return config;
+    }
+
     /** Implement the Parcelable interface {@hide} */
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(networkId);
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 19c4eb0..1fab02e 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -79,6 +79,7 @@
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.BitSet;
+import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -126,6 +127,7 @@
     private int mReconnectCount = 0;
     private boolean mIsScanMode = false;
     private boolean mConfigChanged = false;
+    private List<WifiConfiguration> mConfiguredNetworks = new ArrayList<WifiConfiguration>();
 
     /**
      * Instance of the bluetooth headset helper. This needs to be created
@@ -232,12 +234,8 @@
     private static final int CMD_BLACKLIST_NETWORK                = 56;
     /* Clear the blacklist network list */
     private static final int CMD_CLEAR_BLACKLIST                  = 57;
-    /* Get the configured networks */
-    private static final int CMD_GET_NETWORK_CONFIG               = 58;
     /* Save configuration */
-    private static final int CMD_SAVE_CONFIG                      = 59;
-    /* Connection status */
-    private static final int CMD_CONNECTION_STATUS                = 60;
+    private static final int CMD_SAVE_CONFIG                      = 58;
 
     /* Supplicant commands after driver start*/
     /* Initiate a scan */
@@ -379,10 +377,6 @@
     /* Soft Ap is running */
     private HierarchicalState mSoftApStartedState = new SoftApStartedState();
 
-    /* Argument for Message object to indicate a synchronous call */
-    private static final int SYNCHRONOUS_CALL = 1;
-    private static final int ASYNCHRONOUS_CALL = 0;
-
 
     /**
      * One of  {@link WifiManager#WIFI_STATE_DISABLED},
@@ -488,7 +482,7 @@
     /**
      * TODO: doc
      */
-    public boolean pingSupplicant() {
+    public boolean syncPingSupplicant() {
         return sendSyncMessage(CMD_PING_SUPPLICANT).boolValue;
     }
 
@@ -535,14 +529,14 @@
     /**
      * TODO: doc
      */
-    public int getWifiState() {
+    public int syncGetWifiState() {
         return mWifiState.get();
     }
 
     /**
      * TODO: doc
      */
-    public String getWifiStateByName() {
+    public String syncGetWifiStateByName() {
         switch (mWifiState.get()) {
             case WIFI_STATE_DISABLING:
                 return "disabling";
@@ -562,14 +556,14 @@
     /**
      * TODO: doc
      */
-    public int getWifiApState() {
+    public int syncGetWifiApState() {
         return mWifiApState.get();
     }
 
     /**
      * TODO: doc
      */
-    public String getWifiApStateByName() {
+    public String syncGetWifiApStateByName() {
         switch (mWifiApState.get()) {
             case WIFI_AP_STATE_DISABLING:
                 return "disabling";
@@ -591,11 +585,11 @@
      * @return a {@link WifiInfo} object containing information about the current connection
      *
      */
-    public WifiInfo requestConnectionInfo() {
+    public WifiInfo syncRequestConnectionInfo() {
         return mWifiInfo;
     }
 
-    public DhcpInfo getDhcpInfo() {
+    public DhcpInfo syncGetDhcpInfo() {
         return mDhcpInfo;
     }
 
@@ -635,7 +629,7 @@
     /**
      * TODO: doc
      */
-    public List<ScanResult> getScanResultsList() {
+    public List<ScanResult> syncGetScanResultsList() {
         return mScanResults;
     }
 
@@ -665,12 +659,19 @@
      *
      * @return network id of the new network
      */
-    public int addOrUpdateNetwork(WifiConfiguration config) {
+    public int syncAddOrUpdateNetwork(WifiConfiguration config) {
         return sendSyncMessage(CMD_ADD_OR_UPDATE_NETWORK, config).intValue;
     }
 
-    public List<WifiConfiguration> getConfiguredNetworks() {
-        return sendSyncMessage(CMD_GET_NETWORK_CONFIG).configList;
+    public List<WifiConfiguration> syncGetConfiguredNetworks() {
+        List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
+        synchronized (mConfiguredNetworks) {
+            Iterator<WifiConfiguration> iterator = mConfiguredNetworks.iterator();
+            while(iterator.hasNext()) {
+                networks.add(iterator.next().clone());
+            }
+        }
+        return networks;
     }
 
     /**
@@ -678,7 +679,7 @@
      *
      * @param networkId id of the network to be removed
      */
-    public boolean removeNetwork(int networkId) {
+    public boolean syncRemoveNetwork(int networkId) {
         return sendSyncMessage(obtainMessage(CMD_REMOVE_NETWORK, networkId, 0)).boolValue;
     }
 
@@ -697,7 +698,7 @@
      * @param disableOthers true, if all other networks have to be disabled
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
-    public boolean enableNetwork(int netId, boolean disableOthers) {
+    public boolean syncEnableNetwork(int netId, boolean disableOthers) {
         return sendSyncMessage(CMD_ENABLE_NETWORK,
                 new EnableNetParams(netId, disableOthers)).boolValue;
     }
@@ -708,7 +709,7 @@
      * @param netId network id of the network
      * @return {@code true} if the operation succeeds, {@code false} otherwise
      */
-    public boolean disableNetwork(int netId) {
+    public boolean syncDisableNetwork(int netId) {
         return sendSyncMessage(obtainMessage(CMD_DISABLE_NETWORK, netId, 0)).boolValue;
     }
 
@@ -746,23 +747,6 @@
         sendMessage(obtainMessage(CMD_FORGET_NETWORK, netId, 0));
     }
 
-    /**
-     * Get detailed status of the connection
-     *
-     * @return Example status result
-     *  bssid=aa:bb:cc:dd:ee:ff
-     *  ssid=TestNet
-     *  id=3
-     *  pairwise_cipher=NONE
-     *  group_cipher=NONE
-     *  key_mgmt=NONE
-     *  wpa_state=COMPLETED
-     *  ip_address=X.X.X.X
-     */
-    public String status() {
-        return sendSyncMessage(CMD_CONNECTION_STATUS).stringValue;
-    }
-
     public void enableRssiPolling(boolean enabled) {
        sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0));
     }
@@ -771,7 +755,7 @@
      *
      * @return RSSI value, -1 on failure
      */
-    public int getRssi() {
+    public int syncGetRssi() {
         return sendSyncMessage(CMD_GET_RSSI).intValue;
     }
 
@@ -780,7 +764,7 @@
      *
      * @return RSSI value, -1 on failure
      */
-    public int getRssiApprox() {
+    public int syncGetRssiApprox() {
         return sendSyncMessage(CMD_GET_RSSI_APPROX).intValue;
     }
 
@@ -789,7 +773,7 @@
      *
      * @return link speed, -1 on failure
      */
-    public int getLinkSpeed() {
+    public int syncGetLinkSpeed() {
         return sendSyncMessage(CMD_GET_LINK_SPEED).intValue;
     }
 
@@ -798,7 +782,7 @@
      *
      * @return MAC address, null on failure
      */
-    public String getMacAddress() {
+    public String syncGetMacAddress() {
         return sendSyncMessage(CMD_GET_MAC_ADDR).stringValue;
     }
 
@@ -895,7 +879,7 @@
      *
      * TODO: deprecate this
      */
-    public boolean saveConfig() {
+    public boolean syncSaveConfig() {
         return sendSyncMessage(CMD_SAVE_CONFIG).boolValue;
     }
 
@@ -915,7 +899,6 @@
         int intValue;
         String stringValue;
         Object objValue;
-        List<WifiConfiguration> configList;
     }
 
     class SyncParams {
@@ -931,12 +914,10 @@
     }
 
     /**
-     * message.arg2 is reserved to indicate synchronized
      * message.obj is used to store SyncParams
      */
     private SyncReturn syncedSend(Message msg) {
         SyncParams syncParams = (SyncParams) msg.obj;
-        msg.arg2 = SYNCHRONOUS_CALL;
         synchronized(syncParams) {
             if (DBG) Log.d(TAG, "syncedSend " + msg);
             sendMessage(msg);
@@ -995,7 +976,7 @@
 
         mWifiState.set(wifiState);
 
-        if (DBG) Log.d(TAG, "setWifiState: " + getWifiStateByName());
+        if (DBG) Log.d(TAG, "setWifiState: " + syncGetWifiStateByName());
 
         final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -1020,7 +1001,7 @@
         // Update state
         mWifiApState.set(wifiApState);
 
-        if (DBG) Log.d(TAG, "setWifiApState: " + getWifiApStateByName());
+        if (DBG) Log.d(TAG, "setWifiApState: " + syncGetWifiApStateByName());
 
         final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -1413,7 +1394,8 @@
         mContext.sendStickyBroadcast(intent);
     }
 
-    private void sendSupplicantConfigChangedBroadcast() {
+    private void updateConfigAndSendChangeBroadcast() {
+        updateConfiguredNetworks();
         Intent intent = new Intent(WifiManager.SUPPLICANT_CONFIG_CHANGED_ACTION);
         mContext.sendBroadcast(intent);
     }
@@ -1487,14 +1469,13 @@
     private void enableAllNetworks() {
         if (mEnableAllNetworks) {
             mEnableAllNetworks = false;
-            List<WifiConfiguration> configList = getConfiguredNetworksNative();
-            for (WifiConfiguration config : configList) {
+            for (WifiConfiguration config : mConfiguredNetworks) {
                 if(config != null && config.status == Status.DISABLED) {
                     WifiNative.enableNetworkCommand(config.networkId, false);
                 }
             }
             WifiNative.saveConfigCommand();
-            sendSupplicantConfigChangedBroadcast();
+            updateConfigAndSendChangeBroadcast();
         }
     }
 
@@ -1689,44 +1670,47 @@
         return -1;
     }
 
-    private List<WifiConfiguration> getConfiguredNetworksNative() {
+    private void updateConfiguredNetworks() {
         String listStr = WifiNative.listNetworksCommand();
         mLastPriority = 0;
-        List<WifiConfiguration> networks =
-            new ArrayList<WifiConfiguration>();
-        if (listStr == null)
-            return networks;
 
-        String[] lines = listStr.split("\n");
-        // Skip the first line, which is a header
-        for (int i = 1; i < lines.length; i++) {
-            String[] result = lines[i].split("\t");
-            // network-id | ssid | bssid | flags
-            WifiConfiguration config = new WifiConfiguration();
-            try {
-                config.networkId = Integer.parseInt(result[0]);
-            } catch(NumberFormatException e) {
-                continue;
-            }
-            if (result.length > 3) {
-                if (result[3].indexOf("[CURRENT]") != -1)
-                    config.status = WifiConfiguration.Status.CURRENT;
-                else if (result[3].indexOf("[DISABLED]") != -1)
-                    config.status = WifiConfiguration.Status.DISABLED;
-                else
+        synchronized (mConfiguredNetworks) {
+            mConfiguredNetworks.clear();
+
+            if (listStr == null)
+                return;
+
+            String[] lines = listStr.split("\n");
+            // Skip the first line, which is a header
+            for (int i = 1; i < lines.length; i++) {
+                String[] result = lines[i].split("\t");
+                // network-id | ssid | bssid | flags
+                WifiConfiguration config = new WifiConfiguration();
+                try {
+                    config.networkId = Integer.parseInt(result[0]);
+                } catch(NumberFormatException e) {
+                    continue;
+                }
+                if (result.length > 3) {
+                    if (result[3].indexOf("[CURRENT]") != -1)
+                        config.status = WifiConfiguration.Status.CURRENT;
+                    else if (result[3].indexOf("[DISABLED]") != -1)
+                        config.status = WifiConfiguration.Status.DISABLED;
+                    else
+                        config.status = WifiConfiguration.Status.ENABLED;
+                } else {
                     config.status = WifiConfiguration.Status.ENABLED;
-            } else {
-                config.status = WifiConfiguration.Status.ENABLED;
+                }
+                readNetworkVariables(config);
+                if (config.priority > mLastPriority) {
+                    mLastPriority = config.priority;
+                }
+                mConfiguredNetworks.add(config);
             }
-            readNetworkVariables(config);
-            if (config.priority > mLastPriority) {
-                mLastPriority = config.priority;
-            }
-            networks.add(config);
         }
-        return networks;
     }
 
+
     /**
      * Read the variables from the supplicant daemon that are needed to
      * fill in the WifiConfiguration object.
@@ -2082,16 +2066,11 @@
                 case CMD_GET_LINK_SPEED:
                 case CMD_GET_MAC_ADDR:
                 case CMD_SAVE_CONFIG:
-                case CMD_CONNECTION_STATUS:
-                case CMD_GET_NETWORK_CONFIG:
-                    if (message.arg2 == SYNCHRONOUS_CALL) {
-                        syncParams = (SyncParams) message.obj;
-                        syncParams.mSyncReturn.boolValue = false;
-                        syncParams.mSyncReturn.intValue = -1;
-                        syncParams.mSyncReturn.stringValue = null;
-                        syncParams.mSyncReturn.configList = null;
-                        notifyOnMsgObject(message);
-                    }
+                    syncParams = (SyncParams) message.obj;
+                    syncParams.mSyncReturn.boolValue = false;
+                    syncParams.mSyncReturn.intValue = -1;
+                    syncParams.mSyncReturn.stringValue = null;
+                    notifyOnMsgObject(message);
                     break;
                 case CMD_ENABLE_RSSI_POLL:
                     mEnableRssiPolling = (message.arg1 == 1);
@@ -2423,6 +2402,8 @@
 
                     mWifiInfo.setMacAddress(WifiNative.getMacAddressCommand());
 
+                    updateConfigAndSendChangeBroadcast();
+
                     //TODO: initialize and fix multicast filtering
                     //mWM.initializeMulticastFiltering();
 
@@ -2521,48 +2502,33 @@
                     syncParams = (SyncParams) message.obj;
                     config = (WifiConfiguration) syncParams.mParameter;
                     syncParams.mSyncReturn.intValue = addOrUpdateNetworkNative(config);
+                    updateConfigAndSendChangeBroadcast();
                     notifyOnMsgObject(message);
-                    sendSupplicantConfigChangedBroadcast();
                     break;
                 case CMD_REMOVE_NETWORK:
                     EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-                    if (message.arg2 == SYNCHRONOUS_CALL) {
-                        syncParams = (SyncParams) message.obj;
-                        syncParams.mSyncReturn.boolValue = WifiNative.removeNetworkCommand(
-                                message.arg1);
-                        notifyOnMsgObject(message);
-                    } else {
-                        /* asynchronous handling */
-                        WifiNative.removeNetworkCommand(message.arg1);
-                    }
-                    sendSupplicantConfigChangedBroadcast();
+                    syncParams = (SyncParams) message.obj;
+                    syncParams.mSyncReturn.boolValue = WifiNative.removeNetworkCommand(
+                            message.arg1);
+                    updateConfigAndSendChangeBroadcast();
+                    notifyOnMsgObject(message);
                     break;
                 case CMD_ENABLE_NETWORK:
                     EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-                    if (message.arg2 == SYNCHRONOUS_CALL) {
-                        syncParams = (SyncParams) message.obj;
-                        EnableNetParams enableNetParams = (EnableNetParams) syncParams.mParameter;
-                        syncParams.mSyncReturn.boolValue = WifiNative.enableNetworkCommand(
-                                enableNetParams.netId, enableNetParams.disableOthers);
-                        notifyOnMsgObject(message);
-                    } else {
-                        /* asynchronous handling */
-                        WifiNative.enableNetworkCommand(message.arg1, message.arg2 == 1);
-                    }
-                    sendSupplicantConfigChangedBroadcast();
+                    syncParams = (SyncParams) message.obj;
+                    EnableNetParams enableNetParams = (EnableNetParams) syncParams.mParameter;
+                    syncParams.mSyncReturn.boolValue = WifiNative.enableNetworkCommand(
+                            enableNetParams.netId, enableNetParams.disableOthers);
+                    updateConfigAndSendChangeBroadcast();
+                    notifyOnMsgObject(message);
                     break;
                 case CMD_DISABLE_NETWORK:
                     EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-                    if (message.arg2 == SYNCHRONOUS_CALL) {
-                        syncParams = (SyncParams) message.obj;
-                        syncParams.mSyncReturn.boolValue = WifiNative.disableNetworkCommand(
-                                message.arg1);
-                        notifyOnMsgObject(message);
-                    } else {
-                        /* asynchronous handling */
-                        WifiNative.disableNetworkCommand(message.arg1);
-                    }
-                    sendSupplicantConfigChangedBroadcast();
+                    syncParams = (SyncParams) message.obj;
+                    syncParams.mSyncReturn.boolValue = WifiNative.disableNetworkCommand(
+                            message.arg1);
+                    updateConfigAndSendChangeBroadcast();
+                    notifyOnMsgObject(message);
                     break;
                 case CMD_BLACKLIST_NETWORK:
                     EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
@@ -2571,20 +2537,10 @@
                 case CMD_CLEAR_BLACKLIST:
                     WifiNative.clearBlacklistCommand();
                     break;
-                case CMD_GET_NETWORK_CONFIG:
-                    syncParams = (SyncParams) message.obj;
-                    syncParams.mSyncReturn.configList = getConfiguredNetworksNative();
-                    notifyOnMsgObject(message);
-                    break;
                 case CMD_SAVE_CONFIG:
-                    if (message.arg2 == SYNCHRONOUS_CALL) {
-                        syncParams = (SyncParams) message.obj;
-                        syncParams.mSyncReturn.boolValue = WifiNative.saveConfigCommand();
-                        notifyOnMsgObject(message);
-                    } else {
-                        /* asynchronous handling */
-                        WifiNative.saveConfigCommand();
-                    }
+                    syncParams = (SyncParams) message.obj;
+                    syncParams.mSyncReturn.boolValue = WifiNative.saveConfigCommand();
+                    notifyOnMsgObject(message);
                     // Inform the backup manager about a data change
                     IBackupManager ibm = IBackupManager.Stub.asInterface(
                             ServiceManager.getService(Context.BACKUP_SERVICE));
@@ -2596,11 +2552,6 @@
                         }
                     }
                     break;
-                case CMD_CONNECTION_STATUS:
-                    syncParams = (SyncParams) message.obj;
-                    syncParams.mSyncReturn.stringValue = WifiNative.statusCommand();
-                    notifyOnMsgObject(message);
-                    break;
                 case CMD_GET_MAC_ADDR:
                     syncParams = (SyncParams) message.obj;
                     syncParams.mSyncReturn.stringValue = WifiNative.getMacAddressCommand();
@@ -2623,12 +2574,12 @@
                         WifiNative.enableNetworkCommand(netId, false);
                     }
                     WifiNative.saveConfigCommand();
-                    sendSupplicantConfigChangedBroadcast();
+                    updateConfigAndSendChangeBroadcast();
                     break;
                 case CMD_FORGET_NETWORK:
                     WifiNative.removeNetworkCommand(message.arg1);
                     WifiNative.saveConfigCommand();
-                    sendSupplicantConfigChangedBroadcast();
+                    updateConfigAndSendChangeBroadcast();
                     break;
                 default:
                     return NOT_HANDLED;
@@ -2905,8 +2856,7 @@
                     }
                     // Reset the priority of each network at start or if it goes too high.
                     if (mLastPriority == -1 || mLastPriority > 1000000) {
-                        List<WifiConfiguration> configList = getConfiguredNetworksNative();
-                        for (WifiConfiguration conf : configList) {
+                        for (WifiConfiguration conf : mConfiguredNetworks) {
                             if (conf.networkId != -1) {
                                 conf.priority = 0;
                                 addOrUpdateNetworkNative(conf);
@@ -2927,10 +2877,11 @@
                     WifiNative.enableNetworkCommand(netId, true);
                     WifiNative.reconnectCommand();
                     mEnableAllNetworks = true;
-                    /* Dont send a supplicant config change broadcast here
-                     * as it is better to not expose the temporary disabling
-                     * of all networks
+                    /* update the configured networks but not send a
+                     * broadcast to avoid a fetch from settings
+                     * during this temporary disabling of networks
                      */
+                    updateConfiguredNetworks();
                     break;
                 case SCAN_RESULTS_EVENT:
                     /* Set the scan setting back to "connect" mode */
@@ -3090,7 +3041,7 @@
                           Log.e(TAG, "Failed " +
                                   mReconnectCount + " times, Disabling " + mLastNetworkId);
                       WifiNative.disableNetworkCommand(mLastNetworkId);
-                      sendSupplicantConfigChangedBroadcast();
+                      updateConfigAndSendChangeBroadcast();
                   }
 
                   /* DHCP times out after about 30 seconds, we do a
@@ -3503,7 +3454,7 @@
                      WifiNative.disableNetworkCommand(mWifiInfo.getNetworkId());
                      mPasswordKeyMayBeIncorrect = false;
                      sendSupplicantStateChangedBroadcast(stateChangeResult, true);
-                     sendSupplicantConfigChangedBroadcast();
+                     updateConfigAndSendChangeBroadcast();
                  }
                  else {
                      sendSupplicantStateChangedBroadcast(stateChangeResult, false);
@@ -3563,7 +3514,7 @@
                  }
                  if (mLoopDetectCount > MAX_SUPPLICANT_LOOP_ITERATIONS) {
                      WifiNative.disableNetworkCommand(stateChangeResult.networkId);
-                     sendSupplicantConfigChangedBroadcast();
+                     updateConfigAndSendChangeBroadcast();
                      mLoopDetectCount = 0;
                  }