Merge "A little less verbosity in stagefright and special treatment for the error state while shutting down."
diff --git a/Android.mk b/Android.mk
index ab1e7ea..ec6f96b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -111,8 +111,8 @@
 	core/java/android/net/INetworkManagementEventObserver.aidl \
 	core/java/android/os/ICheckinService.aidl \
 	core/java/android/os/IMessenger.aidl \
-	core/java/android/os/IMountService.aidl \
-	core/java/android/os/IMountServiceListener.aidl \
+	core/java/android/os/storage/IMountService.aidl \
+	core/java/android/os/storage/IMountServiceListener.aidl \
 	core/java/android/os/INetworkManagementService.aidl \
 	core/java/android/os/INetStatService.aidl \
 	core/java/android/os/IParentalControlCallback.aidl \
diff --git a/api/current.xml b/api/current.xml
index e673f0f..b155c45 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -117646,6 +117646,218 @@
 </method>
 </class>
 </package>
+<package name="android.os.storage"
+>
+<class name="StorageEventListener"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="StorageEventListener"
+ type="android.os.storage.StorageEventListener"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="onStorageStateChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+<parameter name="oldState" type="java.lang.String">
+</parameter>
+<parameter name="newState" type="java.lang.String">
+</parameter>
+</method>
+<method name="onUsbMassStorageConnectionChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="connected" type="boolean">
+</parameter>
+</method>
+</class>
+<class name="StorageManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="disableUsbMassStorage"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="enableUsbMassStorage"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isUsbMassStorageConnected"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isUsbMassStorageEnabled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="registerListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.os.storage.StorageEventListener">
+</parameter>
+</method>
+<method name="unregisterListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.os.storage.StorageEventListener">
+</parameter>
+</method>
+</class>
+<class name="StorageResultCode"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="StorageResultCode"
+ type="android.os.storage.StorageResultCode"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="OperationFailedInternalError"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationFailedMediaBlank"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationFailedMediaCorrupt"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationFailedNoMedia"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationFailedVolumeNotMounted"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OperationSucceeded"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
 <package name="android.preference"
 >
 <class name="CheckBoxPreference"
@@ -136301,126 +136513,6 @@
 </method>
 </interface>
 </package>
-<package name="android.storage"
->
-<interface name="StorageEventListener"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<method name="onMediaInserted"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="label" type="java.lang.String">
-</parameter>
-<parameter name="path" type="java.lang.String">
-</parameter>
-<parameter name="major" type="int">
-</parameter>
-<parameter name="minor" type="int">
-</parameter>
-</method>
-<method name="onMediaRemoved"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="label" type="java.lang.String">
-</parameter>
-<parameter name="path" type="java.lang.String">
-</parameter>
-<parameter name="major" type="int">
-</parameter>
-<parameter name="minor" type="int">
-</parameter>
-<parameter name="clean" type="boolean">
-</parameter>
-</method>
-<method name="onShareAvailabilityChanged"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="method" type="java.lang.String">
-</parameter>
-<parameter name="available" type="boolean">
-</parameter>
-</method>
-<method name="onVolumeStateChanged"
- return="void"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="label" type="java.lang.String">
-</parameter>
-<parameter name="path" type="java.lang.String">
-</parameter>
-<parameter name="oldState" type="java.lang.String">
-</parameter>
-<parameter name="newState" type="java.lang.String">
-</parameter>
-</method>
-</interface>
-<class name="StorageManager"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<method name="registerListener"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="listener" type="android.storage.StorageEventListener">
-</parameter>
-</method>
-<method name="unregisterListener"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="listener" type="android.storage.StorageEventListener">
-</parameter>
-</method>
-</class>
-</package>
 <package name="android.telephony"
 >
 <class name="CellLocation"
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 45d7546..4923eee 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -84,7 +84,7 @@
 import android.os.StatFs;
 import android.os.Vibrator;
 import android.os.FileUtils.FileStatus;
-import android.storage.StorageManager;
+import android.os.storage.StorageManager;
 import android.telephony.TelephonyManager;
 import android.text.ClipboardManager;
 import android.util.AndroidRuntimeException;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 5aefe4c..b4a0bf8 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1110,7 +1110,7 @@
      * @see #SENSOR_SERVICE
      * @see android.hardware.SensorManager
      * @see #STORAGE_SERVICE
-     * @see android.storage.StorageManager
+     * @see android.os.storage.StorageManager
      * @see #VIBRATOR_SERVICE
      * @see android.os.Vibrator
      * @see #CONNECTIVITY_SERVICE
@@ -1243,11 +1243,11 @@
     
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
-     * android.storage.StorageManager} for accesssing system storage
+     * android.os.storage.StorageManager} for accesssing system storage
      * functions.
      *
      * @see #getSystemService
-     * @see android.storage.StorageManager
+     * @see android.os.storage.StorageManager
      */
     public static final String STORAGE_SERVICE = "storage";
 
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index bac55cc..b31df32 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2138,7 +2138,7 @@
                     havePerm = true;
                 }
                 if (writePermission != null) {
-                    writePermission = readPermission.intern();
+                    writePermission = writePermission.intern();
                     havePerm = true;
                 }
 
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 9491bd4..ef1f3be 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -18,7 +18,7 @@
 
 import java.io.File;
 
-import android.os.IMountService;
+import android.os.storage.IMountService;
 
 /**
  * Provides access to environment variables.
diff --git a/core/java/android/os/IMountServiceListener.aidl b/core/java/android/os/IMountServiceListener.aidl
deleted file mode 100644
index 3df64b2..0000000
--- a/core/java/android/os/IMountServiceListener.aidl
+++ /dev/null
@@ -1,66 +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;
-
-/**
- * Callback class for receiving events from MountService.
- *
- * @hide
- */
-interface IMountServiceListener {
-    /**
-     * A sharing method has changed availability state.
-     *
-     * @param method The share method which has changed.
-     * @param available The share availability state.
-     */
-    void onShareAvailabilityChanged(String method, boolean available);
-
-    /**
-     * Media has been inserted
-     *
-     * @param label The volume label.
-     * @param path The volume mount path.
-     * @param major The backing device major number.
-     * @param minor The backing device minor number.
-     */
-    void onMediaInserted(String label, String path, int major, int minor);
-
-    /**
-     * Media has been removed
-     *
-     * @param label The volume label.
-     * @param path The volume mount path.
-     * @param major The backing device major number.
-     * @param minor The backing device minor number.
-     * @param clean Indicates if the removal was clean (unmounted first).
-     */
-    void onMediaRemoved(String label, String path, int major, int minor, boolean clean);
-
-    /**
-     *  Volume state has changed.
-     *
-     * @param label The volume label.
-     * @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 onVolumeStateChanged(String label, String path, String oldState, String newState);
-
-}
diff --git a/core/java/android/os/MountServiceListener.java b/core/java/android/os/MountServiceListener.java
deleted file mode 100644
index a68f464..0000000
--- a/core/java/android/os/MountServiceListener.java
+++ /dev/null
@@ -1,69 +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;
-
-/**
- * Callback class for receiving progress reports during a restore operation.  These
- * methods will all be called on your application's main thread.
- * @hide
- */
-public abstract class MountServiceListener {
-    /**
-     * A sharing method has changed availability state.
-     *
-     * @param method The share method which has changed.
-     * @param available The share availability state.
-     */
-    void shareAvailabilityChange(String method, boolean available) {
-    }
-
-    /**
-     * Media has been inserted
-     *
-     * @param label The volume label.
-     * @param path The volume mount path.
-     * @param major The backing device major number.
-     * @param minor The backing device minor number.
-     */
-    void mediaInserted(String label, String path, int major, int minor) {
-    }
-
-    /**
-     * Media has been removed
-     *
-     * @param label The volume label.
-     * @param path The volume mount path.
-     * @param major The backing device major number.
-     * @param minor The backing device minor number.
-     * @param clean Indicates if the removal was clean (unmounted first).
-     */
-    void mediaRemoved(String label, String path, int major, int minor, boolean clean) {
-    }
-
-    /**
-     *  Volume state has changed.
-     *
-     * @param label The volume label.
-     * @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 volumeStateChange(String label, String path, String oldState, String newState) {
-    }
-}
diff --git a/core/java/android/os/MountServiceResultCode.java b/core/java/android/os/MountServiceResultCode.java
deleted file mode 100644
index e71dbf4..0000000
--- a/core/java/android/os/MountServiceResultCode.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 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;
-
-import java.io.IOException;
-
-/**
- * Class that provides access to constants returned from MountService APIs
- *
- * {@hide}
- */
-public class MountServiceResultCode
-{
-    public static final int OperationSucceeded               =  0;
-    public static final int OperationFailedInternalError     = -1;
-    public static final int OperationFailedNoMedia           = -2;
-    public static final int OperationFailedMediaBlank        = -3;
-    public static final int OperationFailedMediaCorrupt      = -4;
-    public static final int OperationFailedVolumeNotMounted  = -5;
-}
diff --git a/core/java/android/os/Power.java b/core/java/android/os/Power.java
index bc76180..b3df522 100644
--- a/core/java/android/os/Power.java
+++ b/core/java/android/os/Power.java
@@ -18,7 +18,7 @@
 
 import java.io.IOException;
 import android.os.ServiceManager;
-import android.os.IMountService;
+import android.os.storage.IMountService;
 
 /**
  * Class that provides access to some of the power management functions.
diff --git a/core/java/android/os/IMountService.aidl b/core/java/android/os/storage/IMountService.aidl
similarity index 82%
rename from core/java/android/os/IMountService.aidl
rename to core/java/android/os/storage/IMountService.aidl
index a5828f6..84e3f58 100644
--- a/core/java/android/os/IMountService.aidl
+++ b/core/java/android/os/storage/IMountService.aidl
@@ -15,14 +15,15 @@
 ** limitations under the License.
 */
 
-package android.os;
+package android.os.storage;
 
-import android.os.IMountServiceListener;
+import android.os.storage.IMountServiceListener;
 
 /** 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
+ * @hide - Applications should use android.os.storage.StorageManager to access
+ * storage functions.
  */
 interface IMountService
 {
@@ -38,31 +39,19 @@
     void unregisterListener(IMountServiceListener listener);
 
     /**
-     * Gets an Array of supported share methods
+     * Returns true if a USB mass storage host is connected
      */
-    String[] getShareMethodList();
+    boolean isUsbMassStorageConnected();
 
     /**
-     * Returns true if the share method is available
+     * Enables / disables USB mass storage.
      */
-    boolean getShareMethodAvailable(String method);
+    int setUsbMassStorageEnabled(boolean enable);
 
     /**
-     * Shares a volume via the specified method
-     * Returns an int consistent with MountServiceResultCode
+     * Returns true if a USB mass storage host is enabled (media is shared)
      */
-    int shareVolume(String path, String method);
-
-    /**
-     * Unshares a volume via the specified method
-     * Returns an int consistent with MountServiceResultCode
-     */
-    int unshareVolume(String path, String method);
-
-    /**
-     * Returns true if the volume is shared via the specified method.
-     */
-    boolean getVolumeShared(String path, String method);
+    boolean isUsbMassStorageEnabled();
 
     /**
      * Mount external storage at given mount point.
diff --git a/core/java/android/os/storage/IMountServiceListener.aidl b/core/java/android/os/storage/IMountServiceListener.aidl
new file mode 100644
index 0000000..883413a
--- /dev/null
+++ b/core/java/android/os/storage/IMountServiceListener.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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/MountServiceListener.java b/core/java/android/os/storage/MountServiceListener.java
new file mode 100644
index 0000000..bebb3f6
--- /dev/null
+++ b/core/java/android/os/storage/MountServiceListener.java
@@ -0,0 +1,44 @@
+/*
+ * 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 progress reports during a restore operation.  These
+ * methods will all be called on your application's main thread.
+ * @hide
+ */
+public abstract class MountServiceListener {
+    /**
+     * USB Mass storage connection state has changed.
+     *
+     * @param connected True if UMS 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 onStorageStateChange(String path, String oldState, String newState) {
+    }
+}
diff --git a/core/java/android/os/storage/StorageEventListener.java b/core/java/android/os/storage/StorageEventListener.java
new file mode 100644
index 0000000..d3d39d6d
--- /dev/null
+++ b/core/java/android/os/storage/StorageEventListener.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2008 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;
+
+/**
+ * Used for receiving notifications from the StorageManager
+ */
+public abstract class StorageEventListener {
+    /**
+     * Called when the detection state of a USB Mass Storage host has changed.
+     * @param connected true if the USB mass storage is connected.
+     */
+    public void onUsbMassStorageConnectionChanged(boolean connected) {
+    }
+
+    /**
+     * Called when storage has changed state
+     * @param path the filesystem path for the storage
+     * @param oldState the old state as returned by {@link android.os.Environment#getExternalStorageState()}.
+     * @param newState the old state as returned by {@link android.os.Environment#getExternalStorageState()}.
+     */
+    public void onStorageStateChanged(String path, String oldState, String newState) {
+    }
+}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
new file mode 100644
index 0000000..e421ea5
--- /dev/null
+++ b/core/java/android/os/storage/StorageManager.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2008 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.content.Context;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.Parcelable;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.Handler;
+import android.os.Message;
+import android.os.ServiceManager;
+import android.os.storage.IMountService;
+import android.os.storage.IMountServiceListener;
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * StorageManager is the interface to the systems storage service.
+ * Get an instance of this class by calling
+ * {@link android.content.Context#getSystemService(java.lang.String)} with an argument
+ * of {@link android.content.Context#STORAGE_SERVICE}.
+ *
+ */
+
+public class StorageManager
+{
+    private static final String TAG = "StorageManager";
+
+    /*
+     * Our internal MountService binder reference
+     */
+    private IMountService mMountService;
+
+    /*
+     * The looper target for callbacks
+     */
+    Looper mTgtLooper;
+
+    /*
+     * Target listener for binder callbacks
+     */
+    private MountServiceBinderListener mBinderListener;
+
+    /*
+     * List of our listeners
+     */
+    private ArrayList<ListenerDelegate> mListeners = new ArrayList<ListenerDelegate>();
+
+    private class MountServiceBinderListener extends IMountServiceListener.Stub {
+        public void onUsbMassStorageConnectionChanged(boolean available) {
+            final int size = mListeners.size();
+            for (int i = 0; i < size; i++) {
+                mListeners.get(i).sendShareAvailabilityChanged(available);
+            }
+        }
+
+        public void onStorageStateChanged(String path, String oldState, String newState) {
+            final int size = mListeners.size();
+            for (int i = 0; i < size; i++) {
+                mListeners.get(i).sendStorageStateChanged(path, oldState, newState);
+            }
+        }
+    }
+
+    /**
+     * Private base class for messages sent between the callback thread
+     * and the target looper handler.
+     */
+    private class StorageEvent {
+        public static final int EVENT_UMS_CONNECTION_CHANGED = 1;
+        public static final int EVENT_STORAGE_STATE_CHANGED   = 2;
+
+        private Message mMessage;
+
+        public StorageEvent(int what) {
+            mMessage = Message.obtain();
+            mMessage.what = what;
+            mMessage.obj = this;
+        }
+
+        public Message getMessage() {
+            return mMessage;
+        }
+    }
+
+    /**
+     * Message sent on a USB mass storage connection change.
+     */
+    private class UmsConnectionChangedStorageEvent extends StorageEvent {
+        public boolean available;
+
+        public UmsConnectionChangedStorageEvent(boolean a) {
+            super(EVENT_UMS_CONNECTION_CHANGED);
+            available = a;
+        }
+    }
+
+    /**
+     * Message sent on volume state change.
+     */
+    private class StorageStateChangedStorageEvent extends StorageEvent {
+        public String path;
+        public String oldState;
+        public String newState;
+
+        public StorageStateChangedStorageEvent(String p, String oldS, String newS) {
+            super(EVENT_STORAGE_STATE_CHANGED);
+            path = p;
+            oldState = oldS;
+            newState = newS;
+        }
+    }
+
+    /**
+     * Private class containing sender and receiver code for StorageEvents.
+     */
+    private class ListenerDelegate {
+        final StorageEventListener mStorageEventListener;
+        private final Handler mHandler;
+
+        ListenerDelegate(StorageEventListener listener) {
+            mStorageEventListener = listener;
+            mHandler = new Handler(mTgtLooper) {
+                @Override
+                public void handleMessage(Message msg) {
+                    StorageEvent e = (StorageEvent) msg.obj;
+
+                    if (msg.what == StorageEvent.EVENT_UMS_CONNECTION_CHANGED) {
+                        UmsConnectionChangedStorageEvent ev = (UmsConnectionChangedStorageEvent) e;
+                        mStorageEventListener.onUsbMassStorageConnectionChanged(ev.available);
+                    } else if (msg.what == StorageEvent.EVENT_STORAGE_STATE_CHANGED) {
+                        StorageStateChangedStorageEvent ev = (StorageStateChangedStorageEvent) e;
+                        mStorageEventListener.onStorageStateChanged(ev.path, ev.oldState, ev.newState);
+                    } else {
+                        Log.e(TAG, "Unsupported event " + msg.what);
+                    }
+                }
+            };
+        }
+
+        StorageEventListener getListener() {
+            return mStorageEventListener;
+        }
+
+        void sendShareAvailabilityChanged(boolean available) {
+            UmsConnectionChangedStorageEvent e = new UmsConnectionChangedStorageEvent(available);
+            mHandler.sendMessage(e.getMessage());
+        }
+
+        void sendStorageStateChanged(String path, String oldState, String newState) {
+            StorageStateChangedStorageEvent e = new StorageStateChangedStorageEvent(path, oldState, newState);
+            mHandler.sendMessage(e.getMessage());
+        }
+    }
+
+    /**
+     * Constructs a StorageManager object through which an application can
+     * can communicate with the systems mount service.
+     * 
+     * @param tgtLooper The {@android.os.Looper} which events will be received on.
+     *
+     * <p>Applications can get instance of this class by calling
+     * {@link android.content.Context#getSystemService(java.lang.String)} with an argument
+     * of {@link android.content.Context#STORAGE_SERVICE}.
+     *
+     * @hide
+     */
+    public StorageManager(Looper tgtLooper) throws RemoteException {
+        mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
+        if (mMountService == null) {
+            Log.e(TAG, "Unable to connect to mount service! - is it running yet?");
+            return;
+        }
+        mTgtLooper = tgtLooper;
+        mBinderListener = new MountServiceBinderListener();
+        mMountService.registerListener(mBinderListener);
+    }
+
+
+    /**
+     * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}.
+     *
+     * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
+     *
+     */
+    public void registerListener(StorageEventListener listener) {
+        if (listener == null) {
+            return;
+        }
+
+        synchronized (mListeners) {
+            mListeners.add(new ListenerDelegate(listener));
+        }
+    }
+
+    /**
+     * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}.
+     *
+     * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
+     *
+     */
+    public void unregisterListener(StorageEventListener listener) {
+        if (listener == null) {
+            return;
+        }
+
+        synchronized (mListeners) {
+            final int size = mListeners.size();
+            for (int i=0 ; i<size ; i++) {
+                ListenerDelegate l = mListeners.get(i);
+                if (l.getListener() == listener) {
+                    mListeners.remove(i);
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Enables USB Mass Storage (UMS) on the device.
+     * @return an integer value representing the outcome of the operation.
+     * @see android.os.storage.StorageResultCode
+     */
+    public int enableUsbMassStorage() {
+        try {
+            return mMountService.setUsbMassStorageEnabled(true);
+        } catch (Exception ex) {
+            Log.e(TAG, "Failed to enable UMS", ex);
+        }
+        return StorageResultCode.OperationFailedInternalError;
+    }
+
+    /**
+     * Disables USB Mass Storage (UMS) on the device.
+     * @return an integer value representing the outcome of the operation.
+     * @see android.os.storage.StorageResultCode
+     */
+    public int disableUsbMassStorage() {
+        try {
+            return mMountService.setUsbMassStorageEnabled(false);
+        } catch (Exception ex) {
+            Log.e(TAG, "Failed to disable UMS", ex);
+        }
+        return StorageResultCode.OperationFailedInternalError;
+    }
+
+    /**
+     * Query if a USB Mass Storage (UMS) host is connected.
+     * @return true if UMS host is connected.
+     */
+    public boolean isUsbMassStorageConnected() {
+        try {
+            return mMountService.isUsbMassStorageConnected();
+        } catch (Exception ex) {
+            Log.e(TAG, "Failed to get UMS connection state", ex);
+        }
+        return false;
+    }
+
+    /**
+     * Query if a USB Mass Storage (UMS) is enabled on the device.
+     * @return true if UMS host is enabled.
+     */
+    public boolean isUsbMassStorageEnabled() {
+        try {
+            return mMountService.isUsbMassStorageEnabled();
+        } catch (RemoteException rex) {
+            Log.e(TAG, "Failed to get UMS enable state", rex);
+        }
+        return false;
+    }
+}
diff --git a/core/java/android/os/storage/StorageResultCode.java b/core/java/android/os/storage/StorageResultCode.java
new file mode 100644
index 0000000..584f160
--- /dev/null
+++ b/core/java/android/os/storage/StorageResultCode.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 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;
+
+/**
+ * Class that provides access to constants returned from StorageManager
+ * and lower level MountService APIs.
+ */
+public class StorageResultCode
+{
+    /**
+     * Operation succeeded.
+     * @see android.os.storage.StorageManager
+     */
+    public static final int OperationSucceeded               =  0;
+
+    /**
+     * Operation failed: Internal error.
+     * @see android.os.storage.StorageManager
+     */
+    public static final int OperationFailedInternalError     = -1;
+
+    /**
+     * Operation failed: Missing media.
+     * @see android.os.storage.StorageManager
+     */
+    public static final int OperationFailedNoMedia           = -2;
+
+    /**
+     * Operation failed: Media is blank.
+     * @see android.os.storage.StorageManager
+     */
+    public static final int OperationFailedMediaBlank        = -3;
+
+    /**
+     * Operation failed: Media is corrupt.
+     * @see android.os.storage.StorageManager
+     */
+    public static final int OperationFailedMediaCorrupt      = -4;
+
+    /**
+     * Operation failed: Media not mounted.
+     * @see android.os.storage.StorageManager
+     */
+    public static final int OperationFailedVolumeNotMounted  = -5;
+}
diff --git a/core/java/android/storage/StorageEventListener.java b/core/java/android/storage/StorageEventListener.java
deleted file mode 100644
index cd71090..0000000
--- a/core/java/android/storage/StorageEventListener.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2008 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.storage;
-
-/**
- * Used for receiving notifications from the StorageManager
- */
-public interface StorageEventListener {
-    /**
-     * Called when the ability to share a volume has changed.
-     * @param method the share-method which has changed.
-     * @param available true if the share is available.
-     */
-    public void onShareAvailabilityChanged(String method, boolean available);
-
-    /**
-     * Called when media has been inserted
-     * @param label the system defined label for the volume.
-     * @param path the filesystem path for the volume.
-     * @param major the major number of the device.
-     * @param minor the minor number of the device.
-     */
-    public void onMediaInserted(String label, String path, int major, int minor);
-
-    /**
-     * Called when media has been removed
-     * @param label the system defined label for the volume.
-     * @param path the filesystem path for the volume.
-     * @param major the major number of the device.
-     * @param minor the minor number of the device.
-     * @param clean the media was removed cleanly.
-     */
-    public void onMediaRemoved(String label, String path, int major, int minor, boolean clean);
-
-    /**
-     * Called when a volume has changed state
-     * @param label the system defined label for the volume.
-     * @param path the filesystem path for the volume.
-     * @param oldState the old state as returned by {@link android.os.Environment#getExternalStorageState()}.
-     * @param newState the old state as returned by {@link android.os.Environment#getExternalStorageState()}.
-     */
-    public void onVolumeStateChanged(String label, String path, String oldState, String newState);
-}
diff --git a/core/java/android/storage/StorageManager.java b/core/java/android/storage/StorageManager.java
deleted file mode 100644
index 924d169..0000000
--- a/core/java/android/storage/StorageManager.java
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright (C) 2008 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.storage;
-
-import android.content.Context;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Looper;
-import android.os.Parcelable;
-import android.os.ParcelFileDescriptor;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.Handler;
-import android.os.Message;
-import android.os.ServiceManager;
-import android.os.IMountService;
-import android.os.IMountServiceListener;
-import android.util.Log;
-import android.util.SparseArray;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * Class that lets you access the device's storage management functions. Get an instance of this
- * class by calling {@link android.content.Context#getSystemService(java.lang.String)
- * Context.getSystemService()} with an argument of {@link android.content.Context#STORAGE_SERVICE}.
- */
-public class StorageManager
-{
-    private static final String TAG = "StorageManager";
-
-    /*
-     * Our internal MountService binder reference
-     */
-    private IMountService mMountService;
-
-    /*
-     * The looper target for callbacks
-     */
-    Looper mTgtLooper;
-
-    /*
-     * Target listener for binder callbacks
-     */
-    private MountServiceBinderListener mBinderListener;
-
-    /*
-     * *static* list of our listeners
-     */
-    static final ArrayList<ListenerDelegate> sListeners = new ArrayList<ListenerDelegate>();
-
-    private class MountServiceBinderListener extends IMountServiceListener.Stub {
-        public void onShareAvailabilityChanged(String method, boolean available) {
-            final int size = sListeners.size();
-            for (int i = 0; i < size; i++) {
-                sListeners.get(i).sendShareAvailabilityChanged(method, available);
-            }
-        }
-
-        public void onMediaInserted(String label, String path, int major, int minor) {
-            final int size = sListeners.size();
-            for (int i = 0; i < size; i++) {
-                sListeners.get(i).sendMediaInserted(label, path, major, minor);
-            }
-        }
-
-        public void onMediaRemoved(String label, String path, int major, int minor, boolean clean) {
-            final int size = sListeners.size();
-            for (int i = 0; i < size; i++) {
-                sListeners.get(i).sendMediaRemoved(label, path, major, minor, clean);
-            }
-        }
-
-        public void onVolumeStateChanged(String label, String path, String oldState, String newState) {
-            final int size = sListeners.size();
-            for (int i = 0; i < size; i++) {
-                sListeners.get(i).sendVolumeStateChanged(label, path, oldState, newState);
-            }
-        }
-    }
-
-    /**
-     * Private base class for messages sent between the callback thread
-     * and the target looper handler
-     */
-    private class StorageEvent {
-        public static final int EVENT_SHARE_AVAILABILITY_CHANGED = 1;
-        public static final int EVENT_MEDIA_INSERTED             = 2;
-        public static final int EVENT_MEDIA_REMOVED              = 3;
-        public static final int EVENT_VOLUME_STATE_CHANGED       = 4;
-
-        private Message mMessage;
-
-        public StorageEvent(int what) {
-            mMessage = Message.obtain();
-            mMessage.what = what;
-            mMessage.obj = this;
-        }
-
-        public Message getMessage() {
-            return mMessage;
-        }
-    }
-
-    /**
-     * Message sent on a share availability change.
-     */
-    private class ShareAvailabilityChangedStorageEvent extends StorageEvent {
-        public String method;
-        public boolean available;
-
-        public ShareAvailabilityChangedStorageEvent(String m, boolean a) {
-            super(EVENT_SHARE_AVAILABILITY_CHANGED);
-            method = m;
-            available = a;
-        }
-    }
-
-    /**
-     * Message sent on media insertion
-     */
-    private class MediaInsertedStorageEvent extends StorageEvent {
-        public String label;
-        public String path;
-        public int major;
-        public int minor;
-
-        public MediaInsertedStorageEvent(String l, String p, int maj, int min) {
-            super(EVENT_MEDIA_INSERTED);
-            label = l;
-            path = p;
-            major = maj;
-            minor = min;
-        }
-    }
-
-    /**
-     * Message sent on media removal
-     */
-    private class MediaRemovedStorageEvent extends StorageEvent {
-        public String label;
-        public String path;
-        public int major;
-        public int minor;
-        public boolean clean;
-
-        public MediaRemovedStorageEvent(String l, String p, int maj, int min, boolean c) {
-            super(EVENT_MEDIA_REMOVED);
-            label = l;
-            path = p;
-            major = maj;
-            minor = min;
-            clean = c;
-        }
-    }
-
-    /**
-     * Message sent on volume state change
-     */
-    private class VolumeStateChangedStorageEvent extends StorageEvent {
-        public String label;
-        public String path;
-        public String oldState;
-        public String newState;
-
-        public VolumeStateChangedStorageEvent(String l, String p, String oldS, String newS) {
-            super(EVENT_VOLUME_STATE_CHANGED);
-            label = l;
-            path = p;
-            oldState = oldS;
-            newState = newS;
-        }
-    }
-
-    /**
-     * Private class containing sender and receiver code for StorageEvents
-     */
-    private class ListenerDelegate {
-        final StorageEventListener mStorageEventListener;
-        private final Handler mHandler;
-
-        ListenerDelegate(StorageEventListener listener) {
-            mStorageEventListener = listener;
-            mHandler = new Handler(mTgtLooper) {
-                @Override
-                public void handleMessage(Message msg) {
-                    StorageEvent e = (StorageEvent) msg.obj;
-
-                    if (msg.what == StorageEvent.EVENT_SHARE_AVAILABILITY_CHANGED) {
-                        ShareAvailabilityChangedStorageEvent ev = (ShareAvailabilityChangedStorageEvent) e;
-                        mStorageEventListener.onShareAvailabilityChanged(ev.method, ev.available);
-                    } else if (msg.what == StorageEvent.EVENT_MEDIA_INSERTED) {
-                        MediaInsertedStorageEvent ev = (MediaInsertedStorageEvent) e;
-                        mStorageEventListener.onMediaInserted(ev.label, ev.path, ev.major, ev.minor);
-                    } else if (msg.what == StorageEvent.EVENT_MEDIA_REMOVED) {
-                        MediaRemovedStorageEvent ev = (MediaRemovedStorageEvent) e;
-                        mStorageEventListener.onMediaRemoved(ev.label, ev.path, ev.major, ev.minor, ev.clean);
-                    } else if (msg.what == StorageEvent.EVENT_VOLUME_STATE_CHANGED) {
-                        VolumeStateChangedStorageEvent ev = (VolumeStateChangedStorageEvent) e;
-                        mStorageEventListener.onVolumeStateChanged(ev.label, ev.path, ev.oldState, ev.newState);
-                    } else {
-                        Log.e(TAG, "Unsupported event " + msg.what);
-                    }
-                }
-            };
-        }
-
-        StorageEventListener getListener() {
-            return mStorageEventListener;
-        }
-
-        void sendShareAvailabilityChanged(String method, boolean available) {
-            ShareAvailabilityChangedStorageEvent e = new ShareAvailabilityChangedStorageEvent(method, available);
-            mHandler.sendMessage(e.getMessage());
-        }
-
-        void sendMediaInserted(String label, String path, int major, int minor) {
-            MediaInsertedStorageEvent e = new MediaInsertedStorageEvent(label, path, major, minor);
-            mHandler.sendMessage(e.getMessage());
-        }
-
-        void sendMediaRemoved(String label, String path, int major, int minor, boolean clean) {
-            MediaRemovedStorageEvent e = new MediaRemovedStorageEvent(label, path, major, minor, clean);
-            mHandler.sendMessage(e.getMessage());
-        }
-
-        void sendVolumeStateChanged(String label, String path, String oldState, String newState) {
-            VolumeStateChangedStorageEvent e = new VolumeStateChangedStorageEvent(label, path, oldState, newState);
-            mHandler.sendMessage(e.getMessage());
-        }
-    }
-
-    /**
-     * {@hide}
-     */
-    public StorageManager(Looper tgtLooper) throws RemoteException {
-        mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
-        if (mMountService == null) {
-            Log.e(TAG, "Unable to connect to mount service! - is it running yet?");
-            return;
-        }
-        mTgtLooper = tgtLooper;
-        mBinderListener = new MountServiceBinderListener();
-        mMountService.registerListener(mBinderListener);
-    }
-
-
-    /**
-     * Registers a {@link android.storage.StorageEventListener StorageEventListener}.
-     *
-     * @param listener A {@link android.storage.StorageEventListener StorageEventListener} object.
-     *
-     */
-    public void registerListener(StorageEventListener listener) {
-        if (listener == null) {
-            return;
-        }
-
-        synchronized (sListeners) {
-            sListeners.add(new ListenerDelegate(listener));
-        }
-    }
-
-    /**
-     * Unregisters a {@link android.storage.StorageEventListener StorageEventListener}.
-     *
-     * @param listener A {@link android.storage.StorageEventListener StorageEventListener} object.
-     *
-     */
-    public void unregisterListener(StorageEventListener listener) {
-        if (listener == null) {
-            return;
-        }
-        synchronized (sListeners) {
-            final int size = sListeners.size();
-            for (int i=0 ; i<size ; i++) {
-                ListenerDelegate l = sListeners.get(i);
-                if (l.getListener() == listener) {
-                    sListeners.remove(i);
-                    break;
-                }
-            }
-        }
-    }
-}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 52c0e01..2a7dc9c 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -6172,6 +6172,9 @@
                     // mContentHeight may not be updated yet
                     y = Math.max(0,
                             (Math.min(maxHeight, y + viewHeight) - viewHeight));
+                    // We need to take into account the visible title height
+                    // when scrolling since y is an absolute view position.
+                    y = Math.max(0, y - getVisibleTitleHeight());
                     scrollTo(x, y);
                     }
                     break;
diff --git a/core/java/com/android/internal/app/ExternalMediaFormatActivity.java b/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
index 2b07ae6..7e9bbd1 100644
--- a/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
+++ b/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
@@ -24,7 +24,7 @@
 import android.content.IntentFilter;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.IMountService;
+import android.os.storage.IMountService;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
diff --git a/core/java/com/android/internal/app/NetInitiatedActivity.java b/core/java/com/android/internal/app/NetInitiatedActivity.java
index 98fb236..24818a8 100755
--- a/core/java/com/android/internal/app/NetInitiatedActivity.java
+++ b/core/java/com/android/internal/app/NetInitiatedActivity.java
@@ -24,7 +24,6 @@
 import android.content.IntentFilter;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.IMountService;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java
index c110f95..2f48499 100644
--- a/core/java/com/android/internal/app/ShutdownThread.java
+++ b/core/java/com/android/internal/app/ShutdownThread.java
@@ -32,7 +32,7 @@
 import android.os.Power;
 import android.os.ServiceManager;
 import android.os.SystemClock;
-import android.os.IMountService;
+import android.os.storage.IMountService;
 
 import com.android.internal.telephony.ITelephony;
 import android.util.Log;
diff --git a/core/java/com/android/internal/app/StorageNotification.java b/core/java/com/android/internal/app/StorageNotification.java
new file mode 100644
index 0000000..8876612
--- /dev/null
+++ b/core/java/com/android/internal/app/StorageNotification.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.app.Activity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.storage.IMountService;
+import android.os.Message;
+import android.os.ServiceManager;
+import android.os.storage.StorageEventListener;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageResultCode;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class StorageNotification extends StorageEventListener {
+    private static final String TAG = "StorageNotification";
+
+    /**
+     * Binder context for this service
+     */
+    private Context mContext;
+    
+    /**
+     * The notification that is shown when a USB mass storage host
+     * is connected. 
+     * <p>
+     * This is lazily created, so use {@link #setUsbStorageNotification()}.
+     */
+    private Notification mUsbStorageNotification;
+
+    /**
+     * The notification that is shown when the following media events occur:
+     *     - Media is being checked
+     *     - Media is blank (or unknown filesystem)
+     *     - Media is corrupt
+     *     - Media is safe to unmount
+     *     - Media is missing
+     * <p>
+     * This is lazily created, so use {@link #setMediaStorageNotification()}.
+     */
+    private Notification   mMediaStorageNotification;
+    private boolean        mUmsAvailable;
+    private StorageManager mStorageManager;
+
+    public StorageNotification(Context context) {
+        mContext = context;
+
+        mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
+        mUmsAvailable = mStorageManager.isUsbMassStorageConnected();
+        Log.d(TAG, String.format( "Startup with UMS connection %s (media state %s)", mUmsAvailable,
+                Environment.getExternalStorageState()));
+    }
+
+    /*
+     * @override com.android.os.storage.StorageEventListener
+     */
+    @Override
+    public void onUsbMassStorageConnectionChanged(boolean connected) {
+        mUmsAvailable = connected;
+        /*
+         * Even though we may have a UMS host connected, we the SD card
+         * may not be in a state for export.
+         */
+        String st = Environment.getExternalStorageState();
+
+        Log.i(TAG, String.format("UMS connection changed to %s (media state %s)", connected, st));
+
+        if (connected && (st.equals(
+                Environment.MEDIA_REMOVED) || st.equals(Environment.MEDIA_CHECKING))) {
+            /*
+             * No card or card being checked = don't display
+             */
+            connected = false;
+        }
+        updateUsbMassStorageNotification(connected);
+    }
+
+    /*
+     * @override com.android.os.storage.StorageEventListener
+     */
+    @Override
+    public void onStorageStateChanged(String path, String oldState, String newState) {
+        Log.i(TAG, String.format(
+                "Media {%s} state changed from {%s} -> {%s}", path, oldState, newState));
+        if (newState.equals(Environment.MEDIA_SHARED)) {
+            /*
+             * Storage is now shared. Modify the UMS notification
+             * for stopping UMS.
+             */
+            Intent intent = new Intent();
+            intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class);
+            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
+            setUsbStorageNotification(
+                    com.android.internal.R.string.usb_storage_stop_notification_title,
+                    com.android.internal.R.string.usb_storage_stop_notification_message,
+                    com.android.internal.R.drawable.stat_sys_warning, false, true, pi);
+        } else if (newState.equals(Environment.MEDIA_CHECKING)) {
+            /*
+             * Storage is now checking. Update media notification and disable
+             * UMS notification.
+             */
+            setMediaStorageNotification(
+                    com.android.internal.R.string.ext_media_checking_notification_title,
+                    com.android.internal.R.string.ext_media_checking_notification_message,
+                    com.android.internal.R.drawable.stat_notify_sdcard_prepare, true, false, null);
+            updateUsbMassStorageNotification(false);
+        } else if (newState.equals(Environment.MEDIA_MOUNTED)) {
+            /*
+             * Storage is now mounted. Dismiss any media notifications,
+             * and enable UMS notification if connected.
+             */
+            setMediaStorageNotification(0, 0, 0, false, false, null);
+            updateUsbMassStorageNotification(mUmsAvailable);
+        } else if (newState.equals(Environment.MEDIA_UNMOUNTED)) {
+            /*
+             * Storage is now unmounted. We may have been unmounted
+             * because the user is enabling/disabling UMS, in which case we don't
+             * want to display the 'safe to unmount' notification.
+             */
+            if (!mStorageManager.isUsbMassStorageEnabled()) {
+                if (oldState.equals(Environment.MEDIA_SHARED)) {
+                    /*
+                     * The unmount was due to UMS being enabled. Dismiss any
+                     * media notifications, and enable UMS notification if connected
+                     */
+                    setMediaStorageNotification(0, 0, 0, false, false, null);
+                    updateUsbMassStorageNotification(mUmsAvailable);
+                } else {
+                    /*
+                     * Show safe to unmount media notification, and enable UMS
+                     * notification if connected.
+                     */
+                    setMediaStorageNotification(
+                            com.android.internal.R.string.ext_media_safe_unmount_notification_title,
+                            com.android.internal.R.string.ext_media_safe_unmount_notification_message,
+                            com.android.internal.R.drawable.stat_notify_sdcard, true, true, null);
+                    updateUsbMassStorageNotification(mUmsAvailable);
+                }
+            } else {
+                /*
+                 * The unmount was due to UMS being enabled. Dismiss any
+                 * media notifications, and disable the UMS notification
+                 */
+                setMediaStorageNotification(0, 0, 0, false, false, null);
+                updateUsbMassStorageNotification(false);
+            }
+        } else if (newState.equals(Environment.MEDIA_NOFS)) {
+            /*
+             * Storage has no filesystem. Show blank media notification,
+             * and enable UMS notification if connected.
+             */
+            Intent intent = new Intent();
+            intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
+            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
+
+            setMediaStorageNotification(
+                    com.android.internal.R.string.ext_media_nofs_notification_title,
+                    com.android.internal.R.string.ext_media_nofs_notification_message,
+                    com.android.internal.R.drawable.stat_notify_sdcard_usb, true, false, pi);
+            updateUsbMassStorageNotification(mUmsAvailable);
+        } else if (newState.equals(Environment.MEDIA_UNMOUNTABLE)) {
+            /*
+             * Storage is corrupt. Show corrupt media notification,
+             * and enable UMS notification if connected.
+             */
+            Intent intent = new Intent();
+            intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
+            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
+
+            setMediaStorageNotification(
+                    com.android.internal.R.string.ext_media_unmountable_notification_title,
+                    com.android.internal.R.string.ext_media_unmountable_notification_message,
+                    com.android.internal.R.drawable.stat_notify_sdcard_usb, true, false, pi); 
+            updateUsbMassStorageNotification(mUmsAvailable);
+        } else if (newState.equals(Environment.MEDIA_REMOVED)) {
+            /*
+             * Storage has been removed. Show nomedia media notification,
+             * and disable UMS notification regardless of connection state.
+             */
+            setMediaStorageNotification(
+                    com.android.internal.R.string.ext_media_nomedia_notification_title,
+                    com.android.internal.R.string.ext_media_nomedia_notification_message,
+                    com.android.internal.R.drawable.stat_notify_sdcard_usb,
+                    true, false, null);
+            updateUsbMassStorageNotification(false);
+        } else if (newState.equals(Environment.MEDIA_BAD_REMOVAL)) {
+            /*
+             * Storage has been removed unsafely. Show bad removal media notification,
+             * and disable UMS notification regardless of connection state.
+             */
+            setMediaStorageNotification(
+                    com.android.internal.R.string.ext_media_badremoval_notification_title,
+                    com.android.internal.R.string.ext_media_badremoval_notification_message,
+                    com.android.internal.R.drawable.stat_sys_warning,
+                    true, true, null);
+            updateUsbMassStorageNotification(false);
+        } else {
+            Log.w(TAG, String.format("Ignoring unknown state {%s}", newState));
+        }
+    }
+
+    /**
+     * Update the state of the USB mass storage notification
+     */
+    void updateUsbMassStorageNotification(boolean available) {
+
+        if (available) {
+            Intent intent = new Intent();
+            intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
+            setUsbStorageNotification(
+                    com.android.internal.R.string.usb_storage_notification_title,
+                    com.android.internal.R.string.usb_storage_notification_message,
+                    com.android.internal.R.drawable.stat_sys_data_usb,
+                    false, true, pi);
+        } else {
+            setUsbStorageNotification(0, 0, 0, false, false, null);
+        }
+    }
+
+    /**
+     * Sets the USB storage notification.
+     */
+    private synchronized void setUsbStorageNotification(int titleId, int messageId, int icon, boolean sound, boolean visible,
+                                                        PendingIntent pi) {
+
+        if (!visible && mUsbStorageNotification == null) {
+            return;
+        }
+
+        NotificationManager notificationManager = (NotificationManager) mContext
+                .getSystemService(Context.NOTIFICATION_SERVICE);
+
+        if (notificationManager == null) {
+            return;
+        }
+        
+        if (visible) {
+            Resources r = Resources.getSystem();
+            CharSequence title = r.getText(titleId);
+            CharSequence message = r.getText(messageId);
+
+            if (mUsbStorageNotification == null) {
+                mUsbStorageNotification = new Notification();
+                mUsbStorageNotification.icon = icon;
+                mUsbStorageNotification.when = 0;
+            }
+
+            if (sound) {
+                mUsbStorageNotification.defaults |= Notification.DEFAULT_SOUND;
+            } else {
+                mUsbStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
+            }
+                
+            mUsbStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
+
+            mUsbStorageNotification.tickerText = title;
+            if (pi == null) {
+                Intent intent = new Intent();
+                pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+            }
+
+            mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
+        }
+    
+        final int notificationId = mUsbStorageNotification.icon;
+        if (visible) {
+            notificationManager.notify(notificationId, mUsbStorageNotification);
+        } else {
+            notificationManager.cancel(notificationId);
+        }
+    }
+
+    private synchronized boolean getMediaStorageNotificationDismissable() {
+        if ((mMediaStorageNotification != null) &&
+            ((mMediaStorageNotification.flags & Notification.FLAG_AUTO_CANCEL) ==
+                    Notification.FLAG_AUTO_CANCEL))
+            return true;
+
+        return false;
+    }
+
+    /**
+     * Sets the media storage notification.
+     */
+    private synchronized void setMediaStorageNotification(int titleId, int messageId, int icon, boolean visible,
+                                                          boolean dismissable, PendingIntent pi) {
+
+        if (!visible && mMediaStorageNotification == null) {
+            return;
+        }
+
+        NotificationManager notificationManager = (NotificationManager) mContext
+                .getSystemService(Context.NOTIFICATION_SERVICE);
+
+        if (notificationManager == null) {
+            return;
+        }
+
+        if (mMediaStorageNotification != null && visible) {
+            /*
+             * Dismiss the previous notification - we're about to
+             * re-use it.
+             */
+            final int notificationId = mMediaStorageNotification.icon;
+            notificationManager.cancel(notificationId);
+        }
+        
+        if (visible) {
+            Resources r = Resources.getSystem();
+            CharSequence title = r.getText(titleId);
+            CharSequence message = r.getText(messageId);
+
+            if (mMediaStorageNotification == null) {
+                mMediaStorageNotification = new Notification();
+                mMediaStorageNotification.when = 0;
+            }
+
+            mMediaStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
+
+            if (dismissable) {
+                mMediaStorageNotification.flags = Notification.FLAG_AUTO_CANCEL;
+            } else {
+                mMediaStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
+            }
+
+            mMediaStorageNotification.tickerText = title;
+            if (pi == null) {
+                Intent intent = new Intent();
+                pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+            }
+
+            mMediaStorageNotification.icon = icon;
+            mMediaStorageNotification.setLatestEventInfo(mContext, title, message, pi);
+        }
+    
+        final int notificationId = mMediaStorageNotification.icon;
+        if (visible) {
+            notificationManager.notify(notificationId, mMediaStorageNotification);
+        } else {
+            notificationManager.cancel(notificationId);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/app/TetherActivity.java b/core/java/com/android/internal/app/TetherActivity.java
index 2b93dbc..cb268b3 100644
--- a/core/java/com/android/internal/app/TetherActivity.java
+++ b/core/java/com/android/internal/app/TetherActivity.java
@@ -25,7 +25,6 @@
 import android.net.ConnectivityManager;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.IMountService;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
diff --git a/core/java/com/android/internal/app/UsbStorageActivity.java b/core/java/com/android/internal/app/UsbStorageActivity.java
index 34ae2b4..991f04b 100644
--- a/core/java/com/android/internal/app/UsbStorageActivity.java
+++ b/core/java/com/android/internal/app/UsbStorageActivity.java
@@ -25,8 +25,9 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Environment;
-import android.os.IMountService;
-import android.os.MountServiceResultCode;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageEventListener;
+import android.os.storage.StorageResultCode;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -35,6 +36,7 @@
 import android.widget.TextView;
 import android.widget.Toast;
 import android.view.View;
+import android.util.Log;
 
 /**
  * This activity is shown to the user for him/her to enable USB mass storage
@@ -42,11 +44,13 @@
  * dialog style. It will be launched from a notification.
  */
 public class UsbStorageActivity extends Activity {
+    private static final String TAG = "UsbStorageActivity";
     private Button mMountButton;
     private Button mUnmountButton;
     private TextView mBanner;
     private TextView mMessage;
     private ImageView mIcon;
+    private StorageManager mStorageManager = null;
 
     /** Used to detect when the USB cable is unplugged, so we can call finish() */
     private BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() {
@@ -57,11 +61,30 @@
             }
         }
     };
+
+    private StorageEventListener mStorageListener = new StorageEventListener() {
+        @Override
+        public void onStorageStateChanged(String path, String oldState, String newState) {
+            if (newState.equals(Environment.MEDIA_SHARED)) {
+                switchDisplay(true);
+            } else {
+                switchDisplay(false);
+            }
+        }
+    };
     
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
+        if (mStorageManager == null) {
+            mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
+            if (mStorageManager == null) {
+                Log.w(TAG, "Failed to get StorageManager");
+            }
+            mStorageManager.registerListener(mStorageListener);
+        }
+
         setTitle(getString(com.android.internal.R.string.usb_storage_activity_title));
 
         setContentView(com.android.internal.R.layout.usb_storage_activity);
@@ -74,9 +97,11 @@
         mMountButton.setOnClickListener(
             new View.OnClickListener() { 
                  public void onClick(View v) {
-                     mountAsUsbStorage();
-                     // TODO: replace with forthcoming MountService callbacks
-                     switchDisplay(true);
+                     int rc = mStorageManager.enableUsbMassStorage();
+                     if (rc != StorageResultCode.OperationSucceeded) {
+                         Log.e(TAG, String.format("UMS enable failed (%d)", rc));
+                         showSharingError();
+                     }
                  }
             });
 
@@ -84,9 +109,11 @@
         mUnmountButton.setOnClickListener(
             new View.OnClickListener() { 
                  public void onClick(View v) {
-                     stopUsbStorage();
-                     // TODO: replace with forthcoming MountService callbacks
-                     switchDisplay(false);
+                     int rc = mStorageManager.disableUsbMassStorage();
+                     if (rc != StorageResultCode.OperationSucceeded) {
+                         Log.e(TAG, String.format("UMS disable failed (%d)", rc));
+                         showStoppingError();
+                     }
                  }
             });
     }
@@ -112,19 +139,11 @@
         super.onResume();
 
         registerReceiver(mBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
-
-        boolean umsOn = false;
         try {
-            IMountService mountService = IMountService.Stub.asInterface(ServiceManager
-                    .getService("mount"));
-            if (mountService != null) {
-                umsOn = mountService.getVolumeShared(
-                        Environment.getExternalStorageDirectory().getPath(), "ums");
-            }
-        } catch (android.os.RemoteException exc) {
-            // pass
+            switchDisplay(mStorageManager.isUsbMassStorageEnabled());
+        } catch (Exception ex) {
+            Log.e(TAG, "Failed to read UMS enable state", ex);
         }
-        switchDisplay(umsOn);
     }
 
     @Override
@@ -134,42 +153,6 @@
         unregisterReceiver(mBatteryReceiver);
     }
 
-    private void mountAsUsbStorage() {
-        IMountService mountService = IMountService.Stub.asInterface(ServiceManager
-                .getService("mount"));
-        if (mountService == null) {
-            showSharingError();
-            return;
-        }
-
-        try {
-            if (mountService.shareVolume(
-                    Environment.getExternalStorageDirectory().getPath(), "ums") !=
-                            MountServiceResultCode.OperationSucceeded) {
-                showSharingError();
-            }
-        } catch (RemoteException e) {
-            showSharingError();
-        }
-    }
-
-    private void stopUsbStorage() {
-        IMountService mountService = IMountService.Stub.asInterface(ServiceManager
-                .getService("mount"));
-        if (mountService == null) {
-            showStoppingError();
-            return;
-        }
-
-        try {
-            mountService.unshareVolume(
-                    Environment.getExternalStorageDirectory().getPath(), "ums");
-        } catch (RemoteException e) {
-            showStoppingError();
-            return;
-        }
-    }
-
     private void handleBatteryChanged(Intent intent) {
         int pluggedType = intent.getIntExtra("plugged", 0);
         if (pluggedType == 0) {
diff --git a/core/res/res/drawable-mdpi/ic_launcher_android.png b/core/res/res/drawable-mdpi/ic_launcher_android.png
index 855484a..6a97d5b 100644
--- a/core/res/res/drawable-mdpi/ic_launcher_android.png
+++ b/core/res/res/drawable-mdpi/ic_launcher_android.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_def_app_icon.png b/core/res/res/drawable-mdpi/sym_def_app_icon.png
index 8be3b54..9777d11 100644
--- a/core/res/res/drawable-mdpi/sym_def_app_icon.png
+++ b/core/res/res/drawable-mdpi/sym_def_app_icon.png
Binary files differ
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 70c6a58..2458d2a 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -129,11 +129,16 @@
             sendCommand(OMX_CommandStateSet, OMX_StateIdle);
             OMX_ERRORTYPE err;
             while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
-                   && state != OMX_StateIdle) {
+                   && state != OMX_StateIdle
+                   && state != OMX_StateInvalid) {
                 usleep(100000);
             }
             CHECK_EQ(err, OMX_ErrorNone);
 
+            if (state == OMX_StateInvalid) {
+                break;
+            }
+
             // fall through
         }
 
@@ -146,7 +151,8 @@
 
             OMX_ERRORTYPE err;
             while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
-                   && state != OMX_StateLoaded) {
+                   && state != OMX_StateLoaded
+                   && state != OMX_StateInvalid) {
                 LOGV("waiting for Loaded state...");
                 usleep(100000);
             }
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index d23b7d0..fecd366 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -6,8 +6,8 @@
 import android.net.Uri;
 import android.os.Debug;
 import android.os.IBinder;
-import android.os.IMountService;
-import android.os.MountServiceResultCode;
+import android.os.storage.IMountService;
+import android.os.storage.StorageResultCode;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
@@ -158,12 +158,12 @@
             int rc = mountService.createSecureContainer(
                     containerId, mbLen, "vfat", sdEncKey, ownerUid);
 
-            if (rc != MountServiceResultCode.OperationSucceeded) {
+            if (rc != StorageResultCode.OperationSucceeded) {
                 Log.e(TAG, String.format("Container creation failed (%d)", rc));
 
                 // XXX: This destroy should not be necessary
                 rc = mountService.destroySecureContainer(containerId);
-                if (rc != MountServiceResultCode.OperationSucceeded) {
+                if (rc != StorageResultCode.OperationSucceeded) {
                     Log.e(TAG, String.format("Container creation-cleanup failed (%d)", rc));
                     return null;
                 }
@@ -171,7 +171,7 @@
                 // XXX: Does this ever actually succeed?
                 rc = mountService.createSecureContainer(
                         containerId, mbLen, "vfat", sdEncKey, ownerUid);
-                if (rc != MountServiceResultCode.OperationSucceeded) {
+                if (rc != StorageResultCode.OperationSucceeded) {
                     Log.e(TAG, String.format("Container creation retry failed (%d)", rc));
                 }
             }
@@ -226,7 +226,7 @@
     private String mountSdDir(String containerId, String key) {
         try {
             int rc = getMountService().mountSecureContainer(containerId, key, Process.myUid());
-            if (rc == MountServiceResultCode.OperationSucceeded) {
+            if (rc == StorageResultCode.OperationSucceeded) {
                 return getMountService().getSecureContainerPath(containerId);
             } else {
                 Log.e(TAG, String.format("Failed to mount id %s with rc %d ", containerId, rc));
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 51abfc3..6de2eff 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -23,13 +23,14 @@
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.net.Uri;
-import android.os.IMountService;
-import android.os.IMountServiceListener;
-import android.os.MountServiceResultCode;
+import android.os.storage.IMountService;
+import android.os.storage.IMountServiceListener;
+import android.os.storage.StorageResultCode;
 import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.Environment;
 import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UEventObserver;
 import android.os.Handler;
@@ -41,11 +42,14 @@
 import java.io.FileReader;
 
 /**
- * MountService implements an to the mount service daemon
- * @hide
+ * MountService implements back-end services for platform storage
+ * management.
+ * @hide - Applications should use android.os.storage.StorageManager
+ * to access the MountService.
  */
 class MountService extends IMountService.Stub
         implements INativeDaemonConnectorCallbacks {
+    private static final boolean LOCAL_LOGD = false;
     
     private static final String TAG = "MountService";
 
@@ -109,45 +113,35 @@
     private PackageManagerService                 mPms;
     private boolean                               mUmsEnabling;
     private ArrayList<MountServiceBinderListener> mListeners;
+    private boolean                               mBooted;
+    private boolean                               mReady;
 
-    /**
-     * Constructs a new MountService instance
-     * 
-     * @param context  Binder context for this service
-     */
-    public MountService(Context context) {
-        mContext = context;
-
-        // XXX: This will go away soon in favor of IMountServiceObserver
-        mPms = (PackageManagerService) ServiceManager.getService("package");
-
-        // Register a BOOT_COMPLETED handler so that we can start
-        // our NativeDaemonConnector. We defer the startup so that we don't
-        // start processing events before we ought-to
-        mContext.registerReceiver(mBroadcastReceiver,
-                new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
-
-        mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector");
-        mListeners = new ArrayList<MountServiceBinderListener>();
+    private void waitForReady() {
+        while (mReady == false) {
+            for (int retries = 5; retries > 0; retries--) {
+                if (mReady) {
+                    return;
+                }
+                SystemClock.sleep(1000);
+            }
+            Log.w(TAG, "Waiting too long for mReady!");
+        }
     }
   
-    BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
 
             if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
-                /*
-                 * Vold does not run in the simulator, so fake out a mounted
-                 * event to trigger MediaScanner
-                 */
-                if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
-                    updatePublicVolumeState("/sdcard", Environment.MEDIA_MOUNTED);
-                    return;
-                }
+                mBooted = true;
 
-                Thread thread = new Thread(
-                        mConnector, NativeDaemonConnector.class.getName());
-                thread.start();
+                String path = Environment.getExternalStorageDirectory().getPath();
+                if (getVolumeState(path).equals(Environment.MEDIA_UNMOUNTED)) {
+                    int rc = doMountVolume(path);
+                    if (rc != StorageResultCode.OperationSucceeded) {
+                        Log.e(TAG, String.format("Boot-time mount failed (%d)", rc));
+                    }
+                }
             }
         }
     };
@@ -161,7 +155,7 @@
         }
 
         public void binderDied() {
-            Log.d(TAG, "An IMountServiceListener has died!");
+            if (LOCAL_LOGD) Log.d(TAG, "An IMountServiceListener has died!");
             synchronized(mListeners) {
                 mListeners.remove(this);
                 mListener.asBinder().unlinkToDeath(this, 0);
@@ -169,7 +163,7 @@
         }
     }
 
-    int doShareUnshareVolume(String path, String method, boolean enable) {
+    private int doShareUnshareVolume(String path, String method, boolean enable) {
         validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
 
         // TODO: Add support for multiple share methods
@@ -182,9 +176,9 @@
          */
         String vs = getVolumeState(path);
         if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
-            mUmsEnabling = enable; // Supress unmounted events
-            unmountVolume(path);
-            mUmsEnabling = false; // Unsupress unmounted events
+            mUmsEnabling = enable; // Override for isUsbMassStorageEnabled()
+            doUnmountVolume(path);
+            mUmsEnabling = false; // Clear override
         }
 
         try {
@@ -192,14 +186,14 @@
                     "volume %sshare %s %s", (enable ? "" : "un"), path, method));
         } catch (NativeDaemonConnectorException e) {
             Log.e(TAG, "Failed to share/unshare", e);
-            return MountServiceResultCode.OperationFailedInternalError;
+            return StorageResultCode.OperationFailedInternalError;
         }
 
         /*
          * If we disabled UMS then mount the volume
          */
         if (!enable) {
-            if (mountVolume(path) != MountServiceResultCode.OperationSucceeded) {
+            if (doMountVolume(path) != StorageResultCode.OperationSucceeded) {
                 Log.e(TAG, String.format(
                         "Failed to remount %s after disabling share method %s", path, method));
                 /*
@@ -210,15 +204,19 @@
             }
         }
 
-        return MountServiceResultCode.OperationSucceeded;
+        return StorageResultCode.OperationSucceeded;
     }
 
-    void updatePublicVolumeState(String path, String state) {
+    private void updatePublicVolumeState(String path, String state) {
         if (!path.equals(Environment.getExternalStorageDirectory().getPath())) {
             Log.w(TAG, "Multiple volumes not currently supported");
             return;
         }
-        Log.i(TAG, "State for {" + path + "} = {" + state + "}");
+
+        if (mLegacyState.equals(state)) {
+            Log.w(TAG, String.format("Duplicate state transition (%s -> %s)", mLegacyState, state));
+            return;
+        }
 
         String oldState = mLegacyState;
         mLegacyState = state;
@@ -227,7 +225,7 @@
             for (int i = mListeners.size() -1; i >= 0; i--) {
                 MountServiceBinderListener bl = mListeners.get(i);
                 try {
-                    bl.mListener.onVolumeStateChanged("", path, oldState, state);
+                    bl.mListener.onStorageStateChanged(path, oldState, state);
                 } catch (RemoteException rex) {
                     Log.e(TAG, "Listener dead");
                     mListeners.remove(i);
@@ -270,11 +268,7 @@
                         if (st == VolumeState.NoMedia) {
                             state = Environment.MEDIA_REMOVED;
                         } else if (st == VolumeState.Idle) {
-                            state = null;
-                            int rc = mountVolume(path);
-                            if (rc != MountServiceResultCode.OperationSucceeded) {
-                                Log.e(TAG, String.format("Connection-mount failed (%d)", rc));
-                            }
+                            state = Environment.MEDIA_UNMOUNTED;
                         } else if (st == VolumeState.Mounted) {
                             state = Environment.MEDIA_MOUNTED;
                             Log.i(TAG, "Media already mounted on daemon connection");
@@ -294,23 +288,26 @@
                 }
 
                 try {
-                    boolean avail = getShareMethodAvailable("ums");
+                    boolean avail = doGetShareMethodAvailable("ums");
                     notifyShareAvailabilityChange("ums", avail);
                 } catch (Exception ex) {
                     Log.w(TAG, "Failed to get share availability");
                 }
+                /*
+                 * Now that we've done our initialization, release 
+                 * the hounds!
+                 */
+                mReady = true;
             }
         }.start();
     }
 
     /**
-     *
      * Callback from NativeDaemonConnector
      */
     public boolean onEvent(int code, String raw, String[] cooked) {
         Intent in = null;
 
-        // Log.d(TAG, "event {" + raw + "}");
         if (code == VoldResponseCode.VolumeStateChange) {
             /*
              * One of the volumes we're managing has changed state.
@@ -347,34 +344,12 @@
                 Log.e(TAG, "Failed to parse major/minor", ex);
             }
 
-            synchronized (mListeners) {
-                for (int i = mListeners.size() -1; i >= 0; i--) {
-                    MountServiceBinderListener bl = mListeners.get(i);
-                    try {
-                        if (code == VoldResponseCode.VolumeDiskInserted) {
-                            bl.mListener.onMediaInserted(label, path, major, minor);
-                        } else if (code == VoldResponseCode.VolumeDiskRemoved) {
-                            bl.mListener.onMediaRemoved(label, path, major, minor, true);
-                        } else if (code == VoldResponseCode.VolumeBadRemoval) {
-                            bl.mListener.onMediaRemoved(label, path, major, minor, false);
-                        } else {
-                            Log.e(TAG, String.format("Unknown code {%d}", code));
-                        }
-                    } catch (RemoteException rex) {
-                        Log.e(TAG, "Listener dead");
-                        mListeners.remove(i);
-                    } catch (Exception ex) {
-                        Log.e(TAG, "Listener failed", ex);
-                    }
-                }
-            }
-
             if (code == VoldResponseCode.VolumeDiskInserted) {
                 new Thread() {
                     public void run() {
                         try {
                             int rc;
-                            if ((rc = mountVolume(path)) != MountServiceResultCode.OperationSucceeded) {
+                            if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
                                 Log.w(TAG, String.format("Insertion mount failed (%d)", rc));
                             }
                         } catch (Exception ex) {
@@ -417,7 +392,7 @@
        return true;
     }
 
-    void notifyVolumeStateChange(String label, String path, int oldState, int newState) {
+    private void notifyVolumeStateChange(String label, String path, int oldState, int newState) {
         String vs = getVolumeState(path);
 
         Intent in = null;
@@ -471,7 +446,144 @@
         }
     }
 
-    void notifyShareAvailabilityChange(String method, final boolean avail) {
+    private boolean doGetShareMethodAvailable(String method) {
+        ArrayList<String> rsp = mConnector.doCommand("share status " + method);
+
+        for (String line : rsp) {
+            String []tok = line.split(" ");
+            int code;
+            try {
+                code = Integer.parseInt(tok[0]);
+            } catch (NumberFormatException nfe) {
+                Log.e(TAG, String.format("Error parsing code %s", tok[0]));
+                return false;
+            }
+            if (code == VoldResponseCode.ShareStatusResult) {
+                if (tok[2].equals("available"))
+                    return true;
+                return false;
+            } else {
+                Log.e(TAG, String.format("Unexpected response code %d", code));
+                return false;
+            }
+        }
+        Log.e(TAG, "Got an empty response");
+        return false;
+    }
+
+    private int doMountVolume(String path) {
+        int rc = StorageResultCode.OperationSucceeded;
+
+        try {
+            mConnector.doCommand(String.format("volume mount %s", path));
+        } catch (NativeDaemonConnectorException e) {
+            /*
+             * Mount failed for some reason
+             */
+            Intent in = null;
+            int code = e.getCode();
+            if (code == VoldResponseCode.OpFailedNoMedia) {
+                /*
+                 * Attempt to mount but no media inserted
+                 */
+                rc = StorageResultCode.OperationFailedNoMedia;
+            } else if (code == VoldResponseCode.OpFailedMediaBlank) {
+                /*
+                 * Media is blank or does not contain a supported filesystem
+                 */
+                updatePublicVolumeState(path, Environment.MEDIA_NOFS);
+                in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path));
+                rc = StorageResultCode.OperationFailedMediaBlank;
+            } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
+                /*
+                 * Volume consistency check failed
+                 */
+                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);
+                in = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, Uri.parse("file://" + path));
+                rc = StorageResultCode.OperationFailedMediaCorrupt;
+            } else {
+                rc = StorageResultCode.OperationFailedInternalError;
+            }
+
+            /*
+             * Send broadcast intent (if required for the failure)
+             */
+            if (in != null) {
+                mContext.sendBroadcast(in);
+            }
+        }
+
+        return rc;
+    }
+
+    private int doUnmountVolume(String path) {
+        if (getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
+            return VoldResponseCode.OpFailedVolNotMounted;
+        }
+
+        // Notify PackageManager of potential media removal and deal with
+        // return code later on. The caller of this api should be aware or have been
+        // notified that the applications installed on the media will be killed.
+        mPms.updateExternalMediaStatus(false);
+        try {
+            mConnector.doCommand(String.format("volume unmount %s", path));
+            return StorageResultCode.OperationSucceeded;
+        } catch (NativeDaemonConnectorException e) {
+            // Don't worry about mismatch in PackageManager since the
+            // call back will handle the status changes any way.
+            int code = e.getCode();
+            if (code == VoldResponseCode.OpFailedVolNotMounted) {
+                return StorageResultCode.OperationFailedVolumeNotMounted;
+            } else {
+                return StorageResultCode.OperationFailedInternalError;
+            }
+        }
+    }
+
+    private int doFormatVolume(String path) {
+        try {
+            String cmd = String.format("volume format %s", path);
+            mConnector.doCommand(cmd);
+            return StorageResultCode.OperationSucceeded;
+        } catch (NativeDaemonConnectorException e) {
+            int code = e.getCode();
+            if (code == VoldResponseCode.OpFailedNoMedia) {
+                return StorageResultCode.OperationFailedNoMedia;
+            } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
+                return StorageResultCode.OperationFailedMediaCorrupt;
+            } else {
+                return StorageResultCode.OperationFailedInternalError;
+            }
+        }
+    }
+
+    private boolean doGetVolumeShared(String path, String method) {
+        String cmd = String.format("volume shared %s %s", path, method);
+        ArrayList<String> rsp = mConnector.doCommand(cmd);
+
+        for (String line : rsp) {
+            String []tok = line.split(" ");
+            int code;
+            try {
+                code = Integer.parseInt(tok[0]);
+            } catch (NumberFormatException nfe) {
+                Log.e(TAG, String.format("Error parsing code %s", tok[0]));
+                return false;
+            }
+            if (code == VoldResponseCode.ShareEnabledResult) {
+                if (tok[2].equals("enabled"))
+                    return true;
+                return false;
+            } else {
+                Log.e(TAG, String.format("Unexpected response code %d", code));
+                return false;
+            }
+        }
+        Log.e(TAG, "Got an empty response");
+        return false;
+    }
+
+    private void notifyShareAvailabilityChange(String method, final boolean avail) {
         if (!method.equals("ums")) {
            Log.w(TAG, "Ignoring unsupported share method {" + method + "}");
            return;
@@ -481,7 +593,7 @@
             for (int i = mListeners.size() -1; i >= 0; i--) {
                 MountServiceBinderListener bl = mListeners.get(i);
                 try {
-                    bl.mListener.onShareAvailabilityChanged(method, avail);
+                    bl.mListener.onUsbMassStorageConnectionChanged(avail);
                 } catch (RemoteException rex) {
                     Log.e(TAG, "Listener dead");
                     mListeners.remove(i);
@@ -491,22 +603,55 @@
             }
         }
 
-        Intent intent;
-        if (avail) {
-            intent = new Intent(Intent.ACTION_UMS_CONNECTED);
-        } else {
-            intent = new Intent(Intent.ACTION_UMS_DISCONNECTED);
+        if (mBooted == true) {
+            Intent intent;
+            if (avail) {
+                intent = new Intent(Intent.ACTION_UMS_CONNECTED);
+            } else {
+                intent = new Intent(Intent.ACTION_UMS_DISCONNECTED);
+            }
+            mContext.sendBroadcast(intent);
         }
-        mContext.sendBroadcast(intent);
     }
 
-    void validatePermission(String perm) {
+    private void validatePermission(String perm) {
         if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException(String.format("Requires %s permission", perm));
         }
     }
 
     /**
+     * Constructs a new MountService instance
+     *
+     * @param context  Binder context for this service
+     */
+    public MountService(Context context) {
+        mContext = context;
+
+        /*
+         * Vold does not run in the simulator, so fake out a mounted
+         * event to trigger MediaScanner
+         */
+        if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
+            updatePublicVolumeState("/sdcard", Environment.MEDIA_MOUNTED);
+            return;
+        }
+
+        // XXX: This will go away soon in favor of IMountServiceObserver
+        mPms = (PackageManagerService) ServiceManager.getService("package");
+
+        mContext.registerReceiver(mBroadcastReceiver,
+                new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
+
+        mListeners = new ArrayList<MountServiceBinderListener>();
+
+        mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector");
+        mReady = false;
+        Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
+        thread.start();
+    }
+
+    /**
      * Exposed API calls below here
      */
 
@@ -549,7 +694,7 @@
              * the UMS host could have dirty FAT cache entries
              * yet to flush.
              */
-            if (unshareVolume(path, "ums") != MountServiceResultCode.OperationSucceeded) {
+            if (setUsbMassStorageEnabled(false) != StorageResultCode.OperationSucceeded) {
                 Log.e(TAG, "UMS disable on shutdown failed");
             }
         } else if (state.equals(Environment.MEDIA_CHECKING)) {
@@ -577,75 +722,30 @@
             /*
              * If the media is mounted, then gracefully unmount it.
              */
-            if (unmountVolume(path) != MountServiceResultCode.OperationSucceeded) {
+            if (doUnmountVolume(path) != StorageResultCode.OperationSucceeded) {
                 Log.e(TAG, "Failed to unmount media for shutdown");
             }
         }
     }
 
-    public String[] getShareMethodList() {
-        String[] rdata = new String[1];
-        rdata[0] = "ums";
-        return rdata;
-    }
+    public boolean isUsbMassStorageConnected() {
+        waitForReady();
 
-    public boolean getShareMethodAvailable(String method) {
-        ArrayList<String> rsp = mConnector.doCommand("share status " + method);
-
-        for (String line : rsp) {
-            String []tok = line.split(" ");
-            int code;
-            try {
-                code = Integer.parseInt(tok[0]);
-            } catch (NumberFormatException nfe) {
-                Log.e(TAG, String.format("Error parsing code %s", tok[0]));
-                return false;
-            }
-            if (code == VoldResponseCode.ShareStatusResult) {
-                if (tok[2].equals("available"))
-                    return true;
-                return false;
-            } else {
-                Log.e(TAG, String.format("Unexpected response code %d", code));
-                return false;
-            }
+        if (mUmsEnabling) {
+            return true;
         }
-        Log.e(TAG, "Got an empty response");
-        return false;
+        return doGetShareMethodAvailable("ums");
     }
 
-    public int shareVolume(String path, String method) {
-        return doShareUnshareVolume(path, method, true);
+    public int setUsbMassStorageEnabled(boolean enable) {
+        waitForReady();
+
+        return doShareUnshareVolume(Environment.getExternalStorageDirectory().getPath(), "ums", enable);
     }
 
-    public int unshareVolume(String path, String method) {
-        return doShareUnshareVolume(path, method, false);
-    }
-
-    public boolean getVolumeShared(String path, String method) {
-        String cmd = String.format("volume shared %s %s", path, method);
-        ArrayList<String> rsp = mConnector.doCommand(cmd);
-
-        for (String line : rsp) {
-            String []tok = line.split(" ");
-            int code;
-            try {
-                code = Integer.parseInt(tok[0]);
-            } catch (NumberFormatException nfe) {
-                Log.e(TAG, String.format("Error parsing code %s", tok[0]));
-                return false;
-            }
-            if (code == VoldResponseCode.ShareEnabledResult) {
-                if (tok[2].equals("enabled"))
-                    return true;
-                return false;
-            } else {
-                Log.e(TAG, String.format("Unexpected response code %d", code));
-                return false;
-            }
-        }
-        Log.e(TAG, "Got an empty response");
-        return false;
+    public boolean isUsbMassStorageEnabled() {
+        waitForReady();
+        return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums");
     }
     
     /**
@@ -664,113 +764,38 @@
         return mLegacyState;
     }
 
-    
-    /**
-     * Attempt to mount external media
-     */
     public int mountVolume(String path) {
         validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
-        int rc = MountServiceResultCode.OperationSucceeded;
 
-        try {
-            mConnector.doCommand(String.format("volume mount %s", path));
-        } catch (NativeDaemonConnectorException e) {
-            /*
-             * Mount failed for some reason
-             */
-            Intent in = null;
-            int code = e.getCode();
-            if (code == VoldResponseCode.OpFailedNoMedia) {
-                /*
-                 * Attempt to mount but no media inserted
-                 */
-                rc = MountServiceResultCode.OperationFailedNoMedia;
-            } else if (code == VoldResponseCode.OpFailedMediaBlank) {
-                /*
-                 * Media is blank or does not contain a supported filesystem
-                 */
-                updatePublicVolumeState(path, Environment.MEDIA_NOFS);
-                in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path));
-                rc = MountServiceResultCode.OperationFailedMediaBlank;
-            } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
-                /*
-                 * Volume consistency check failed
-                 */
-                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);
-                in = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, Uri.parse("file://" + path));
-                rc = MountServiceResultCode.OperationFailedMediaCorrupt;
-            } else {
-                rc = MountServiceResultCode.OperationFailedInternalError;
-            }
-
-            /*
-             * Send broadcast intent (if required for the failure)
-             */
-            if (in != null) {
-                mContext.sendBroadcast(in);
-            }
-        }
-
-        return rc;
+        waitForReady();
+        return doMountVolume(path);
     }
 
-    /**
-     * Attempt to unmount external media to prepare for eject
-     */
     public int unmountVolume(String path) {
         validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+        waitForReady();
 
-        // Check if media has been mounted
-        String oldState = mLegacyState;
-        if (!oldState.equals(Environment.MEDIA_MOUNTED)) {
-            return VoldResponseCode.OpFailedVolNotMounted;
-        }
-        // Notify PackageManager of potential media removal and deal with
-        // return code later on. The caller of this api should be aware or have been
-        // notified that the applications installed on the media will be killed.
-        mPms.updateExternalMediaStatus(false);
-        try {
-            mConnector.doCommand(String.format("volume unmount %s", path));
-            return MountServiceResultCode.OperationSucceeded;
-        } catch (NativeDaemonConnectorException e) {
-            // Don't worry about mismatch in PackageManager since the
-            // call back will handle the status changes any way.
-            int code = e.getCode();
-            if (code == VoldResponseCode.OpFailedVolNotMounted) {
-                return MountServiceResultCode.OperationFailedVolumeNotMounted;
-            } else {
-                return MountServiceResultCode.OperationFailedInternalError;
-            }
-        }
+        return doUnmountVolume(path);
     }
 
-    /**
-     * Synchronously formats a volume
-     *
-     * @param path The volume path to format
-     * @return Error code from MountServiceResultCode
-     */
     public int formatVolume(String path) {
         validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
+        waitForReady();
 
-        try {
-            String cmd = String.format("volume format %s", path);
-            mConnector.doCommand(cmd);
-            return MountServiceResultCode.OperationSucceeded;
-        } catch (NativeDaemonConnectorException e) {
-            int code = e.getCode();
-            if (code == VoldResponseCode.OpFailedNoMedia) {
-                return MountServiceResultCode.OperationFailedNoMedia;
-            } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
-                return MountServiceResultCode.OperationFailedMediaCorrupt;
-            } else {
-                return MountServiceResultCode.OperationFailedInternalError;
-            }
+        return doFormatVolume(path);
+    }
+
+    private void warnOnNotMounted() {
+        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+            Log.w(TAG, "getSecureContainerList() called when storage not mounted");
         }
     }
 
     public String[] getSecureContainerList() {
         validatePermission(android.Manifest.permission.ASEC_ACCESS);
+        waitForReady();
+        warnOnNotMounted();
+
         try {
             return mConnector.doListCommand("asec list", VoldResponseCode.AsecListResult);
         } catch (NativeDaemonConnectorException e) {
@@ -781,82 +806,96 @@
     public int createSecureContainer(String id, int sizeMb, String fstype,
                                     String key, int ownerUid) {
         validatePermission(android.Manifest.permission.ASEC_CREATE);
+        waitForReady();
+        warnOnNotMounted();
 
-        int rc = MountServiceResultCode.OperationSucceeded;
+        int rc = StorageResultCode.OperationSucceeded;
         String cmd = String.format("asec create %s %d %s %s %d", id, sizeMb, fstype, key, ownerUid);
         try {
             mConnector.doCommand(cmd);
         } catch (NativeDaemonConnectorException e) {
-            rc = MountServiceResultCode.OperationFailedInternalError;
+            rc = StorageResultCode.OperationFailedInternalError;
         }
         return rc;
     }
 
     public int finalizeSecureContainer(String id) {
         validatePermission(android.Manifest.permission.ASEC_CREATE);
+        warnOnNotMounted();
 
-        int rc = MountServiceResultCode.OperationSucceeded;
+        int rc = StorageResultCode.OperationSucceeded;
         try {
             mConnector.doCommand(String.format("asec finalize %s", id));
         } catch (NativeDaemonConnectorException e) {
-            rc = MountServiceResultCode.OperationFailedInternalError;
+            rc = StorageResultCode.OperationFailedInternalError;
         }
         return rc;
     }
 
     public int destroySecureContainer(String id) {
         validatePermission(android.Manifest.permission.ASEC_DESTROY);
+        waitForReady();
+        warnOnNotMounted();
 
-        int rc = MountServiceResultCode.OperationSucceeded;
+        int rc = StorageResultCode.OperationSucceeded;
         try {
             mConnector.doCommand(String.format("asec destroy %s", id));
         } catch (NativeDaemonConnectorException e) {
-            rc = MountServiceResultCode.OperationFailedInternalError;
+            rc = StorageResultCode.OperationFailedInternalError;
         }
         return rc;
     }
    
     public int mountSecureContainer(String id, String key, int ownerUid) {
         validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
+        waitForReady();
+        warnOnNotMounted();
 
-        int rc = MountServiceResultCode.OperationSucceeded;
+        int rc = StorageResultCode.OperationSucceeded;
         String cmd = String.format("asec mount %s %s %d", id, key, ownerUid);
         try {
             mConnector.doCommand(cmd);
         } catch (NativeDaemonConnectorException e) {
-            rc = MountServiceResultCode.OperationFailedInternalError;
+            rc = StorageResultCode.OperationFailedInternalError;
         }
         return rc;
     }
 
     public int unmountSecureContainer(String id) {
         validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
+        waitForReady();
+        warnOnNotMounted();
 
-        int rc = MountServiceResultCode.OperationSucceeded;
+        int rc = StorageResultCode.OperationSucceeded;
         String cmd = String.format("asec unmount %s", id);
         try {
             mConnector.doCommand(cmd);
         } catch (NativeDaemonConnectorException e) {
-            rc = MountServiceResultCode.OperationFailedInternalError;
+            rc = StorageResultCode.OperationFailedInternalError;
         }
         return rc;
     }
 
     public int renameSecureContainer(String oldId, String newId) {
         validatePermission(android.Manifest.permission.ASEC_RENAME);
+        waitForReady();
+        warnOnNotMounted();
 
-        int rc = MountServiceResultCode.OperationSucceeded;
+        int rc = StorageResultCode.OperationSucceeded;
         String cmd = String.format("asec rename %s %s", oldId, newId);
         try {
             mConnector.doCommand(cmd);
         } catch (NativeDaemonConnectorException e) {
-            rc = MountServiceResultCode.OperationFailedInternalError;
+            rc = StorageResultCode.OperationFailedInternalError;
         }
         return rc;
     }
 
     public String getSecureContainerPath(String id) {
         validatePermission(android.Manifest.permission.ASEC_ACCESS);
+        waitForReady();
+        warnOnNotMounted();
+
         ArrayList<String> rsp = mConnector.doCommand("asec path " + id);
 
         for (String line : rsp) {
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index d989b6b..ad8ab84 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -50,6 +50,7 @@
 import android.os.Power;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.storage.StorageManager;
 import android.os.SystemProperties;
 import android.os.Vibrator;
 import android.provider.Settings;
@@ -406,6 +407,10 @@
         mSound.setUsesWakeLock(context);
         mToastQueue = new ArrayList<ToastRecord>();
         mHandler = new WorkerHandler();
+
+        StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
+        sm.registerListener(new com.android.internal.app.StorageNotification(context));
+
         mStatusBarService = statusBar;
         statusBar.setNotificationCallbacks(mNotificationCallbacks);
 
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index f27ef8e..c99480f 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -74,7 +74,7 @@
 import android.os.FileObserver;
 import android.os.FileUtils;
 import android.os.Handler;
-import android.os.MountServiceResultCode;
+import android.os.storage.StorageResultCode;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.ServiceManager;
@@ -8295,17 +8295,17 @@
 
         int rc = mountService.createSecureContainer(
                 pkgName, mbLen, "vfat", sdEncKey, Process.SYSTEM_UID);
-        if (rc != MountServiceResultCode.OperationSucceeded) {
+        if (rc != StorageResultCode.OperationSucceeded) {
             Log.e(TAG, String.format("Failed to create container (%d)", rc));
 
             rc = mountService.destroySecureContainer(pkgName);
-            if (rc != MountServiceResultCode.OperationSucceeded) {
+            if (rc != StorageResultCode.OperationSucceeded) {
                 Log.e(TAG, String.format("Failed to cleanup container (%d)", rc));
                 return null;
             }
             rc = mountService.createSecureContainer(
                     pkgName, mbLen, "vfat", sdEncKey, Process.SYSTEM_UID);
-            if (rc != MountServiceResultCode.OperationSucceeded) {
+            if (rc != StorageResultCode.OperationSucceeded) {
                 Log.e(TAG, String.format("Failed to create container (2nd try) (%d)", rc));
                 return null;
             }
@@ -8325,7 +8325,7 @@
 
        int rc = getMountService().mountSecureContainer(pkgName, sdEncKey, ownerUid);
 
-       if (rc != MountServiceResultCode.OperationSucceeded) {
+       if (rc != StorageResultCode.OperationSucceeded) {
            Log.i(TAG, "Failed to mount container for pkg : " + pkgName + " rc : " + rc);
            return null;
        }
@@ -8336,7 +8336,7 @@
    private boolean unMountSdDir(String pkgName) {
        // STOPSHIP unmount directory
        int rc = getMountService().unmountSecureContainer(pkgName);
-       if (rc != MountServiceResultCode.OperationSucceeded) {
+       if (rc != StorageResultCode.OperationSucceeded) {
            Log.e(TAG, "Failed to unmount : " + pkgName + " with rc " + rc);
            return false;
        }
@@ -8360,7 +8360,7 @@
 
     private boolean finalizeSdDir(String pkgName) {
         int rc = getMountService().finalizeSecureContainer(pkgName);
-        if (rc != MountServiceResultCode.OperationSucceeded) {
+        if (rc != StorageResultCode.OperationSucceeded) {
             Log.i(TAG, "Failed to finalize container for pkg : " + pkgName);
             return false;
         }
@@ -8369,7 +8369,7 @@
 
     private boolean destroySdDir(String pkgName) {
         int rc = getMountService().destroySecureContainer(pkgName);
-        if (rc != MountServiceResultCode.OperationSucceeded) {
+        if (rc != StorageResultCode.OperationSucceeded) {
             Log.i(TAG, "Failed to destroy container for pkg : " + pkgName);
             return false;
         }
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 1e7dd99..1ccae86 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -41,7 +41,7 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
-import android.os.IMountService;
+import android.os.storage.IMountService;
 import android.os.IPowerManager;
 import android.os.LocalPowerManager;
 import android.os.Power;
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
index a1370ea..3a4d38c 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -16,7 +16,7 @@
 
 package com.android.unit_tests;
 
-import android.os.IMountService.Stub;
+import android.os.storage.IMountService.Stub;
 
 import android.net.Uri;
 import android.os.FileUtils;
@@ -54,8 +54,8 @@
 import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.IMountService;
-import android.os.MountServiceResultCode;
+import android.os.storage.IMountService;
+import android.os.storage.StorageResultCode;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StatFs;
@@ -662,7 +662,7 @@
         try {
         String mPath = Environment.getExternalStorageDirectory().toString();
         int ret = getMs().mountVolume(mPath);
-        return ret == MountServiceResultCode.OperationSucceeded;
+        return ret == StorageResultCode.OperationSucceeded;
         } catch (RemoteException e) {
             return false;
         }
@@ -675,7 +675,7 @@
         try {
         String mPath = Environment.getExternalStorageDirectory().toString();
         int ret = getMs().unmountVolume(mPath);
-        return ret == MountServiceResultCode.OperationSucceeded;
+        return ret == StorageResultCode.OperationSucceeded;
         } catch (RemoteException e) {
             return true;
         }
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index cbb5203..558b587 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -39,7 +39,7 @@
           mRequireLocalization(false), mPseudolocalize(false),
           mUTF8(false), mEncodingSpecified(false), mValues(false),
           mCompressionMethod(0), mOutputAPKFile(NULL), mManifestPackageNameOverride(NULL),
-          mAssetSourceDir(NULL), mProguardFile(NULL),
+          mAutoAddOverlay(false), mAssetSourceDir(NULL), mProguardFile(NULL),
           mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
           mRClassDir(NULL), mResourceIntermediatesDir(NULL),
           mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL),
@@ -90,6 +90,8 @@
     void setOutputAPKFile(const char* val) { mOutputAPKFile = val; }
     const char* getManifestPackageNameOverride() const { return mManifestPackageNameOverride; }
     void setManifestPackageNameOverride(const char * val) { mManifestPackageNameOverride = val; }
+    bool getAutoAddOverlay() { return mAutoAddOverlay; }
+    void setAutoAddOverlay(bool val) { mAutoAddOverlay = val; }
 
     /*
      * Input options.
@@ -181,6 +183,7 @@
     bool        mJunkPath;
     const char* mOutputAPKFile;
     const char* mManifestPackageNameOverride;
+    bool        mAutoAddOverlay;
     const char* mAssetSourceDir;
     const char* mProguardFile;
     const char* mAndroidManifestFile;
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 6675ac2..6d0a351 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -60,6 +60,7 @@
         "        [--min-sdk-version VAL] [--target-sdk-version VAL] \\\n"
         "        [--max-sdk-version VAL] [--app-version VAL] \\\n"
         "        [--app-version-name TEXT] [--custom-package VAL] [--utf16] \\\n"
+        "        [--auto-add-overlay] \\\n"
         "        [-I base-package [-I base-package ...]] \\\n"
         "        [-A asset-source-dir]  [-G class-list-file] [-P public-definitions-file] \\\n"
         "        [-S resource-sources [-S resource-sources ...]] "
@@ -136,6 +137,8 @@
         "       inserts android:versionName in to manifest.\n"
         "   --custom-package\n"
         "       generates R.java into a different package.\n"
+        "   --auto-add-overlay\n"
+        "       Automatically add resources that are only in overlays.\n"
         "   --utf16\n"
         "       changes default encoding for resources to UTF-16.  Only useful when API\n"
         "       level is set to 7 or higher where the default encoding is UTF-8.\n");
@@ -445,6 +448,8 @@
                         goto bail;
                     }
                     bundle.setManifestPackageNameOverride(argv[0]);
+                } else if (strcmp(cp, "-auto-add-overlay") == 0) {
+                    bundle.setAutoAddOverlay(true);
                 } else {
                     fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp);
                     wantUsage = true;
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index a9cbd11..b682702 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -1591,7 +1591,7 @@
                sourcePos.file.striing(), sourcePos.line, String8(type).string());
     }
 #endif
-    if (overlay && !hasBagOrEntry(package, type, name)) {
+    if (overlay && !mBundle->getAutoAddOverlay() && !hasBagOrEntry(package, type, name)) {
         bool canAdd = false;
         sp<Package> p = mPackages.valueFor(package);
         if (p != NULL) {
@@ -3279,12 +3279,13 @@
                                                        const SourcePos& sourcePos,
                                                        const ResTable_config* config,
                                                        bool doSetIndex,
-                                                       bool overlay)
+                                                       bool overlay,
+                                                       bool autoAddOverlay)
 {
     int pos = -1;
     sp<ConfigList> c = mConfigs.valueFor(entry);
     if (c == NULL) {
-        if (overlay == true && mCanAddEntries.indexOf(entry) < 0) {
+        if (overlay && !autoAddOverlay && mCanAddEntries.indexOf(entry) < 0) {
             sourcePos.error("Resource at %s appears in overlay but not"
                             " in the base package; use <add-resource> to add.\n",
                             String8(entry).string());
@@ -3596,7 +3597,7 @@
     if (t == NULL) {
         return NULL;
     }
-    return t->getEntry(name, sourcePos, config, doSetIndex, overlay);
+    return t->getEntry(name, sourcePos, config, doSetIndex, overlay, mBundle->getAutoAddOverlay());
 }
 
 sp<const ResourceTable::Entry> ResourceTable::getEntry(uint32_t resID,
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index cfa75a71..60d0901 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -425,7 +425,8 @@
                            const SourcePos& pos,
                            const ResTable_config* config = NULL,
                            bool doSetIndex = false,
-                           bool overlay = false);
+                           bool overlay = false,
+                           bool autoAddOverlay = false);
 
         const SourcePos& getFirstPublicSourcePos() const { return *mFirstPublicSourcePos; }