Merge "Fix issue 2285561: New AudioFlinger and audio driver API needed for A/V sync"
diff --git a/Android.mk b/Android.mk
index 568352e..7520afe 100644
--- a/Android.mk
+++ b/Android.mk
@@ -117,6 +117,7 @@
 	core/java/android/os/IParentalControlCallback.aidl \
 	core/java/android/os/IPermissionController.aidl \
 	core/java/android/os/IPowerManager.aidl \
+    core/java/android/os/IRemoteCallback.aidl \
 	core/java/android/os/IVibratorService.aidl \
     core/java/android/service/wallpaper/IWallpaperConnection.aidl \
     core/java/android/service/wallpaper/IWallpaperEngine.aidl \
@@ -136,6 +137,7 @@
 	core/java/android/speech/tts/ITtsCallback.aidl \
 	core/java/com/android/internal/app/IBatteryStats.aidl \
 	core/java/com/android/internal/app/IUsageStats.aidl \
+	core/java/com/android/internal/app/IMediaContainerService.aidl \
 	core/java/com/android/internal/appwidget/IAppWidgetService.aidl \
 	core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
 	core/java/com/android/internal/backup/IBackupTransport.aidl \
diff --git a/api/current.xml b/api/current.xml
index cd200c1..1250461 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -3184,7 +3184,7 @@
  value="16843395"
  static="true"
  final="true"
- deprecated="deprecated"
+ deprecated="not deprecated"
  visibility="public"
 >
 </field>
@@ -3261,7 +3261,7 @@
  value="16843362"
  static="true"
  final="true"
- deprecated="deprecated"
+ deprecated="not deprecated"
  visibility="public"
 >
 </field>
@@ -5131,7 +5131,7 @@
  value="16842997"
  static="true"
  final="true"
- deprecated="deprecated"
+ deprecated="not deprecated"
  visibility="public"
 >
 </field>
@@ -5252,7 +5252,7 @@
  value="16842996"
  static="true"
  final="true"
- deprecated="deprecated"
+ deprecated="not deprecated"
  visibility="public"
 >
 </field>
@@ -16176,11 +16176,26 @@
  synchronized="false"
  static="false"
  final="false"
+ deprecated="deprecated"
+ visibility="protected"
+>
+<parameter name="id" type="int">
+</parameter>
+</method>
+<method name="onCreateDialog"
+ return="android.app.Dialog"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
  deprecated="not deprecated"
  visibility="protected"
 >
 <parameter name="id" type="int">
 </parameter>
+<parameter name="args" type="android.os.Bundle">
+</parameter>
 </method>
 <method name="onCreateOptionsMenu"
  return="boolean"
@@ -16476,6 +16491,21 @@
  synchronized="false"
  static="false"
  final="false"
+ deprecated="deprecated"
+ visibility="protected"
+>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="dialog" type="android.app.Dialog">
+</parameter>
+</method>
+<method name="onPrepareDialog"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
  deprecated="not deprecated"
  visibility="protected"
 >
@@ -16483,6 +16513,8 @@
 </parameter>
 <parameter name="dialog" type="android.app.Dialog">
 </parameter>
+<parameter name="args" type="android.os.Bundle">
+</parameter>
 </method>
 <method name="onPrepareOptionsMenu"
  return="boolean"
@@ -17110,6 +17142,21 @@
 <parameter name="id" type="int">
 </parameter>
 </method>
+<method name="showDialog"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="args" type="android.os.Bundle">
+</parameter>
+</method>
 <method name="startActivityForResult"
  return="void"
  abstract="false"
@@ -19895,6 +19942,21 @@
 <parameter name="context" type="android.content.Context">
 </parameter>
 </method>
+<method name="onDisableRequested"
+ return="java.lang.CharSequence"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
 <method name="onDisabled"
  return="void"
  abstract="false"
@@ -19996,6 +20058,17 @@
  visibility="public"
 >
 </field>
+<field name="ACTION_DEVICE_ADMIN_DISABLE_REQUESTED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ACTION_DEVICE_ADMIN_ENABLED"
  type="java.lang.String"
  transient="false"
@@ -20051,6 +20124,17 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_DISABLE_WARNING"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.extra.DISABLE_WARNING&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="DeviceAdminInfo"
  extends="java.lang.Object"
@@ -20420,6 +20504,21 @@
 <parameter name="password" type="java.lang.String">
 </parameter>
 </method>
+<method name="setMaximumFailedPasswordsForWipe"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+<parameter name="num" type="int">
+</parameter>
+</method>
 <method name="setMaximumTimeToLock"
  return="void"
  abstract="false"
@@ -20500,6 +20599,17 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_ADD_EXPLANATION"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.app.extra.ADD_EXPLANATION&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="EXTRA_DEVICE_ADMIN"
  type="java.lang.String"
  transient="false"
@@ -119960,6 +120070,28 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_HEADERS_KEY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;com.android.browser.headers_key&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_HEADERS_VALUE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;com.android.browser.headers_value&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="HISTORY_PROJECTION"
  type="java.lang.String[]"
  transient="false"
@@ -189850,6 +189982,21 @@
 >
 <parameter name="url" type="java.lang.String">
 </parameter>
+<parameter name="extraHeaders" type="java.util.Map&lt;java.lang.String, java.lang.String&gt;">
+</parameter>
+</method>
+<method name="loadUrl"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="java.lang.String">
+</parameter>
 </method>
 <method name="onChildViewAdded"
  return="void"
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index a8e217e..81d60dc 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -1191,14 +1191,6 @@
 
     CameraParameters p(params);
 
-    // The orientation parameter is actually for CameraService, not for the camera driver.
-    if (p.getOrientation() == CameraParameters::CAMERA_ORIENTATION_PORTRAIT) {
-        LOGV("portrait mode");
-        mOrientation = ISurface::BufferHeap::ROT_90;
-    } else {
-        mOrientation = 0;
-    }
-
     return mHardware->setParameters(p);
 }
 
@@ -1224,6 +1216,30 @@
     status_t result = checkPid();
     if (result != NO_ERROR) return result;
 
+    if (cmd == CAMERA_CMD_SET_DISPLAY_ORIENTATION) {
+        // The orientation cannot be set during preview.
+        if (mHardware->previewEnabled()) {
+            return INVALID_OPERATION;
+        }
+        switch (arg1) {
+            case 0:
+                mOrientation = ISurface::BufferHeap::ROT_0;
+                break;
+            case 90:
+                mOrientation = ISurface::BufferHeap::ROT_90;
+                break;
+            case 180:
+                mOrientation = ISurface::BufferHeap::ROT_180;
+                break;
+            case 270:
+                mOrientation = ISurface::BufferHeap::ROT_270;
+                break;
+            default:
+                return BAD_VALUE;
+        }
+        return OK;
+    }
+
     if (mHardware == 0) {
         LOGE("mHardware is NULL, returning.");
         return INVALID_OPERATION;
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 9300915..78f90a1 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -129,7 +129,7 @@
     dump_file("LAST PANIC CONSOLE", "/data/dontpanic/apanic_console");
     dump_file("LAST PANIC THREADS", "/data/dontpanic/apanic_threads");
 
-    printf("----- BACKLIGHTS -----\n");
+    printf("------ BACKLIGHTS ------\n");
     printf("LCD brightness=");
     dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness");
     printf("Button brightness=");
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index fda618c..39e14e4 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -43,13 +43,13 @@
     int fd = open(path, O_RDONLY);
     if (fd < 0) {
         int err = errno;
-        if (title) printf("----- %s (%s) -----\n", title, path);
+        if (title) printf("------ %s (%s) ------\n", title, path);
         printf("*** %s: %s\n", path, strerror(err));
         if (title) printf("\n");
         return -1;
     }
 
-    if (title) printf("----- %s (%s", title, path);
+    if (title) printf("------ %s (%s", title, path);
 
     if (title) {
         struct stat st;
@@ -59,7 +59,7 @@
             strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M:%S", localtime(&mtime));
             printf(": %s", stamp);
         }
-        printf(") -----\n");
+        printf(") ------\n");
     }
 
     int newline = 0;
@@ -97,13 +97,13 @@
 
         va_list ap;
         va_start(ap, command);
-        if (title) printf("----- %s (%s", title, command);
+        if (title) printf("------ %s (%s", title, command);
         for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) {
             args[arg] = va_arg(ap, const char *);
             if (args[arg] == NULL) break;
             if (title) printf(" %s", args[arg]);
         }
-        if (title) printf(") -----\n");
+        if (title) printf(") ------\n");
         fflush(stdout);
 
         execvp(command, (char**) args);
@@ -159,7 +159,7 @@
     property_list(print_prop, NULL);
     qsort(&props, num_props, sizeof(props[0]), compare_prop);
 
-    printf("----- SYSTEM PROPERTIES -----\n");
+    printf("------ SYSTEM PROPERTIES ------\n");
     for (i = 0; i < num_props; ++i) {
         fputs(props[i], stdout);
         free(props[i]);
diff --git a/cmds/installd/utils.c b/cmds/installd/utils.c
index 5db5545..555c19e 100644
--- a/cmds/installd/utils.c
+++ b/cmds/installd/utils.c
@@ -33,6 +33,7 @@
     }
 
     x = pkgname;
+    int alpha = -1;
     while (*x) {
         if (isalnum(*x) || (*x == '_')) {
                 /* alphanumeric or underscore are fine */
@@ -42,13 +43,28 @@
                 LOGE("invalid package name '%s'\n", pkgname);
                 return -1;
             }
-        } else {
+        } else if (*x == '-') {
+            /* Suffix -X is fine to let versioning of packages.
+               But whatever follows should be alphanumeric.*/
+            alpha = 1;
+        }else {
                 /* anything not A-Z, a-z, 0-9, _, or . is invalid */
             LOGE("invalid package name '%s'\n", pkgname);
             return -1;
         }
         x++;
     }
+    if (alpha == 1) {
+        // Skip current character
+        x++;
+        while (*x) {
+            if (!isalnum(*x)) {
+                LOGE("invalid package name '%s' should include only numbers after -\n", pkgname);
+                return -1;
+            }
+            x++;
+        }
+    }
 
     sprintf(path, "%s%s%s", prefix, pkgname, postfix);
     return 0;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 1c3414d..95142e3 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -39,6 +39,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
@@ -608,8 +609,13 @@
     private static final String SAVED_DIALOG_IDS_KEY = "android:savedDialogIds";
     private static final String SAVED_DIALOGS_TAG = "android:savedDialogs";
     private static final String SAVED_DIALOG_KEY_PREFIX = "android:dialog_";
+    private static final String SAVED_DIALOG_ARGS_KEY_PREFIX = "android:dialog_args_";
 
-    private SparseArray<Dialog> mManagedDialogs;
+    private static class ManagedDialog {
+        Dialog mDialog;
+        Bundle mArgs;
+    }
+    private SparseArray<ManagedDialog> mManagedDialogs;
 
     // set by the thread after the constructor and before onCreate(Bundle savedInstanceState) is called.
     private Instrumentation mInstrumentation;
@@ -850,35 +856,41 @@
 
         final int[] ids = b.getIntArray(SAVED_DIALOG_IDS_KEY);
         final int numDialogs = ids.length;
-        mManagedDialogs = new SparseArray<Dialog>(numDialogs);
+        mManagedDialogs = new SparseArray<ManagedDialog>(numDialogs);
         for (int i = 0; i < numDialogs; i++) {
             final Integer dialogId = ids[i];
             Bundle dialogState = b.getBundle(savedDialogKeyFor(dialogId));
             if (dialogState != null) {
                 // Calling onRestoreInstanceState() below will invoke dispatchOnCreate
                 // so tell createDialog() not to do it, otherwise we get an exception
-                final Dialog dialog = createDialog(dialogId, dialogState);
-                mManagedDialogs.put(dialogId, dialog);
-                onPrepareDialog(dialogId, dialog);
-                dialog.onRestoreInstanceState(dialogState);
+                final ManagedDialog md = new ManagedDialog();
+                md.mArgs = b.getBundle(savedDialogArgsKeyFor(dialogId));
+                md.mDialog = createDialog(dialogId, dialogState, md.mArgs);
+                if (md.mDialog != null) {
+                    mManagedDialogs.put(dialogId, md);
+                    onPrepareDialog(dialogId, md.mDialog, md.mArgs);
+                    md.mDialog.onRestoreInstanceState(dialogState);
+                }
             }
         }
     }
 
-    private Dialog createDialog(Integer dialogId, Bundle state) {
-        final Dialog dialog = onCreateDialog(dialogId);
+    private Dialog createDialog(Integer dialogId, Bundle state, Bundle args) {
+        final Dialog dialog = onCreateDialog(dialogId, args);
         if (dialog == null) {
-            throw new IllegalArgumentException("Activity#onCreateDialog did "
-                    + "not create a dialog for id " + dialogId);
+            return null;
         }
         dialog.dispatchOnCreate(state);
         return dialog;
     }
 
-    private String savedDialogKeyFor(int key) {
+    private static String savedDialogKeyFor(int key) {
         return SAVED_DIALOG_KEY_PREFIX + key;
     }
 
+    private static String savedDialogArgsKeyFor(int key) {
+        return SAVED_DIALOG_ARGS_KEY_PREFIX + key;
+    }
 
     /**
      * Called when activity start-up is complete (after {@link #onStart}
@@ -1095,8 +1107,11 @@
         for (int i = 0; i < numDialogs; i++) {
             final int key = mManagedDialogs.keyAt(i);
             ids[i] = key;
-            final Dialog dialog = mManagedDialogs.valueAt(i);
-            dialogState.putBundle(savedDialogKeyFor(key), dialog.onSaveInstanceState());
+            final ManagedDialog md = mManagedDialogs.valueAt(i);
+            dialogState.putBundle(savedDialogKeyFor(key), md.mDialog.onSaveInstanceState());
+            if (md.mArgs != null) {
+                dialogState.putBundle(savedDialogArgsKeyFor(key), md.mArgs);
+            }
         }
 
         dialogState.putIntArray(SAVED_DIALOG_IDS_KEY, ids);
@@ -1282,14 +1297,14 @@
 
         // dismiss any dialogs we are managing.
         if (mManagedDialogs != null) {
-
             final int numDialogs = mManagedDialogs.size();
             for (int i = 0; i < numDialogs; i++) {
-                final Dialog dialog = mManagedDialogs.valueAt(i);
-                if (dialog.isShowing()) {
-                    dialog.dismiss();
+                final ManagedDialog md = mManagedDialogs.valueAt(i);
+                if (md.mDialog.isShowing()) {
+                    md.mDialog.dismiss();
                 }
             }
+            mManagedDialogs = null;
         }
 
         // close any cursors we are managing.
@@ -1300,6 +1315,7 @@
                 c.mCursor.close();
             }
         }
+        mManagedCursors.clear();
     }
 
     /**
@@ -2410,36 +2426,57 @@
     }
 
     /**
-     * Callback for creating dialogs that are managed (saved and restored) for you
-     * by the activity.
-     *
-     * If you use {@link #showDialog(int)}, the activity will call through to
-     * this method the first time, and hang onto it thereafter.  Any dialog
-     * that is created by this method will automatically be saved and restored
-     * for you, including whether it is showing.
-     *
-     * If you would like the activity to manage the saving and restoring dialogs
-     * for you, you should override this method and handle any ids that are
-     * passed to {@link #showDialog}.
-     *
-     * If you would like an opportunity to prepare your dialog before it is shown,
-     * override {@link #onPrepareDialog(int, Dialog)}.
-     *
-     * @param id The id of the dialog.
-     * @return The dialog
-     *
-     * @see #onPrepareDialog(int, Dialog)
-     * @see #showDialog(int)
-     * @see #dismissDialog(int)
-     * @see #removeDialog(int)
+     * @deprecated Old no-arguments version of {@link #onCreateDialog(int, Bundle)}.
      */
+    @Deprecated
     protected Dialog onCreateDialog(int id) {
         return null;
     }
 
     /**
+     * Callback for creating dialogs that are managed (saved and restored) for you
+     * by the activity.  The default implementation calls through to
+     * {@link #onCreateDialog(int)} for compatibility.
+     *
+     * <p>If you use {@link #showDialog(int)}, the activity will call through to
+     * this method the first time, and hang onto it thereafter.  Any dialog
+     * that is created by this method will automatically be saved and restored
+     * for you, including whether it is showing.
+     *
+     * <p>If you would like the activity to manage saving and restoring dialogs
+     * for you, you should override this method and handle any ids that are
+     * passed to {@link #showDialog}.
+     *
+     * <p>If you would like an opportunity to prepare your dialog before it is shown,
+     * override {@link #onPrepareDialog(int, Dialog, Bundle)}.
+     *
+     * @param id The id of the dialog.
+     * @param args The dialog arguments provided to {@link #showDialog(int, Bundle)}.
+     * @return The dialog.  If you return null, the dialog will not be created.
+     *
+     * @see #onPrepareDialog(int, Dialog, Bundle)
+     * @see #showDialog(int, Bundle)
+     * @see #dismissDialog(int)
+     * @see #removeDialog(int)
+     */
+    protected Dialog onCreateDialog(int id, Bundle args) {
+        return onCreateDialog(id);
+    }
+
+    /**
+     * @deprecated Old no-arguments version of
+     * {@link #onPrepareDialog(int, Dialog, Bundle)}.
+     */
+    @Deprecated
+    protected void onPrepareDialog(int id, Dialog dialog) {
+        dialog.setOwnerActivity(this);
+    }
+
+    /**
      * Provides an opportunity to prepare a managed dialog before it is being
-     * shown.
+     * shown.  The default implementation calls through to
+     * {@link #onPrepareDialog(int, Dialog)} for compatibility.
+     * 
      * <p>
      * Override this if you need to update a managed dialog based on the state
      * of the application each time it is shown. For example, a time picker
@@ -2449,43 +2486,66 @@
      * 
      * @param id The id of the managed dialog.
      * @param dialog The dialog.
-     * @see #onCreateDialog(int)
+     * @param args The dialog arguments provided to {@link #showDialog(int, Bundle)}.
+     * @see #onCreateDialog(int, Bundle)
      * @see #showDialog(int)
      * @see #dismissDialog(int)
      * @see #removeDialog(int)
      */
-    protected void onPrepareDialog(int id, Dialog dialog) {
-        dialog.setOwnerActivity(this);
+    protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
+        onPrepareDialog(id, dialog);
     }
 
     /**
-     * Show a dialog managed by this activity.  A call to {@link #onCreateDialog(int)}
+     * Simple version of {@link #showDialog(int, Bundle)} that does not
+     * take any arguments.  Simply calls {@link #showDialog(int, Bundle)}
+     * with null arguments.
+     */
+    public final void showDialog(int id) {
+        showDialog(id, null);
+    }
+
+    /**
+     * Show a dialog managed by this activity.  A call to {@link #onCreateDialog(int, Bundle)}
      * will be made with the same id the first time this is called for a given
      * id.  From thereafter, the dialog will be automatically saved and restored.
      *
-     * Each time a dialog is shown, {@link #onPrepareDialog(int, Dialog)} will
+     * <p>Each time a dialog is shown, {@link #onPrepareDialog(int, Dialog, Bundle)} will
      * be made to provide an opportunity to do any timely preparation.
      *
      * @param id The id of the managed dialog.
-     *
+     * @param args Arguments to pass through to the dialog.  These will be saved
+     * and restored for you.  Note that if the dialog is already created,
+     * {@link #onCreateDialog(int, Bundle)} will not be called with the new
+     * arguments but {@link #onPrepareDialog(int, Dialog, Bundle)} will be.
+     * If you need to rebuild the dialog, call {@link #removeDialog(int)}Êfirst.
+     * @return Returns true if the Dialog was created; false is returned if
+     * it is not created because {@link #onCreateDialog(int, Bundle)} returns false.
+     * 
      * @see Dialog
-     * @see #onCreateDialog(int)
-     * @see #onPrepareDialog(int, Dialog)
+     * @see #onCreateDialog(int, Bundle)
+     * @see #onPrepareDialog(int, Dialog, Bundle)
      * @see #dismissDialog(int)
      * @see #removeDialog(int)
      */
-    public final void showDialog(int id) {
+    public final boolean showDialog(int id, Bundle args) {
         if (mManagedDialogs == null) {
-            mManagedDialogs = new SparseArray<Dialog>();
+            mManagedDialogs = new SparseArray<ManagedDialog>();
         }
-        Dialog dialog = mManagedDialogs.get(id);
-        if (dialog == null) {
-            dialog = createDialog(id, null);
-            mManagedDialogs.put(id, dialog);
+        ManagedDialog md = mManagedDialogs.get(id);
+        if (md == null) {
+            md = new ManagedDialog();
+            md.mDialog = createDialog(id, null, args);
+            if (md.mDialog == null) {
+                return false;
+            }
+            mManagedDialogs.put(id, md);
         }
         
-        onPrepareDialog(id, dialog);
-        dialog.show();
+        md.mArgs = args;
+        onPrepareDialog(id, md.mDialog, args);
+        md.mDialog.show();
+        return true;
     }
 
     /**
@@ -2496,21 +2556,21 @@
      * @throws IllegalArgumentException if the id was not previously shown via
      *   {@link #showDialog(int)}.
      *
-     * @see #onCreateDialog(int)
-     * @see #onPrepareDialog(int, Dialog)
+     * @see #onCreateDialog(int, Bundle)
+     * @see #onPrepareDialog(int, Dialog, Bundle)
      * @see #showDialog(int)
      * @see #removeDialog(int)
      */
     public final void dismissDialog(int id) {
         if (mManagedDialogs == null) {
             throw missingDialog(id);
-
         }
-        final Dialog dialog = mManagedDialogs.get(id);
-        if (dialog == null) {
+        
+        final ManagedDialog md = mManagedDialogs.get(id);
+        if (md == null) {
             throw missingDialog(id);
         }
-        dialog.dismiss();
+        md.mDialog.dismiss();
     }
 
     /**
@@ -2526,28 +2586,27 @@
      * Removes any internal references to a dialog managed by this Activity.
      * If the dialog is showing, it will dismiss it as part of the clean up.
      *
-     * This can be useful if you know that you will never show a dialog again and
+     * <p>This can be useful if you know that you will never show a dialog again and
      * want to avoid the overhead of saving and restoring it in the future.
      *
      * @param id The id of the managed dialog.
      *
-     * @see #onCreateDialog(int)
-     * @see #onPrepareDialog(int, Dialog)
+     * @see #onCreateDialog(int, Bundle)
+     * @see #onPrepareDialog(int, Dialog, Bundle)
      * @see #showDialog(int)
      * @see #dismissDialog(int)
      */
     public final void removeDialog(int id) {
-
         if (mManagedDialogs == null) {
             return;
         }
 
-        final Dialog dialog = mManagedDialogs.get(id);
-        if (dialog == null) {
+        final ManagedDialog md = mManagedDialogs.get(id);
+        if (md == null) {
             return;
         }
 
-        dialog.dismiss();
+        md.mDialog.dismiss();
         mManagedDialogs.remove(id);
     }
 
@@ -3449,17 +3508,7 @@
             return;
         }
         
-        // uses super.getSystemService() since this.getSystemService() looks at the
-        // mSearchManager field.
-        mSearchManager = (SearchManager) super.getSystemService(Context.SEARCH_SERVICE);
-        int ident = mIdent;
-        if (ident == 0) {
-            if (mParent != null) ident = mParent.mIdent;
-            if (ident == 0) {
-                throw new IllegalArgumentException("no ident");
-            }
-        }
-        mSearchManager.setIdent(ident, getComponentName());
+        mSearchManager = new SearchManager(this, null);
     }
     
     @Override
diff --git a/core/java/android/app/DeviceAdmin.java b/core/java/android/app/DeviceAdmin.java
index 9750d6e..88fdab2 100644
--- a/core/java/android/app/DeviceAdmin.java
+++ b/core/java/android/app/DeviceAdmin.java
@@ -22,6 +22,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.os.Bundle;
 
 /**
  * Base class for implementing a device administration component.  This
@@ -62,6 +63,27 @@
             = "android.app.action.DEVICE_ADMIN_ENABLED";
 
     /**
+     * Action sent to a device administrator when the user has requested to
+     * disable it, but before this has actually been done.  This gives you
+     * a chance to supply a message to the user about the impact of
+     * disabling your admin, by setting the extra field
+     * {@link #EXTRA_DISABLE_WARNING} in the result Intent.  If not set,
+     * no warning will be displayed.  If set, the given text will be shown
+     * to the user before they disable your admin.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED
+            = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED";
+    
+    /**
+     * A CharSequence that can be shown to the user informing them of the
+     * impact of disabling your admin.
+     *
+     * @see #ACTION_DEVICE_ADMIN_DISABLE_REQUESTED
+     */
+    public static final String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING";
+    
+    /**
      * Action sent to a device administrator when the user has disabled
      * it.  Upon return, the application no longer has access to the
      * protected device policy manager APIs.  You will generally
@@ -166,6 +188,21 @@
     }
     
     /**
+     * Called when the user has asked to disable the administrator, as a result of
+     * receiving {@link #ACTION_DEVICE_ADMIN_DISABLE_REQUESTED}, giving you
+     * a chance to present a warning message to them.  The message is returned
+     * as the result; if null is returned (the default implementation), no
+     * message will be displayed.
+     * @param context The running context as per {@link #onReceive}.
+     * @param intent The received intent as per {@link #onReceive}.
+     * @return Return the warning message to display to the user before
+     * being disabled; if null is returned, no message is displayed.
+     */
+    public CharSequence onDisableRequested(Context context, Intent intent) {
+        return null;
+    }
+    
+    /**
      * Called prior to the administrator being disabled, as a result of
      * receiving {@link #ACTION_DEVICE_ADMIN_DISABLED}.  Upon return, you
      * can no longer use the protected parts of the {@link DevicePolicyManager}
@@ -226,6 +263,12 @@
             onPasswordSucceeded(context, intent);
         } else if (ACTION_DEVICE_ADMIN_ENABLED.equals(action)) {
             onEnabled(context, intent);
+        } else if (ACTION_DEVICE_ADMIN_DISABLE_REQUESTED.equals(action)) {
+            CharSequence res = onDisableRequested(context, intent);
+            if (res != null) {
+                Bundle extras = getResultExtras(true);
+                extras.putCharSequence(EXTRA_DISABLE_WARNING, res);
+            }
         } else if (ACTION_DEVICE_ADMIN_DISABLED.equals(action)) {
             onDisabled(context, intent);
         }
diff --git a/core/java/android/app/DeviceAdminInfo.java b/core/java/android/app/DeviceAdminInfo.java
index 92fdbc8..e50db89 100644
--- a/core/java/android/app/DeviceAdminInfo.java
+++ b/core/java/android/app/DeviceAdminInfo.java
@@ -19,7 +19,6 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import android.R;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
@@ -111,48 +110,47 @@
 
     /** @hide */
     public static class PolicyInfo {
+        public final int ident;
         final public String tag;
         final public int label;
         final public int description;
         
-        public PolicyInfo(String tagIn, int labelIn, int descriptionIn) {
+        public PolicyInfo(int identIn, String tagIn, int labelIn, int descriptionIn) {
+            ident = identIn;
             tag = tagIn;
             label = labelIn;
             description = descriptionIn;
         }
     }
     
+    static ArrayList<PolicyInfo> sPoliciesDisplayOrder = new ArrayList<PolicyInfo>();
     static HashMap<String, Integer> sKnownPolicies = new HashMap<String, Integer>();
     static SparseArray<PolicyInfo> sRevKnownPolicies = new SparseArray<PolicyInfo>();
     
     static {
-        sRevKnownPolicies.put(USES_POLICY_LIMIT_PASSWORD,
-                new PolicyInfo("limit-password",
-                        com.android.internal.R.string.policylab_limitPassword,
-                        com.android.internal.R.string.policydesc_limitPassword));
-        sRevKnownPolicies.put(USES_POLICY_WATCH_LOGIN,
-                new PolicyInfo("watch-login",
-                        com.android.internal.R.string.policylab_watchLogin,
-                        com.android.internal.R.string.policydesc_watchLogin));
-        sRevKnownPolicies.put(USES_POLICY_RESET_PASSWORD,
-                new PolicyInfo("reset-password",
-                        com.android.internal.R.string.policylab_resetPassword,
-                        com.android.internal.R.string.policydesc_resetPassword));
-        sRevKnownPolicies.put(USES_POLICY_LIMIT_UNLOCK,
-                new PolicyInfo("limit-unlock",
-                        com.android.internal.R.string.policylab_limitUnlock,
-                        com.android.internal.R.string.policydesc_limitUnlock));
-        sRevKnownPolicies.put(USES_POLICY_FORCE_LOCK,
-                new PolicyInfo("force-lock",
-                        com.android.internal.R.string.policylab_forceLock,
-                        com.android.internal.R.string.policydesc_forceLock));
-        sRevKnownPolicies.put(USES_POLICY_WIPE_DATA,
-                new PolicyInfo("wipe-data",
-                        com.android.internal.R.string.policylab_wipeData,
-                        com.android.internal.R.string.policydesc_wipeData));
-        for (int i=0; i<sRevKnownPolicies.size(); i++) {
-            sKnownPolicies.put(sRevKnownPolicies.valueAt(i).tag,
-                    sRevKnownPolicies.keyAt(i));
+        sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WIPE_DATA, "wipe-data",
+                com.android.internal.R.string.policylab_wipeData,
+                com.android.internal.R.string.policydesc_wipeData));
+        sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_RESET_PASSWORD, "reset-password",
+                com.android.internal.R.string.policylab_resetPassword,
+                com.android.internal.R.string.policydesc_resetPassword));
+        sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_LIMIT_PASSWORD, "limit-password",
+                com.android.internal.R.string.policylab_limitPassword,
+                com.android.internal.R.string.policydesc_limitPassword));
+        sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WATCH_LOGIN, "watch-login",
+                com.android.internal.R.string.policylab_watchLogin,
+                com.android.internal.R.string.policydesc_watchLogin));
+        sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_LIMIT_UNLOCK, "limit-unlock",
+                com.android.internal.R.string.policylab_limitUnlock,
+                com.android.internal.R.string.policydesc_limitUnlock));
+        sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_FORCE_LOCK, "force-lock",
+                com.android.internal.R.string.policylab_forceLock,
+                com.android.internal.R.string.policydesc_forceLock));
+        
+        for (int i=0; i<sPoliciesDisplayOrder.size(); i++) {
+            PolicyInfo pi = sPoliciesDisplayOrder.get(i);
+            sRevKnownPolicies.put(pi.ident, pi);
+            sKnownPolicies.put(pi.tag, pi.ident);
         }
     }
     
@@ -335,10 +333,10 @@
     /** @hide */
     public ArrayList<PolicyInfo> getUsedPolicies() {
         ArrayList<PolicyInfo> res = new ArrayList<PolicyInfo>();
-        for (int i=0; i<sRevKnownPolicies.size(); i++) {
-            int ident = sRevKnownPolicies.keyAt(i);
-            if (usesPolicy(ident)) {
-                res.add(sRevKnownPolicies.valueAt(i));
+        for (int i=0; i<sPoliciesDisplayOrder.size(); i++) {
+            PolicyInfo pi = sPoliciesDisplayOrder.get(i);
+            if (usesPolicy(pi.ident)) {
+                res.add(pi);
             }
         }
         return res;
diff --git a/core/java/android/app/DevicePolicyManager.java b/core/java/android/app/DevicePolicyManager.java
index 25e3230..9de7336 100644
--- a/core/java/android/app/DevicePolicyManager.java
+++ b/core/java/android/app/DevicePolicyManager.java
@@ -26,6 +26,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Handler;
+import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
@@ -43,8 +44,9 @@
     private static boolean localLOGV = DEBUG || android.util.Config.LOGV;
 
     private final Context mContext;
-    private final Handler mHandler;
     private final IDevicePolicyManager mService;
+    
+    private final Handler mHandler;
 
     /*package*/ DevicePolicyManager(Context context, Handler handler) {
         mContext = context;
@@ -60,6 +62,10 @@
      * bring the user through adding the device administrator to the system (or
      * allowing them to reject it).
      * 
+     * <p>You can optionally include the {@link #EXTRA_ADD_EXPLANATION}
+     * field to provide the user with additional explanation (in addition
+     * to your component's description) about what is being added.
+     * 
      * <p>Note: the current platform can only have one device administrator
      * active at a time.  If you make this request while there is already
      * an active administrator, this new request will be canceled automatically.
@@ -76,6 +82,14 @@
     public static final String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
     
     /**
+     * An optional CharSequence providing additional explanation for why the
+     * admin is being added.
+     *
+     * @see #ACTION_ADD_DEVICE_ADMIN
+     */
+    public static final String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
+    
+    /**
      * Activity action: have the user enter a new password.  This activity
      * should be launched after using {@link #setPasswordMode(ComponentName, int)}
      * or {@link #setMinimumPasswordLength(ComponentName, int)} to have the
@@ -285,6 +299,29 @@
     }
 
     /**
+     * Set the maximum number of failed password attempts that are allowed
+     * before the device wipes its data.  This is convenience for implementing
+     * the corresponding functionality with a combination of watching failed
+     * password attempts and calling {@link #wipeData} upon reaching a certain
+     * count, and as such requires that you request both
+     * {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} and
+     * {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}}.
+     * 
+     * @param admin Which {@link DeviceAdmin} this request is associated with.
+     * @param num The number of failed password attempts at which point the
+     * device will wipe its data.
+     */
+    public void setMaximumFailedPasswordsForWipe(ComponentName admin, int num) {
+        if (mService != null) {
+            try {
+                mService.setMaximumFailedPasswordsForWipe(admin, num);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+    
+    /**
      * Force a new password on the user.  This takes effect immediately.  The
      * given password must meet the current password minimum length constraint
      * or it will be rejected.  The given password will be accepted regardless
@@ -451,6 +488,19 @@
     /**
      * @hide
      */
+    public void getRemoveWarning(ComponentName admin, RemoteCallback result) {
+        if (mService != null) {
+            try {
+                mService.getRemoveWarning(admin, result);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
     public void setActivePasswordState(int mode, int length) {
         if (mService != null) {
             try {
diff --git a/core/java/android/app/IDevicePolicyManager.aidl b/core/java/android/app/IDevicePolicyManager.aidl
index 7e38194..edb8603 100644
--- a/core/java/android/app/IDevicePolicyManager.aidl
+++ b/core/java/android/app/IDevicePolicyManager.aidl
@@ -18,6 +18,7 @@
 package android.app;
 
 import android.content.ComponentName;
+import android.os.RemoteCallback;
 
 /**
  * Internal IPC interface to the device policy service.
@@ -32,6 +33,7 @@
     
     boolean isActivePasswordSufficient();
     int getCurrentFailedPasswordAttempts();
+    void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num);
     
     boolean resetPassword(String password);
     
@@ -44,6 +46,7 @@
     
     void setActiveAdmin(in ComponentName policyReceiver);
     ComponentName getActiveAdmin();
+    void getRemoveWarning(in ComponentName policyReceiver, in RemoteCallback result);
     void removeActiveAdmin(in ComponentName policyReceiver);
     
     void setActivePasswordState(int mode, int length);
diff --git a/core/java/android/app/ISearchManager.aidl b/core/java/android/app/ISearchManager.aidl
index 0920467..9ba7863 100644
--- a/core/java/android/app/ISearchManager.aidl
+++ b/core/java/android/app/ISearchManager.aidl
@@ -29,23 +29,4 @@
    List<SearchableInfo> getSearchablesForWebSearch();
    SearchableInfo getDefaultSearchableForWebSearch();
    void setDefaultWebSearch(in ComponentName component);
-   void startSearch(in String initialQuery,
-            boolean selectInitialQuery,
-            in ComponentName launchActivity,
-            in Bundle appSearchData,
-            boolean globalSearch,
-            ISearchManagerCallback searchManagerCallback,
-            int ident);
-
-    void triggerSearch(in String query,
-            in ComponentName launchActivity,
-            in Bundle appSearchData,
-            ISearchManagerCallback searchManagerCallback,
-            int ident);
-
-    void stopSearch();
-
-
-    boolean isVisible();
-
 }
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index b396396..3dfbe71 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -73,8 +73,8 @@
 import java.util.concurrent.atomic.AtomicLong;
 
 /**
- * System search dialog. This is controlled by the 
- * SearchManagerService and runs in the system process.
+ * Search dialog. This is controlled by the 
+ * SearchManager and runs in the current foreground process.
  * 
  * @hide
  */
@@ -118,6 +118,7 @@
     private Bundle mAppSearchData;
     private boolean mGlobalSearchMode;
     private Context mActivityContext;
+    private SearchManager mSearchManager;
     
     // Values we store to allow user to toggle between in-app search and global search.
     private ComponentName mStoredComponentName;
@@ -157,7 +158,7 @@
      * 
      * @param context Application Context we can use for system acess
      */
-    public SearchDialog(Context context) {
+    public SearchDialog(Context context, SearchManager searchManager) {
         super(context, com.android.internal.R.style.Theme_GlobalSearchBar);
 
         // Save voice intent for later queries/launching
@@ -168,6 +169,7 @@
 
         mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
         mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mSearchManager = searchManager;
     }
 
     /**
@@ -180,7 +182,6 @@
 
         Window theWindow = getWindow();
         WindowManager.LayoutParams lp = theWindow.getAttributes();
-        lp.type = WindowManager.LayoutParams.TYPE_SEARCH_BAR;
         lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
         // taking up the whole window (even when transparent) is less than ideal,
         // but necessary to show the popup window until the window manager supports
@@ -291,8 +292,10 @@
             //
             // TODO: When the browser icon issue is reconciled in Eclair, remove this special case.
             if (isBrowserSearch()) currentSearchText = "";
-            
-            return doShow(currentSearchText, false, null, mAppSearchData, true);
+
+            cancel();
+            mSearchManager.startGlobalSearch(currentSearchText, false, mStoredAppSearchData);
+            return true;
         } else {
             if (mStoredComponentName != null) {
                 // This means we should toggle *back* to an in-app search context from
@@ -1314,8 +1317,7 @@
     }
 
     /**
-     * Launches an intent, including any special intent handling.  Doesn't dismiss the dialog
-     * since that will be handled in {@link SearchDialogWrapper#performActivityResuming}
+     * Launches an intent, including any special intent handling.
      */
     private void launchIntent(Intent intent) {
         if (intent == null) {
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index d25d670..12a43478 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1709,7 +1709,7 @@
     /* package */ OnDismissListener mDismissListener = null;
     /* package */ OnCancelListener mCancelListener = null;
 
-    private final SearchManagerCallback mSearchManagerCallback = new SearchManagerCallback();
+    private SearchDialog mSearchDialog;
 
     /*package*/ SearchManager(Context context, Handler handler)  {
         mContext = context;
@@ -1778,31 +1778,29 @@
                             ComponentName launchActivity,
                             Bundle appSearchData,
                             boolean globalSearch) {
-        if (mIdent == 0) throw new IllegalArgumentException(
-                "Called from outside of an Activity context");
+        ensureSearchDialog();
 
         if (globalSearch) {
             startGlobalSearch(initialQuery, selectInitialQuery, appSearchData);
             return;
         }
 
-        if (!mAssociatedPackage.equals(launchActivity.getPackageName())) {
-            Log.w(TAG, "invoking app search on a different package " +
-                    "not associated with this search manager");
-        }
-        try {
-            // activate the search manager and start it up!
-            mService.startSearch(initialQuery, selectInitialQuery, launchActivity, appSearchData,
-                    globalSearch, mSearchManagerCallback, mIdent);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "startSearch() failed.", ex);
+        mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData,
+                globalSearch);
+    }
+
+    private void ensureSearchDialog() {
+        if (mSearchDialog == null) {
+            mSearchDialog = new SearchDialog(mContext, this);
+            mSearchDialog.setOnCancelListener(this);
+            mSearchDialog.setOnDismissListener(this);
         }
     }
 
     /**
      * Starts the global search activity.
      */
-    private void startGlobalSearch(String initialQuery, boolean selectInitialQuery,
+    /* package */ void startGlobalSearch(String initialQuery, boolean selectInitialQuery,
             Bundle appSearchData) {
         ComponentName globalSearchActivity = getGlobalSearchActivity();
         if (globalSearchActivity == null) {
@@ -1876,8 +1874,6 @@
     public void triggerSearch(String query,
                               ComponentName launchActivity,
                               Bundle appSearchData) {
-        if (mIdent == 0) throw new IllegalArgumentException(
-                "Called from outside of an Activity context");
         if (!mAssociatedPackage.equals(launchActivity.getPackageName())) {
             throw new IllegalArgumentException("invoking app search on a different package " +
                     "not associated with this search manager");
@@ -1886,12 +1882,8 @@
             Log.w(TAG, "triggerSearch called with empty query, ignoring.");
             return;
         }
-        try {
-            mService.triggerSearch(query, launchActivity, appSearchData, mSearchManagerCallback,
-                    mIdent);
-        } catch (RemoteException ex) {
-            Log.e(TAG, "triggerSearch() failed.", ex);
-        }
+        startSearch(query, false, launchActivity, appSearchData, false);
+        mSearchDialog.launchQuerySearch();
     }
 
     /**
@@ -1906,10 +1898,8 @@
      * @see #startSearch
      */
     public void stopSearch() {
-        if (DBG) debug("stopSearch()");
-        try {
-            mService.stopSearch();
-        } catch (RemoteException ex) {
+        if (mSearchDialog != null) {
+            mSearchDialog.cancel();
         }
     }
 
@@ -1923,13 +1913,7 @@
      * @hide
      */
     public boolean isVisible() {
-        if (DBG) debug("isVisible()");
-        try {
-            return mService.isVisible();
-        } catch (RemoteException e) {
-            Log.e(TAG, "isVisible() failed: " + e);
-            return false;
-        }
+        return mSearchDialog == null? false : mSearchDialog.isShowing();
     }
 
     /**
@@ -1976,44 +1960,14 @@
         mCancelListener = listener;
     }
 
-    private class SearchManagerCallback extends ISearchManagerCallback.Stub {
-
-        private final Runnable mFireOnDismiss = new Runnable() {
-            public void run() {
-                if (DBG) debug("mFireOnDismiss");
-                if (mDismissListener != null) {
-                    mDismissListener.onDismiss();
-                }
-            }
-        };
-
-        private final Runnable mFireOnCancel = new Runnable() {
-            public void run() {
-                if (DBG) debug("mFireOnCancel");
-                if (mCancelListener != null) {
-                    mCancelListener.onCancel();
-                }
-            }
-        };
-
-        public void onDismiss() {
-            if (DBG) debug("onDismiss()");
-            mHandler.post(mFireOnDismiss);
-        }
-
-        public void onCancel() {
-            if (DBG) debug("onCancel()");
-            mHandler.post(mFireOnCancel);
-        }
-
-    }
-
     /**
      * @deprecated This method is an obsolete internal implementation detail. Do not use.
      */
     @Deprecated
     public void onCancel(DialogInterface dialog) {
-        throw new UnsupportedOperationException();
+        if (mCancelListener != null) {
+            mCancelListener.onCancel();
+        }
     }
 
     /**
@@ -2021,7 +1975,9 @@
      */
     @Deprecated
     public void onDismiss(DialogInterface dialog) {
-        throw new UnsupportedOperationException();
+        if (mDismissListener != null) {
+            mDismissListener.onDismiss();
+        }
     }
 
     /**
@@ -2208,4 +2164,4 @@
         Thread thread = Thread.currentThread();
         Log.d(TAG, msg + " (" + thread.getName() + "-" + thread.getId() + ")");
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index d90536c..4c4455a 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -543,6 +543,21 @@
     public native final void stopSmoothZoom();
 
     /**
+     * Set the display orientation. This affects the preview frames and the
+     * picture displayed after snapshot. This method is useful for portrait
+     * mode applications.
+     *
+     * This does not affect the order of byte array passed in
+     * {@link PreviewCallback#onPreviewFrame}. This method is not allowed to
+     * be called during preview.
+     *
+     * @param degrees the angle that the picture will be rotated clockwise.
+     *                Valid values are 0, 90, 180, and 270.
+     * @hide
+     */
+    public native final void setDisplayOrientation(int degrees);
+
+    /**
      * Handles the zoom callback.
      *
      * @hide
diff --git a/core/java/android/os/IRemoteCallback.aidl b/core/java/android/os/IRemoteCallback.aidl
new file mode 100644
index 0000000..f0c6c73
--- /dev/null
+++ b/core/java/android/os/IRemoteCallback.aidl
@@ -0,0 +1,25 @@
+/* //device/java/android/android/app/IActivityPendingResult.aidl
+**
+** Copyright 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;
+
+import android.os.Bundle;
+
+/** @hide */
+oneway interface IRemoteCallback {
+    void sendResult(in Bundle data);
+}
diff --git a/core/java/android/os/MailboxNotAvailableException.java b/core/java/android/os/MailboxNotAvailableException.java
deleted file mode 100644
index 574adbd..0000000
--- a/core/java/android/os/MailboxNotAvailableException.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2006 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;
-
-/** @hide */
-public class MailboxNotAvailableException extends Throwable
-{
-  /**
-   * This exception represents the case when a request for a
-   * named, published mailbox fails because the requested name has not been published
-   */
-
-    public
-    MailboxNotAvailableException()
-    {
-    }
-
-    public
-    MailboxNotAvailableException(String s)
-    {
-        super(s);
-    }
-}
diff --git a/core/java/android/os/Messenger.java b/core/java/android/os/Messenger.java
index 1bc554e..ad55abdd 100644
--- a/core/java/android/os/Messenger.java
+++ b/core/java/android/os/Messenger.java
@@ -29,7 +29,7 @@
      * Create a new Messenger pointing to the given Handler.  Any Message
      * objects sent through this Messenger will appear in the Handler as if
      * {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had
-     * be called directly.
+     * been called directly.
      * 
      * @param target The Handler that will receive sent messages.
      */
diff --git a/core/java/android/os/RemoteCallback.aidl b/core/java/android/os/RemoteCallback.aidl
new file mode 100644
index 0000000..7ae56f5
--- /dev/null
+++ b/core/java/android/os/RemoteCallback.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 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;
+
+parcelable RemoteCallback;
diff --git a/core/java/android/os/RemoteCallback.java b/core/java/android/os/RemoteCallback.java
new file mode 100644
index 0000000..ca95bdf
--- /dev/null
+++ b/core/java/android/os/RemoteCallback.java
@@ -0,0 +1,107 @@
+/*
+ * 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;
+
+/**
+ * TODO: Make this a public API?  Let's see how it goes with a few use
+ * cases first.
+ * @hide
+ */
+public abstract class RemoteCallback implements Parcelable {
+    final Handler mHandler;
+    final IRemoteCallback mTarget;
+    
+    class DeliverResult implements Runnable {
+        final Bundle mResult;
+        
+        DeliverResult(Bundle result) {
+            mResult = result;
+        }
+        
+        public void run() {
+            onResult(mResult);
+        }
+    }
+    
+    class LocalCallback extends IRemoteCallback.Stub {
+        public void sendResult(Bundle bundle) {
+            mHandler.post(new DeliverResult(bundle));
+        }
+    }
+    
+    static class RemoteCallbackProxy extends RemoteCallback {
+        RemoteCallbackProxy(IRemoteCallback target) {
+            super(target);
+        }
+        
+        protected void onResult(Bundle bundle) {
+        }
+    }
+    
+    public RemoteCallback(Handler handler) {
+        mHandler = handler;
+        mTarget = new LocalCallback();
+    }
+    
+     RemoteCallback(IRemoteCallback target) {
+        mHandler = null;
+        mTarget = target;
+    }
+    
+    public void sendResult(Bundle bundle) throws RemoteException {
+        mTarget.sendResult(bundle);
+    }
+    
+    protected abstract void onResult(Bundle bundle);
+    
+    public boolean equals(Object otherObj) {
+        if (otherObj == null) {
+            return false;
+        }
+        try {
+            return mTarget.asBinder().equals(((RemoteCallback)otherObj)
+                    .mTarget.asBinder());
+        } catch (ClassCastException e) {
+        }
+        return false;
+    }
+    
+    public int hashCode() {
+        return mTarget.asBinder().hashCode();
+    }
+    
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeStrongBinder(mTarget.asBinder());
+    }
+
+    public static final Parcelable.Creator<RemoteCallback> CREATOR
+            = new Parcelable.Creator<RemoteCallback>() {
+        public RemoteCallback createFromParcel(Parcel in) {
+            IBinder target = in.readStrongBinder();
+            return target != null ? new RemoteCallbackProxy(
+                    IRemoteCallback.Stub.asInterface(target)) : null;
+        }
+
+        public RemoteCallback[] newArray(int size) {
+            return new RemoteCallback[size];
+        }
+    };
+}
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index d67169f..ef43afe 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -34,12 +34,6 @@
         Uri.parse("content://browser/bookmarks");
 
     /**
-     * The inline scheme to show embedded content in a browser.
-     * @hide
-     */
-    public static final Uri INLINE_URI = Uri.parse("inline:");
-
-    /**
      * The name of extra data when starting Browser with ACTION_VIEW or
      * ACTION_SEARCH intent.
      * <p>
@@ -62,24 +56,6 @@
         "com.android.browser.application_id";
 
     /**
-     * The content to be rendered when url's scheme is inline.
-     * @hide
-     */
-    public static final String EXTRA_INLINE_CONTENT ="com.android.browser.inline.content";
-
-    /**
-     * The encoding of the inlined content for inline scheme.
-     * @hide
-     */
-    public static final String EXTRA_INLINE_ENCODING ="com.android.browser.inline.encoding";
-
-    /**
-     * The url used when the inline content is falied to render.
-     * @hide
-     */
-    public static final String EXTRA_INLINE_FAILURL ="com.android.browser.inline.failurl";
-
-    /**
      * The name of the extra data in the VIEW intent. The data is in boolean.
      * <p>
      * If the Browser is handling the intent and the setting for
@@ -102,6 +78,27 @@
      */
     public static final String EXTRA_POST_DATA = "com.android.browser.post_data";
 
+    /**
+     * The name of the extra data in the VIEW intent. The data is in the format
+     * of String array. This should be paired with EXTRA_HEADERS_VALUE.
+     * <p>
+     * The keys will be combined with the values and sent in the HTTP request
+     * headers for the provided url. The keys can't be the standard HTTP headers
+     * as they are set by the WebView. The url's schema must be http(s).
+     * <p>
+     */
+    public static final String EXTRA_HEADERS_KEY = "com.android.browser.headers_key";
+
+    /**
+     * The name of the extra data in the VIEW intent. The data is in the format
+     * of String array. This should be paired with EXTRA_HEADERS_KEY.
+     * <p>
+     * The values will be combined with the keys and sent in the HTTP request
+     * headers for the provided url. The url's schema must be http(s).
+     * <p>
+     */
+    public static final String EXTRA_HEADERS_VALUE = "com.android.browser.headers_value";
+
     /* if you change column order you must also change indices
        below */
     public static final String[] HISTORY_PROJECTION = new String[] {
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index cbd8a26..f89ba91 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -744,9 +744,10 @@
                 try {
                     while (subCursor.moveToNext()) {
                         ContentValues extendedValues = new ContentValues();
-                        extendedValues.put(ExtendedProperties.NAME, cursor.getString(COLUMN_NAME));
+                        extendedValues.put(ExtendedProperties.NAME,
+                                subCursor.getString(COLUMN_NAME));
                         extendedValues.put(ExtendedProperties.VALUE,
-                                cursor.getString(COLUMN_VALUE));
+                                subCursor.getString(COLUMN_VALUE));
                         entity.addSubValue(ExtendedProperties.CONTENT_URI, extendedValues);
                     }
                 } finally {
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 6bf09b5..08ab166 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -517,6 +517,8 @@
     /**
      * This download couldn't be completed because of a storage issue.
      * Typically, that's because the filesystem is missing or full.
+     * Use the more specific {@link #STATUS_INSUFFICIENT_SPACE_ERROR}
+     * and {@link #STATUS_DEVICE_NOT_FOUND_ERROR} when appropriate.
      * @hide
      */
     public static final int STATUS_FILE_ERROR = 492;
@@ -558,6 +560,21 @@
     public static final int STATUS_TOO_MANY_REDIRECTS = 497;
 
     /**
+     * This download couldn't be completed due to insufficient storage
+     * space.  Typically, this is because the SD card is full.
+     * @hide
+     */
+    public static final int STATUS_INSUFFICIENT_SPACE_ERROR = 498;
+
+    /**
+     * This download couldn't be completed because no external storage
+     * device was found.  Typically, this is because the SD card is not
+     * mounted.
+     * @hide
+     */
+    public static final int STATUS_DEVICE_NOT_FOUND_ERROR = 499;
+
+    /**
      * This download is visible but only shows in the notifications
      * while it's in progress.
      * @hide
@@ -1019,6 +1036,8 @@
         /**
          * This download couldn't be completed because of a storage issue.
          * Typically, that's because the filesystem is missing or full.
+         * Use the more specific {@link #STATUS_INSUFFICIENT_SPACE_ERROR}
+         * and {@link #STATUS_DEVICE_NOT_FOUND_ERROR} when appropriate.
          */
         public static final int STATUS_FILE_ERROR = 492;
 
@@ -1054,6 +1073,19 @@
         public static final int STATUS_TOO_MANY_REDIRECTS = 497;
 
         /**
+         * This download couldn't be completed due to insufficient storage
+         * space.  Typically, this is because the SD card is full.
+         */
+        public static final int STATUS_INSUFFICIENT_SPACE_ERROR = 498;
+
+        /**
+         * This download couldn't be completed because no external storage
+         * device was found.  Typically, this is because the SD card is not
+         * mounted.
+         */
+        public static final int STATUS_DEVICE_NOT_FOUND_ERROR = 499;
+
+        /**
          * This download is visible but only shows in the notifications
          * while it's in progress.
          */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ecfea00..23a9f49 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2033,10 +2033,10 @@
         public static final String ALLOW_MOCK_LOCATION = "mock_location";
 
         /**
-         * The Android ID (a unique 64-bit value) as a hex string.
-         * Identical to that obtained by calling
-         * GoogleLoginService.getAndroidId(); it is also placed here
-         * so you can get it without binding to a service.
+         * A 64-bit number (as a hex string) that is randomly
+         * generated on the device's first boot and should remain
+         * constant for the lifetime of the device.  (The value may
+         * change if a factory reset is performed on the device.)
          */
         public static final String ANDROID_ID = "android_id";
 
diff --git a/core/java/android/server/search/SearchDialogWrapper.java b/core/java/android/server/search/SearchDialogWrapper.java
deleted file mode 100644
index 9ee64af..0000000
--- a/core/java/android/server/search/SearchDialogWrapper.java
+++ /dev/null
@@ -1,426 +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.server.search;
-
-import android.app.ISearchManagerCallback;
-import android.app.SearchDialog;
-import android.app.SearchManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.os.DeadObjectException;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.SystemProperties;
-import android.text.TextUtils;
-import android.util.Log;
-
-/**
- * Runs an instance of {@link SearchDialog} on its own thread.
- */
-class SearchDialogWrapper
-implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
-
-    private static final String TAG = "SearchManagerService";
-    private static final boolean DBG = false;
-
-    private static final String SEARCH_UI_THREAD_NAME = "SearchDialog";
-    private static final int SEARCH_UI_THREAD_PRIORITY =
-        android.os.Process.THREAD_PRIORITY_DEFAULT;
-
-    // Takes no arguments
-    private static final int MSG_INIT = 0;
-    // Takes these arguments:
-    // arg1: selectInitialQuery, 0 = false, 1 = true
-    // arg2: globalSearch, 0 = false, 1 = true
-    // obj: searchManagerCallback
-    // data[KEY_INITIAL_QUERY]: initial query
-    // data[KEY_LAUNCH_ACTIVITY]: launch activity
-    // data[KEY_APP_SEARCH_DATA]: app search data
-    // data[KEY_TRIGGER]: 0 = false, 1 = true
-    private static final int MSG_START_SEARCH = 1;
-    // Takes no arguments
-    private static final int MSG_STOP_SEARCH = 2;
-    // arg1 is activity id
-    private static final int MSG_ACTIVITY_RESUMING = 3;
-    // obj is the reason
-    private static final int MSG_CLOSING_SYSTEM_DIALOGS = 4;
-
-    private static final String KEY_INITIAL_QUERY = "q";
-    private static final String KEY_LAUNCH_ACTIVITY = "a";
-    private static final String KEY_APP_SEARCH_DATA = "d";
-    private static final String KEY_IDENT = "i";
-    private static final String KEY_TRIGGER = "t";
-
-    // Context used for getting search UI resources
-    private final Context mContext;
-
-    // Handles messages on the search UI thread.
-    private final SearchDialogHandler mSearchUiThread;
-
-    // The search UI
-    SearchDialog mSearchDialog;
-
-    // If the search UI is visible, this is the callback for the client that showed it.
-    ISearchManagerCallback mCallback = null;
-
-    // Identity of last activity that started search.
-    private int mStartedIdent = 0;
-    
-    // Identity of currently resumed activity.
-    private int mResumedIdent = 0;
-
-    // True if we have registered our receivers.
-    private boolean mReceiverRegistered;
-
-    private volatile boolean mVisible = false;
-    
-    /**
-     * Creates a new search dialog wrapper and a search UI thread. The search dialog itself will
-     * be created some asynchronously on the search UI thread.
-     *
-     * @param context Context used for getting search UI resources.
-     */
-    public SearchDialogWrapper(Context context) {
-        mContext = context;
-
-        // Create the search UI thread
-        HandlerThread t = new HandlerThread(SEARCH_UI_THREAD_NAME, SEARCH_UI_THREAD_PRIORITY);
-        t.start();
-        mSearchUiThread = new SearchDialogHandler(t.getLooper());
-
-        // Create search UI on the search UI thread
-        mSearchUiThread.sendEmptyMessage(MSG_INIT);
-    }
-
-    public boolean isVisible() {
-        return mVisible;
-    }
-
-    /**
-     * Initializes the search UI.
-     * Must be called from the search UI thread.
-     */
-    private void init() {
-        mSearchDialog = new SearchDialog(mContext);
-        mSearchDialog.setOnCancelListener(this);
-        mSearchDialog.setOnDismissListener(this);
-    }
-
-    private void registerBroadcastReceiver() {
-        if (!mReceiverRegistered) {
-            IntentFilter filter = new IntentFilter(
-                    Intent.ACTION_CONFIGURATION_CHANGED);
-            mContext.registerReceiver(mBroadcastReceiver, filter, null,
-                    mSearchUiThread);
-            mReceiverRegistered = true;
-        }
-    }
-
-    private void unregisterBroadcastReceiver() {
-        if (mReceiverRegistered) {
-            mContext.unregisterReceiver(mBroadcastReceiver);
-            mReceiverRegistered = false;
-        }
-    }
-
-    /**
-     * Closes the search dialog when requested by the system (e.g. when a phone call comes in).
-     */
-    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
-                if (DBG) debug(Intent.ACTION_CONFIGURATION_CHANGED);
-                performOnConfigurationChanged();
-            }
-        }
-    };
-
-    //
-    // External API
-    //
-
-    /**
-     * Launches the search UI.
-     * Can be called from any thread.
-     *
-     * @see SearchManager#startSearch(String, boolean, ComponentName, Bundle, boolean)
-     */
-    public void startSearch(final String initialQuery,
-            final boolean selectInitialQuery,
-            final ComponentName launchActivity,
-            final Bundle appSearchData,
-            final boolean globalSearch,
-            final ISearchManagerCallback searchManagerCallback,
-            int ident,
-            boolean trigger) {
-        if (DBG) debug("startSearch()");
-        Message msg = Message.obtain();
-        msg.what = MSG_START_SEARCH;
-        msg.arg1 = selectInitialQuery ? 1 : 0;
-        msg.arg2 = globalSearch ? 1 : 0;
-        msg.obj = searchManagerCallback;
-        Bundle msgData = msg.getData();
-        msgData.putString(KEY_INITIAL_QUERY, initialQuery);
-        msgData.putParcelable(KEY_LAUNCH_ACTIVITY, launchActivity);
-        msgData.putBundle(KEY_APP_SEARCH_DATA, appSearchData);
-        msgData.putInt(KEY_IDENT, ident);
-        msgData.putInt(KEY_TRIGGER, trigger ? 1 : 0);
-        mSearchUiThread.sendMessage(msg);
-        // be a little more eager in setting this so isVisible will return the correct value if
-        // called immediately after startSearch
-        mVisible = true;
-    }
-
-    /**
-     * Cancels the search dialog.
-     * Can be called from any thread.
-     */
-    public void stopSearch() {
-        if (DBG) debug("stopSearch()");
-        mSearchUiThread.sendEmptyMessage(MSG_STOP_SEARCH);
-        // be a little more eager in setting this so isVisible will return the correct value if
-        // called immediately after stopSearch
-        mVisible = false;
-    }
-
-    /**
-     * Updates the currently resumed activity.
-     * Can be called from any thread.
-     */
-    public void activityResuming(int ident) {
-        if (DBG) debug("activityResuming(ident=" + ident + ")");
-        Message msg = Message.obtain();
-        msg.what = MSG_ACTIVITY_RESUMING;
-        msg.arg1 = ident;
-        mSearchUiThread.sendMessage(msg);
-    }
-
-    /**
-     * Handles closing of system windows/dialogs
-     * Can be called from any thread.
-     */
-    public void closingSystemDialogs(String reason) {
-        if (DBG) debug("closingSystemDialogs(reason=" + reason + ")");
-        Message msg = Message.obtain();
-        msg.what = MSG_CLOSING_SYSTEM_DIALOGS;
-        msg.obj = reason;
-        mSearchUiThread.sendMessage(msg);
-    }
-
-    //
-    // Implementation methods that run on the search UI thread
-    //
-
-    private class SearchDialogHandler extends Handler {
-
-        public SearchDialogHandler(Looper looper) {
-            super(looper);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_INIT:
-                    init();
-                    break;
-                case MSG_START_SEARCH:
-                    handleStartSearchMessage(msg);
-                    break;
-                case MSG_STOP_SEARCH:
-                    performStopSearch();
-                    break;
-                case MSG_ACTIVITY_RESUMING:
-                    performActivityResuming(msg.arg1);
-                    break;
-                case MSG_CLOSING_SYSTEM_DIALOGS:
-                    performClosingSystemDialogs((String)msg.obj);
-                    break;
-            }
-        }
-
-        private void handleStartSearchMessage(Message msg) {
-            Bundle msgData = msg.getData();
-            String initialQuery = msgData.getString(KEY_INITIAL_QUERY);
-            boolean selectInitialQuery = msg.arg1 != 0;
-            ComponentName launchActivity =
-                    (ComponentName) msgData.getParcelable(KEY_LAUNCH_ACTIVITY);
-            Bundle appSearchData = msgData.getBundle(KEY_APP_SEARCH_DATA);
-            boolean globalSearch = msg.arg2 != 0;
-            ISearchManagerCallback searchManagerCallback = (ISearchManagerCallback) msg.obj;
-            int ident = msgData.getInt(KEY_IDENT);
-            boolean trigger = msgData.getInt(KEY_TRIGGER) != 0;
-            performStartSearch(initialQuery, selectInitialQuery, launchActivity,
-                    appSearchData, globalSearch, searchManagerCallback, ident, trigger);
-        }
-
-    }
-
-    /**
-     * Actually launches the search UI.
-     * This must be called on the search UI thread.
-     */
-    void performStartSearch(String initialQuery,
-            boolean selectInitialQuery,
-            ComponentName launchActivity,
-            Bundle appSearchData,
-            boolean globalSearch,
-            ISearchManagerCallback searchManagerCallback,
-            int ident,
-            boolean trigger) {
-        if (DBG) debug("performStartSearch()");
-
-        registerBroadcastReceiver();
-        mCallback = searchManagerCallback;
-
-        // clean up any hidden dialog that we were waiting to resume
-        if (mStartedIdent != 0) {
-            mSearchDialog.dismiss();
-        }
-
-        mStartedIdent = ident;
-        if (DBG) Log.v(TAG, "******************* DIALOG: start");
-
-        mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData,
-                globalSearch);
-        mVisible = true;
-        if (trigger) {
-            mSearchDialog.launchQuerySearch();
-        }
-    }
-
-    /**
-     * Actually cancels the search UI.
-     * This must be called on the search UI thread.
-     */
-    void performStopSearch() {
-        if (DBG) debug("performStopSearch()");
-        if (DBG) Log.v(TAG, "******************* DIALOG: cancel");
-        mSearchDialog.cancel();
-        mVisible = false;
-        mStartedIdent = 0;
-    }
-
-    /**
-     * Updates the resumed activity
-     * This must be called on the search UI thread.
-     */
-    void performActivityResuming(int ident) {
-        if (DBG) debug("performResumingActivity(): mStartedIdent="
-                + mStartedIdent + ", resuming: " + ident);
-        this.mResumedIdent = ident;
-        if (mStartedIdent != 0) {
-            if (mStartedIdent == mResumedIdent) {
-                // we are resuming into the activity where we previously hid the dialog, bring it
-                // back
-                if (DBG) Log.v(TAG, "******************* DIALOG: show");
-                mSearchDialog.show();
-                mVisible = true;
-            } else {
-                // resuming into some other activity; hide ourselves in case we ever come back
-                // so we can show ourselves quickly again
-                if (DBG) Log.v(TAG, "******************* DIALOG: hide");
-                mSearchDialog.hide();
-                mVisible = false;
-            }
-        }
-    }
-
-    /**
-     * Updates due to system dialogs being closed
-     * This must be called on the search UI thread.
-     */
-    void performClosingSystemDialogs(String reason) {
-        if (DBG) debug("performClosingSystemDialogs(): mStartedIdent="
-                + mStartedIdent + ", reason: " + reason);
-        if (!"search".equals(reason)) {
-            if (DBG) debug(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-            performStopSearch();
-        }
-    }
-
-    /**
-     * Must be called from the search UI thread.
-     */
-    void performOnConfigurationChanged() {
-        if (DBG) debug("performOnConfigurationChanged()");
-        mSearchDialog.onConfigurationChanged();
-    }
-
-    /**
-     * Called by {@link SearchDialog} when it goes away.
-     */
-    public void onDismiss(DialogInterface dialog) {
-        if (DBG) debug("onDismiss()");
-        mStartedIdent = 0;
-        mVisible = false;
-        callOnDismiss();
-
-        // we don't need the callback anymore, release it
-        mCallback = null;
-        unregisterBroadcastReceiver();
-    }
-
-
-    /**
-     * Called by {@link SearchDialog} when the user or activity cancels search.
-     * Whenever this method is called, {@link #onDismiss} is always called afterwards.
-     */
-    public void onCancel(DialogInterface dialog) {
-        if (DBG) debug("onCancel()");
-        callOnCancel();
-    }
-
-    private void callOnDismiss() {
-        if (mCallback == null) return;
-        try {
-            // should be safe to do on the search UI thread, since it's a oneway interface
-            mCallback.onDismiss();
-        } catch (DeadObjectException ex) {
-            // The process that hosted the callback has died, do nothing
-        } catch (RemoteException ex) {
-            Log.e(TAG, "onDismiss() failed: " + ex);
-        }
-    }
-
-    private void callOnCancel() {
-        if (mCallback != null) {
-            try {
-                // should be safe to do on the search UI thread, since it's a oneway interface
-                mCallback.onCancel();
-            } catch (DeadObjectException ex) {
-                // The process that hosted the callback has died, do nothing
-            } catch (RemoteException ex) {
-                Log.e(TAG, "onCancel() failed: " + ex);
-            }
-        }
-    }
-
-    private static void debug(String msg) {
-        Thread thread = Thread.currentThread();
-        Log.d(TAG, msg + " (" + thread.getName() + "-" + thread.getId() + ")");
-    }
-}
diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java
index f9a0b93..9953b56 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/core/java/android/server/search/SearchManagerService.java
@@ -51,10 +51,6 @@
     // Only accessed by ensureSearchablesCreated() and getSearchables()
     private Searchables mSearchables;
 
-    // This field is initialized in ensureSearchDialogCreated(), and then never modified.
-    // Only accessed by ensureSearchDialogCreated() and getSearchDialog()
-    private SearchDialogWrapper mSearchDialog;
-
     /**
      * Initializes the Search Manager service in the provided system context.
      * Only one instance of this object should be created!
@@ -63,23 +59,6 @@
      */
     public SearchManagerService(Context context)  {
         mContext = context;
-        // call initialize() after all pending actions on the main system thread have finished
-        new Handler().post(new Runnable() {
-            public void run() {
-                initialize();
-            }
-        });
-    }
-
-    /**
-     * Initializes the list of searchable activities and the search UI.
-     */
-    void initialize() {
-        try {
-            ActivityManagerNative.getDefault().registerActivityWatcher(
-                    mActivityWatcher);
-        } catch (RemoteException e) {
-        }
     }
 
     private synchronized void ensureSearchablesCreated() {
@@ -96,22 +75,11 @@
         mContext.registerReceiver(mPackageChangedReceiver, packageFilter);
     }
 
-    private synchronized void ensureSearchDialogCreated() {
-        if (mSearchDialog != null) return;
-
-        mSearchDialog = new SearchDialogWrapper(mContext);
-    }
-
     private synchronized Searchables getSearchables() {
         ensureSearchablesCreated();
         return mSearchables;
     }
 
-    private synchronized SearchDialogWrapper getSearchDialog() {
-        ensureSearchDialogCreated();
-        return mSearchDialog;
-    }
-
     /**
      * Refreshes the "searchables" list when packages are added/removed.
      */
@@ -124,8 +92,6 @@
                     Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
                     Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
                 if (DBG) Log.d(TAG, "Got " + action);
-                // Dismiss search dialog, since the search context may no longer be valid
-                getSearchDialog().stopSearch();
                 // Update list of searchable activities
                 getSearchables().buildSearchableList();
                 broadcastSearchablesChanged();
@@ -133,19 +99,6 @@
         }
     };
 
-    private IActivityWatcher.Stub mActivityWatcher = new IActivityWatcher.Stub() {
-        public void activityResuming(int activityId) throws RemoteException {
-            if (DBG) Log.i("foo", "********************** resuming: " + activityId);
-            if (mSearchDialog == null) return;
-            mSearchDialog.activityResuming(activityId);
-        }
-        public void closingSystemDialogs(String reason) {
-            if (DBG) Log.i("foo", "********************** closing dialogs: " + reason);
-            if (mSearchDialog == null) return;
-            mSearchDialog.closingSystemDialogs(reason);
-        }
-    };
-    
     /**
      * Informs all listeners that the list of searchables has been updated.
      */
@@ -214,62 +167,4 @@
         getSearchables().setDefaultWebSearch(component);
         broadcastSearchablesChanged();
     }
-
-    // Search UI API
-
-    /**
-     * Launches the search UI. Can be called from any thread.
-     *
-     * @see SearchManager#startSearch(String, boolean, ComponentName, Bundle, boolean)
-     */
-    public void startSearch(String initialQuery,
-            boolean selectInitialQuery,
-            ComponentName launchActivity,
-            Bundle appSearchData,
-            boolean globalSearch,
-            ISearchManagerCallback searchManagerCallback,
-            int ident) {
-        getSearchDialog().startSearch(initialQuery,
-                selectInitialQuery,
-                launchActivity,
-                appSearchData,
-                globalSearch,
-                searchManagerCallback,
-                ident,
-                false); // don't trigger
-    }
-
-    /**
-     * Launches the search UI and triggers the search, as if the user had clicked on the
-     * search button within the dialog.
-     *
-     * @see SearchManager#triggerSearch(String, android.content.ComponentName, android.os.Bundle)
-     */
-    public void triggerSearch(String query,
-            ComponentName launchActivity,
-            Bundle appSearchData,
-            ISearchManagerCallback searchManagerCallback,
-            int ident) {
-        getSearchDialog().startSearch(
-                query,
-                false,
-                launchActivity,
-                appSearchData,
-                false,
-                searchManagerCallback,
-                ident,
-                true); // triger search after launching
-    }
-
-    /**
-     * Cancels the search dialog. Can be called from any thread.
-     */
-    public void stopSearch() {
-        getSearchDialog().stopSearch();
-    }
-
-    public boolean isVisible() {
-        return mSearchDialog != null && mSearchDialog.isVisible();
-    }
-
 }
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 1337bed..3f1672a 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -177,18 +177,21 @@
 
     /**
      * Load a url from the network or the filesystem into the main frame.
-     * Following the same behaviour as Safari, javascript: URLs are not
-     * passed to the main frame, instead they are evaluated immediately.
+     * Following the same behaviour as Safari, javascript: URLs are not passed
+     * to the main frame, instead they are evaluated immediately.
      * @param url The url to load.
+     * @param extraHeaders The extra headers sent with this url. This should not
+     *            include the common headers like "user-agent". If it does, it
+     *            will be replaced by the intrinsic value of the WebView.
      */
-    public void loadUrl(String url) {
+    public void loadUrl(String url, Map<String, String> extraHeaders) {
         mLoadInitFromJava = true;
         if (URLUtil.isJavaScriptUrl(url)) {
             // strip off the scheme and evaluate the string
             stringByEvaluatingJavaScriptFromString(
                     url.substring("javascript:".length()));
         } else {
-            nativeLoadUrl(url);
+            nativeLoadUrl(url, extraHeaders);
         }
         mLoadInitFromJava = false;
     }
@@ -904,7 +907,7 @@
     /**
      * Returns false if the url is bad.
      */
-    private native void nativeLoadUrl(String url);
+    private native void nativeLoadUrl(String url, Map<String, String> headers);
 
     private native void nativePostUrl(String url, byte[] postData);
 
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 93e72ff..ecea55f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1376,6 +1376,22 @@
     }
 
     /**
+     * Load the given url with the extra headers.
+     * @param url The url of the resource to load.
+     * @param extraHeaders The extra headers sent with this url. This should not
+     *            include the common headers like "user-agent". If it does, it
+     *            will be replaced by the intrinsic value of the WebView.
+     */
+    public void loadUrl(String url, Map<String, String> extraHeaders) {
+        switchOutDrawHistory();
+        WebViewCore.GetUrlData arg = new WebViewCore.GetUrlData();
+        arg.mUrl = url;
+        arg.mExtraHeaders = extraHeaders;
+        mWebViewCore.sendMessage(EventHub.LOAD_URL, arg);
+        clearTextEntry();
+    }
+
+    /**
      * Load the given url.
      * @param url The url of the resource to load.
      */
@@ -1383,9 +1399,7 @@
         if (url == null) {
             return;
         }
-        switchOutDrawHistory();
-        mWebViewCore.sendMessage(EventHub.LOAD_URL, url);
-        clearTextEntry();
+        loadUrl(url, null);
     }
 
     /**
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 6700d71..1e21cb4 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -686,6 +686,11 @@
         int mY;
     }
 
+    static class GetUrlData {
+        String mUrl;
+        Map<String, String> mExtraHeaders;
+    }
+
     static class PostUrlData {
         String mUrl;
         byte[] mPostData;
@@ -958,9 +963,11 @@
                                     ((Float) msg.obj).floatValue(), msg.arg1);
                             break;
 
-                        case LOAD_URL:
-                            loadUrl((String) msg.obj);
+                        case LOAD_URL: {
+                            GetUrlData param = (GetUrlData) msg.obj;
+                            loadUrl(param.mUrl, param.mExtraHeaders);
                             break;
+                        }
 
                         case POST_URL: {
                             PostUrlData param = (PostUrlData) msg.obj;
@@ -1545,9 +1552,9 @@
         }
     }
 
-    private void loadUrl(String url) {
+    private void loadUrl(String url, Map<String, String> extraHeaders) {
         if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, " CORE loadUrl " + url);
-        mBrowserFrame.loadUrl(url);
+        mBrowserFrame.loadUrl(url, extraHeaders);
     }
 
     private void key(KeyEvent evt, boolean isDown) {
diff --git a/core/java/com/android/internal/app/IMediaContainerService.aidl b/core/java/com/android/internal/app/IMediaContainerService.aidl
new file mode 100755
index 0000000..726e28f
--- /dev/null
+++ b/core/java/com/android/internal/app/IMediaContainerService.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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 com.android.internal.app;
+
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+
+interface IMediaContainerService {
+    String copyResourceToContainer(in Uri packageURI,
+                String containerId,
+                String key, String resFileName);
+    boolean copyResource(in Uri packageURI,
+                in ParcelFileDescriptor outStream);
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/util/HanziToPinyin.java b/core/java/com/android/internal/util/HanziToPinyin.java
index 4368e98..6a4adaa 100644
--- a/core/java/com/android/internal/util/HanziToPinyin.java
+++ b/core/java/com/android/internal/util/HanziToPinyin.java
@@ -16,8 +16,6 @@
 
 package com.android.internal.util;
 
-import com.google.android.util.AbstractMessageParser.Token;
-
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -298,8 +296,10 @@
         };
 
     /** First and last Chinese character with known Pinyin according to zh collation */
-    private static final String FIRST_UNIHAN =  "\u5416";
-    private static final String LAST_UNIHAN =  "\u5497";
+    private static final String FIRST_PINYIN_UNIHAN =  "\u5416";
+    private static final String LAST_PINYIN_UNIHAN =  "\u5497";
+    /** The first Chinese character in Unicode block */
+    private static final char FIRST_UNIHAN = '\u3400';
     private static final Collator COLLATOR = Collator.getInstance(Locale.CHINA);
 
     private static HanziToPinyin sInstance;
@@ -311,10 +311,18 @@
          */
         public static final String SEPARATOR = " ";
 
-        public static final int ASCII = 1;
+        public static final int LATIN = 1;
         public static final int PINYIN = 2;
         public static final int UNKNOWN = 3;
 
+        public Token() {
+        }
+
+        public Token(int type, String source, String target) {
+            this.type = type;
+            this.source = source;
+            this.target = target;
+        }
         /**
          * Type of this token, ASCII, PINYIN or UNKNOWN.
          */
@@ -347,6 +355,7 @@
                     return sInstance;
                 }
             }
+            Log.w(TAG, "There is no Chinese collator, HanziToPinyin is disabled");
             sInstance = new HanziToPinyin(false);
             return sInstance;
         }
@@ -359,11 +368,15 @@
         int offset = -1;
         int cmp;
         if (character < 256) {
-            token.type = Token.ASCII;
+            token.type = Token.LATIN;
+            token.target = letter;
+            return token;
+        } else if (character < FIRST_UNIHAN) {
+            token.type = Token.UNKNOWN;
             token.target = letter;
             return token;
         } else {
-            cmp = COLLATOR.compare(letter, FIRST_UNIHAN);
+            cmp = COLLATOR.compare(letter, FIRST_PINYIN_UNIHAN);
             if (cmp < 0) {
                 token.type = Token.UNKNOWN;
                 token.target = letter;
@@ -372,7 +385,7 @@
                 token.type = Token.PINYIN;
                 offset = 0;
             } else {
-                cmp = COLLATOR.compare(letter, LAST_UNIHAN);
+                cmp = COLLATOR.compare(letter, LAST_PINYIN_UNIHAN);
                 if (cmp > 0) {
                     token.type = Token.UNKNOWN;
                     token.target = letter;
@@ -412,44 +425,71 @@
         return token;
     }
 
+    /**
+     * Convert the input to a array of tokens. The sequence of ASCII or Unknown
+     * characters without space will be put into a Token, One Hanzi character 
+     * which has pinyin will be treated as a Token.
+     * If these is no China collator, the empty token array is returned.
+     */
     public ArrayList<Token> get(final String input) {
-        if (!mHasChinaCollator || TextUtils.isEmpty(input)) {
-            return null;
-        }
-
         ArrayList<Token> tokens = new ArrayList<Token>();
-        Token currentToken;
-
+        if (!mHasChinaCollator || TextUtils.isEmpty(input)) {
+            // return empty tokens.
+            return tokens;
+        }
         final int inputLength = input.length();
-
-        currentToken = getToken(input.charAt(0));
-
-        for (int i = 1; i < inputLength; i++) {
+        final StringBuilder sb = new StringBuilder();
+        int tokenType = Token.LATIN;
+        // Go through the input, create a new token when
+        // a. Token type changed
+        // b. Get the Pinyin of current charater.
+        // c. current character is space.
+        for (int i = 0; i < inputLength; i++) {
             final char character = input.charAt(i);
-            Token token = getToken(character);
-
-            if (token.type != currentToken.type) {
-                currentToken.target = currentToken.target.trim();
-                tokens.add(currentToken);
-                currentToken = token;
+            if (character == ' ') {
+                if (sb.length() > 0) {
+                    addToken(sb, tokens, tokenType);
+                }
+            } else if (character < 256) {
+                if (tokenType != Token.LATIN && sb.length() > 0) {
+                    addToken(sb, tokens, tokenType);
+                }
+                tokenType = Token.LATIN;
+                sb.append(character);
+            } else if (character < FIRST_UNIHAN) {
+                if (tokenType != Token.UNKNOWN && sb.length() > 0) {
+                    addToken(sb, tokens, tokenType);
+                }
+                tokenType = Token.UNKNOWN;
+                sb.append(character);
             } else {
-                switch (token.type) {
-                    case Token.ASCII:
-                    case Token.UNKNOWN:
-                        currentToken.source += token.source;
-                        currentToken.target += token.target;
-                        break;
-                    case Token.PINYIN:
-                        currentToken.source += token.source;
-                        currentToken.target += " " + token.target;
-                        break;
+                Token t = getToken(character);
+                if (t.type == Token.PINYIN) {
+                    if (sb.length() > 0) {
+                        addToken(sb, tokens, tokenType);
+                    }
+                    tokens.add(t);
+                    tokenType = Token.PINYIN;
+                } else {
+                    if (tokenType != t.type && sb.length() > 0) {
+                        addToken(sb, tokens, tokenType);
+                    }
+                    tokenType = t.type;
+                    sb.append(character);
                 }
             }
         }
-
-        currentToken.target = currentToken.target.trim();
-        tokens.add(currentToken);
-
+        if (sb.length() > 0) {
+            addToken(sb, tokens, tokenType);
+        }
         return tokens;
     }
+
+    private void addToken(final StringBuilder sb, final ArrayList<Token> tokens,
+            final int tokenType) {
+        String str = sb.toString();
+        tokens.add(new Token(tokenType, str, str));
+        sb.setLength(0);
+    }
+
 }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 67a0bda..7fd58e8 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -99,6 +99,7 @@
 	android/graphics/Shader.cpp \
 	android/graphics/Typeface.cpp \
 	android/graphics/Xfermode.cpp \
+	android/graphics/YuvToJpegEncoder.cpp \
 	android_media_AudioRecord.cpp \
 	android_media_AudioSystem.cpp \
 	android_media_AudioTrack.cpp \
@@ -148,6 +149,7 @@
 	external/tremor/Tremor \
 	external/icu4c/i18n \
 	external/icu4c/common \
+	external/jpeg \
 	frameworks/opt/emoji
 
 LOCAL_SHARED_LIBRARIES := \
@@ -175,7 +177,8 @@
 	libicui18n \
 	libicudata \
 	libmedia \
-	libwpa_client
+	libwpa_client \
+	libjpeg
 
 ifeq ($(BOARD_HAVE_BLUETOOTH),true)
 LOCAL_C_INCLUDES += \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 8364838..fa1ee0d 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -64,6 +64,7 @@
 extern int register_android_graphics_Region(JNIEnv* env);
 extern int register_android_graphics_Shader(JNIEnv* env);
 extern int register_android_graphics_Typeface(JNIEnv* env);
+extern int register_android_graphics_YuvImage(JNIEnv* env);
 
 extern int register_com_google_android_gles_jni_EGLImpl(JNIEnv* env);
 extern int register_com_google_android_gles_jni_GLImpl(JNIEnv* env);
@@ -1215,6 +1216,7 @@
     REG_JNI(register_android_graphics_Shader),
     REG_JNI(register_android_graphics_Typeface),
     REG_JNI(register_android_graphics_Xfermode),
+    REG_JNI(register_android_graphics_YuvImage),
     REG_JNI(register_com_android_internal_graphics_NativeUtils),
 
     REG_JNI(register_android_database_CursorWindow),
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.cpp b/core/jni/android/graphics/YuvToJpegEncoder.cpp
new file mode 100644
index 0000000..ef5c9ae
--- /dev/null
+++ b/core/jni/android/graphics/YuvToJpegEncoder.cpp
@@ -0,0 +1,252 @@
+#include "CreateJavaOutputStreamAdaptor.h"
+#include "SkJpegUtility.h"
+#include "YuvToJpegEncoder.h"
+#include "ui/PixelFormat.h"
+
+#include <jni.h>
+
+YuvToJpegEncoder* YuvToJpegEncoder::create(int format, int* strides) {
+    // Only PIXEL_FORMAT_YCbCr_420_SP and PIXEl_FOMAT_YCbCr_422_I are supported
+    // for now.
+    if (format == android::PIXEL_FORMAT_YCbCr_420_SP) {
+        return new Yuv420SpToJpegEncoder(strides);
+    } else if (format == android::PIXEL_FORMAT_YCbCr_422_I) {
+        return new Yuv422IToJpegEncoder(strides);
+    } else {
+      return NULL;
+    }
+}
+
+YuvToJpegEncoder::YuvToJpegEncoder(int* strides) : fStrides(strides) {
+}
+
+bool YuvToJpegEncoder::encode(SkWStream* stream, void* inYuv, int width,
+        int height, int* offsets, int jpegQuality) {
+    jpeg_compress_struct    cinfo;
+    skjpeg_error_mgr        sk_err;
+    skjpeg_destination_mgr  sk_wstream(stream);
+
+    cinfo.err = jpeg_std_error(&sk_err);
+    sk_err.error_exit = skjpeg_error_exit;
+    if (setjmp(sk_err.fJmpBuf)) {
+        return false;
+    }
+    jpeg_create_compress(&cinfo);
+
+    cinfo.dest = &sk_wstream;
+
+    setJpegCompressStruct(&cinfo, width, height, jpegQuality);
+
+    jpeg_start_compress(&cinfo, TRUE);
+
+    compress(&cinfo, (uint8_t*) inYuv, offsets);
+
+    jpeg_finish_compress(&cinfo);
+
+    return true;
+}
+
+void YuvToJpegEncoder::setJpegCompressStruct(jpeg_compress_struct* cinfo,
+        int width, int height, int quality) {
+    jpeg_set_quality(cinfo, quality, TRUE);
+
+    cinfo->image_width = width;
+    cinfo->image_height = height;
+
+    cinfo->input_components = 3;
+    cinfo->in_color_space = JCS_YCbCr;
+    jpeg_set_defaults(cinfo);
+    jpeg_set_colorspace(cinfo, JCS_YCbCr);
+    cinfo->raw_data_in = TRUE;
+
+    cinfo->dct_method = JDCT_IFAST;
+
+    configSamplingFactors(cinfo);
+}
+
+///////////////////////////////////////////////////////////////////
+Yuv420SpToJpegEncoder::Yuv420SpToJpegEncoder(int* strides) :
+        YuvToJpegEncoder(strides) {
+    fNumPlanes = 2;
+}
+
+void Yuv420SpToJpegEncoder::compress(jpeg_compress_struct* cinfo,
+        uint8_t* yuv, int* offsets) {
+    SkDebugf("onFlyCompress");
+    JSAMPROW y[16];
+    JSAMPROW cb[8];
+    JSAMPROW cr[8];
+    JSAMPARRAY planes[3];
+    planes[0] = y;
+    planes[1] = cb;
+    planes[2] = cr;
+
+    int width = cinfo->image_width;
+    int height = cinfo->image_height;
+    uint8_t* yPlanar = yuv + offsets[0];
+    uint8_t* vuPlanar = yuv + offsets[1]; //width * height;
+    uint8_t* uRows = new uint8_t [8 * (width >> 1)];
+    uint8_t* vRows = new uint8_t [8 * (width >> 1)];
+
+
+    // process 16 lines of Y and 8 lines of U/V each time.
+    while (cinfo->next_scanline < cinfo->image_height) {
+        //deitnerleave u and v
+        deinterleave(vuPlanar, uRows, vRows, cinfo->next_scanline, width);
+
+        for (int i = 0; i < 16; i++) {
+            // y row
+            y[i] = yPlanar + (cinfo->next_scanline + i) * fStrides[0];
+
+            // construct u row and v row
+            if ((i & 1) == 0) {
+                // height and width are both halved because of downsampling
+                int offset = (i >> 1) * (width >> 1);
+                cb[i/2] = uRows + offset;
+                cr[i/2] = vRows + offset;
+            }
+          }
+        jpeg_write_raw_data(cinfo, planes, 16);
+    }
+    delete [] uRows;
+    delete [] vRows;
+
+}
+
+void Yuv420SpToJpegEncoder::deinterleave(uint8_t* vuPlanar, uint8_t* uRows,
+        uint8_t* vRows, int rowIndex, int width) {
+    for (int row = 0; row < 8; ++row) {
+        int offset = ((rowIndex >> 1) + row) * fStrides[1];
+        uint8_t* vu = vuPlanar + offset;
+        for (int i = 0; i < (width >> 1); ++i) {
+            int index = row * (width >> 1) + i;
+            uRows[index] = vu[1];
+            vRows[index] = vu[0];
+            vu += 2;
+        }
+    }
+}
+
+void Yuv420SpToJpegEncoder::configSamplingFactors(jpeg_compress_struct* cinfo) {
+    // cb and cr are horizontally downsampled and vertically downsampled as well.
+    cinfo->comp_info[0].h_samp_factor = 2;
+    cinfo->comp_info[0].v_samp_factor = 2;
+    cinfo->comp_info[1].h_samp_factor = 1;
+    cinfo->comp_info[1].v_samp_factor = 1;
+    cinfo->comp_info[2].h_samp_factor = 1;
+    cinfo->comp_info[2].v_samp_factor = 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+Yuv422IToJpegEncoder::Yuv422IToJpegEncoder(int* strides) :
+        YuvToJpegEncoder(strides) {
+    fNumPlanes = 1;
+}
+
+void Yuv422IToJpegEncoder::compress(jpeg_compress_struct* cinfo,
+        uint8_t* yuv, int* offsets) {
+    SkDebugf("onFlyCompress_422");
+    JSAMPROW y[16];
+    JSAMPROW cb[16];
+    JSAMPROW cr[16];
+    JSAMPARRAY planes[3];
+    planes[0] = y;
+    planes[1] = cb;
+    planes[2] = cr;
+
+    int width = cinfo->image_width;
+    int height = cinfo->image_height;
+    uint8_t* yRows = new uint8_t [16 * width];
+    uint8_t* uRows = new uint8_t [16 * (width >> 1)];
+    uint8_t* vRows = new uint8_t [16 * (width >> 1)];
+
+    uint8_t* yuvOffset = yuv + offsets[0];
+
+    // process 16 lines of Y and 16 lines of U/V each time.
+    while (cinfo->next_scanline < cinfo->image_height) {
+        deinterleave(yuvOffset, yRows, uRows, vRows, cinfo->next_scanline, width, height);
+
+        for (int i = 0; i < 16; i++) {
+            // y row
+            y[i] = yRows + i * width;
+
+            // construct u row and v row
+            // width is halved because of downsampling
+            int offset = i * (width >> 1);
+            cb[i] = uRows + offset;
+            cr[i] = vRows + offset;
+        }
+
+        jpeg_write_raw_data(cinfo, planes, 16);
+    }
+    delete [] yRows;
+    delete [] uRows;
+    delete [] vRows;
+}
+
+
+void Yuv422IToJpegEncoder::deinterleave(uint8_t* yuv, uint8_t* yRows, uint8_t* uRows,
+        uint8_t* vRows, int rowIndex, int width, int height) {
+    for (int row = 0; row < 16; ++row) {
+        uint8_t* yuvSeg = yuv + (rowIndex + row) * fStrides[0];
+        for (int i = 0; i < (width >> 1); ++i) {
+            int indexY = row * width + (i << 1);
+            int indexU = row * (width >> 1) + i;
+            yRows[indexY] = yuvSeg[0];
+            yRows[indexY + 1] = yuvSeg[2];
+            uRows[indexU] = yuvSeg[1];
+            vRows[indexU] = yuvSeg[3];
+            yuvSeg += 4;
+        }
+    }
+}
+
+void Yuv422IToJpegEncoder::configSamplingFactors(jpeg_compress_struct* cinfo) {
+    // cb and cr are horizontally downsampled and vertically downsampled as well.
+    cinfo->comp_info[0].h_samp_factor = 2;
+    cinfo->comp_info[0].v_samp_factor = 2;
+    cinfo->comp_info[1].h_samp_factor = 1;
+    cinfo->comp_info[1].v_samp_factor = 2;
+    cinfo->comp_info[2].h_samp_factor = 1;
+    cinfo->comp_info[2].v_samp_factor = 2;
+}
+///////////////////////////////////////////////////////////////////////////////
+
+static jboolean YuvImage_compressToJpeg(JNIEnv* env, jobject, jbyteArray inYuv,
+        int format, int width, int height, jintArray offsets,
+        jintArray strides, int jpegQuality, jobject jstream,
+        jbyteArray jstorage) {
+    jbyte* yuv = env->GetByteArrayElements(inYuv, NULL);
+    SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
+
+    jint* imgOffsets = env->GetIntArrayElements(offsets, NULL);
+    jint* imgStrides = env->GetIntArrayElements(strides, NULL);
+    YuvToJpegEncoder* encoder = YuvToJpegEncoder::create(format, imgStrides);
+    if (encoder == NULL) {
+        return false;
+    }
+    encoder->encode(strm, yuv, width, height, imgOffsets, jpegQuality);
+
+    delete encoder;
+    env->ReleaseByteArrayElements(inYuv, yuv, 0);
+    env->ReleaseIntArrayElements(offsets, imgOffsets, 0);
+    env->ReleaseIntArrayElements(strides, imgStrides, 0);
+    return true;
+}
+///////////////////////////////////////////////////////////////////////////////
+
+#include <android_runtime/AndroidRuntime.h>
+
+static JNINativeMethod gYuvImageMethods[] = {
+    {   "nativeCompressToJpeg",  "([BIII[I[IILjava/io/OutputStream;[B)Z",
+        (void*)YuvImage_compressToJpeg }
+};
+
+#define kClassPathName  "android/graphics/YuvImage"
+
+int register_android_graphics_YuvImage(JNIEnv* env);
+int register_android_graphics_YuvImage(JNIEnv* env)
+{
+    return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
+            gYuvImageMethods, SK_ARRAY_COUNT(gYuvImageMethods));
+}
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.h b/core/jni/android/graphics/YuvToJpegEncoder.h
new file mode 100644
index 0000000..97106ce
--- /dev/null
+++ b/core/jni/android/graphics/YuvToJpegEncoder.h
@@ -0,0 +1,74 @@
+#ifndef YuvToJpegEncoder_DEFINED
+#define YuvToJpegEncoder_DEFINED
+
+#include "SkTypes.h"
+#include "SkStream.h"
+extern "C" {
+    #include "jpeglib.h"
+    #include "jerror.h"
+}
+
+class YuvToJpegEncoder {
+public:
+    /** Create an encoder based on the YUV format.
+     *
+     *  @param pixelFormat The yuv pixel format as defined in ui/PixelFormat.h.
+     *  @param strides The number of row bytes in each image plane.
+     *  @return an encoder based on the pixelFormat.
+     */
+    static YuvToJpegEncoder* create(int pixelFormat, int* strides);
+
+    YuvToJpegEncoder(int* strides);
+
+    /** Encode YUV data to jpeg,  which is output to a stream.
+     *
+     *  @param stream The jpeg output stream.
+     *  @param inYuv The input yuv data.
+     *  @param width Width of the the Yuv data in terms of pixels.
+     *  @param height Height of the Yuv data in terms of pixels.
+     *  @param offsets The offsets in each image plane with respect to inYuv.
+     *  @param jpegQuality Picture quality in [0, 100].
+     *  @return true if successfully compressed the stream.
+     */
+    bool encode(SkWStream* stream,  void* inYuv, int width,
+           int height, int* offsets, int jpegQuality);
+
+    virtual ~YuvToJpegEncoder() {}
+
+protected:
+    int fNumPlanes;
+    int* fStrides;
+    void setJpegCompressStruct(jpeg_compress_struct* cinfo, int width,
+            int height, int quality);
+    virtual void configSamplingFactors(jpeg_compress_struct* cinfo) = 0;
+    virtual void compress(jpeg_compress_struct* cinfo,
+            uint8_t* yuv, int* offsets) = 0;
+};
+
+class Yuv420SpToJpegEncoder : public YuvToJpegEncoder {
+public:
+     Yuv420SpToJpegEncoder(int* strides);
+     virtual ~Yuv420SpToJpegEncoder() {}
+
+private:
+     void configSamplingFactors(jpeg_compress_struct* cinfo);
+     void deinterleaveYuv(uint8_t* yuv, int width, int height,
+            uint8_t*& yPlanar, uint8_t*& uPlanar, uint8_t*& vPlanar);
+     void deinterleave(uint8_t* vuPlanar, uint8_t* uRows, uint8_t* vRows,
+             int rowIndex, int width);
+     void compress(jpeg_compress_struct* cinfo, uint8_t* yuv, int* offsets);
+};
+
+class Yuv422IToJpegEncoder : public YuvToJpegEncoder {
+public:
+    Yuv422IToJpegEncoder(int* strides);
+    virtual ~Yuv422IToJpegEncoder() {}
+
+private:
+    void configSamplingFactors(jpeg_compress_struct* cinfo);
+    void compress(jpeg_compress_struct* cinfo, uint8_t* yuv, int* offsets);
+    void deinterleave(uint8_t* yuv, uint8_t* yRows, uint8_t* uRows,
+            uint8_t* vRows, int rowIndex, int width, int height);
+};
+
+#endif
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 64ee4f0..1a5987c 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -546,6 +546,18 @@
     }
 }
 
+static void android_hardware_Camera_setDisplayOrientation(JNIEnv *env, jobject thiz,
+        jint value)
+{
+    LOGV("setDisplayOrientation");
+    sp<Camera> camera = get_native_camera(env, thiz, NULL);
+    if (camera == 0) return;
+
+    if (camera->sendCommand(CAMERA_CMD_SET_DISPLAY_ORIENTATION, value, 0) != NO_ERROR) {
+        jniThrowException(env, "java/lang/RuntimeException", "set display orientation failed");
+    }
+}
+
 //-------------------------------------------------
 
 static JNINativeMethod camMethods[] = {
@@ -603,6 +615,9 @@
   { "stopSmoothZoom",
     "()V",
     (void *)android_hardware_Camera_stopSmoothZoom },
+  { "setDisplayOrientation",
+    "(I)V",
+    (void *)android_hardware_Camera_setDisplayOrientation },
 };
 
 struct field {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d81476a..54e15a5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -700,6 +700,46 @@
         android:label="@string/permlab_mount_format_filesystems"
         android:description="@string/permdesc_mount_format_filesystems" />
 
+    <!-- Allows access to ASEC non-destructive API calls
+         @hide  -->
+    <permission android:name="android.permission.ASEC_ACCESS"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="dangerous"
+        android:label="@string/permlab_asec_access"
+        android:description="@string/permdesc_asec_access" />
+
+    <!-- Allows creation of ASEC volumes
+         @hide  -->
+    <permission android:name="android.permission.ASEC_CREATE"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="dangerous"
+        android:label="@string/permlab_asec_create"
+        android:description="@string/permdesc_asec_create" />
+
+    <!-- Allows destruction of ASEC volumes
+         @hide  -->
+    <permission android:name="android.permission.ASEC_DESTROY"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="dangerous"
+        android:label="@string/permlab_asec_destroy"
+        android:description="@string/permdesc_asec_destroy" />
+
+    <!-- Allows mount / unmount of ASEC volumes
+         @hide  -->
+    <permission android:name="android.permission.ASEC_MOUNT_UNMOUNT"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="dangerous"
+        android:label="@string/permlab_asec_mount_unmount"
+        android:description="@string/permdesc_asec_mount_unmount" />
+
+    <!-- Allows rename of ASEC volumes
+         @hide  -->
+    <permission android:name="android.permission.ASEC_RENAME"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="dangerous"
+        android:label="@string/permlab_asec_rename"
+        android:description="@string/permdesc_asec_rename" />
+
     <!-- Allows applications to disable the keyguard -->
     <permission android:name="android.permission.DISABLE_KEYGUARD"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
@@ -1162,6 +1202,16 @@
         android:description="@string/permdesc_cache_filesystem"
         android:protectionLevel="signatureOrSystem" />
 
+    <!-- Must be required by default container service so that only
+         the system can bind to it and use it to copy
+         protected data to secure containers or files
+         accessible to the system.
+         @hide -->
+    <permission android:name="android.permission.COPY_PROTECTED_DATA"
+        android:label="@string/permlab_copyProtectedData"
+        android:description="@string/permlab_copyProtectedData"
+        android:protectionLevel="signature" />
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0ef07ff..259398f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -877,6 +877,31 @@
     <string name="permdesc_mount_format_filesystems">Allows the application to format removable storage.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_asec_access">get information on secure storage</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_asec_access">Allows the application to get information on secure storage.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_asec_create">create secure storage</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_asec_create">Allows the application to create secure storage.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_asec_destroy">destroy secure storage</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_asec_destroy">Allows the application to destroy secure storage.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_asec_mount_unmount">mount / unmount secure storage</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_asec_mount_unmount">Allows the application to mount / unmount secure storage.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_asec_rename">rename secure storage</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_asec_rename">Allows the application to rename secure storage.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_vibrate">control vibrator</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_vibrate">Allows the application to control
@@ -1167,10 +1192,10 @@
     <!-- Title of policy access to watch user login attempts -->
     <string name="policylab_watchLogin">Watch login attempts</string>
     <!-- Description of policy access to watch user login attempts -->
-    <string name="policydesc_watchLogin">Monitor attempts to login to
-        the device, in particular to respond to failed login attempts.</string>
+    <string name="policydesc_watchLogin">Monitor failed attempts to login to
+        the device, to perform some action.</string>
     <!-- Title of policy access to reset user's password -->
-    <string name="policylab_resetPassword">Reset your password</string>
+    <string name="policylab_resetPassword">Reset password</string>
     <!-- Description of policy access to reset user's password -->
     <string name="policydesc_resetPassword">Force your password
         to a new value, requiring the administrator give it to you
@@ -1184,12 +1209,12 @@
     <string name="policylab_forceLock">Force lock</string>
     <!-- Description of policy access to limiting the user's password choices -->
     <string name="policydesc_forceLock">Force the device to immediately lock,
-        requiring that its password is re-entered.</string>
+        requiring that you re-enter its password.</string>
     <!-- Title of policy access to wipe the user's data -->
     <string name="policylab_wipeData">Erase all data</string>
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData">Perform a factory reset, deleting
-        all of your data without any confirmation from you.</string>
+        all of your data without any confirmation.</string>
 
     <!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
     <!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
@@ -2077,6 +2102,12 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_pkgUsageStats">Allows the modification of collected component usage statistics. Not for use by normal applications.</string>
 
+    <!-- permission attributes related to default container service -->
+    <!-- Title of an application permission that lets an application use default container service. -->
+    <string name="permlab_copyProtectedData">Allows to invoke default container service to copy content. Not for use by normal applications.</string>
+    <!-- Description of an application permission,  used to invoke default container service to copy content. -->
+    <string name="permdesc_copyProtectedData">Allows to invoke default container service to copy content. Not for use by normal applications.</string>
+
     <!-- Shown in the tutorial for tap twice for zoom control. -->
     <string name="tutorial_double_tap_to_zoom_message_short">Tap twice for zoom control</string>
 
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
new file mode 100644
index 0000000..77c176f
--- /dev/null
+++ b/core/tests/coretests/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_PACKAGE_NAME := FrameworksCoreTests
+
+include $(BUILD_PACKAGE)
+
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
new file mode 100644
index 0000000..674bda7
--- /dev/null
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.frameworks.coretests">
+    <uses-permission android:name="android.permission.RECEIVE_SMS"/>
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.READ_CONTACTS" />
+    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
+    <uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
+    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+
+    <!-- location test permissions -->
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>
+    <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+    
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <activity android:name="StubTestBrowserActivity" android:label="Stubbed Test Browser">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.FOR_TESTS_ONLY"/>
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.test.TestBrowserTests" android:label="Test Browser Tests">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.UNIT_TEST"/>
+            </intent-filter>
+        </activity>
+    </application>
+
+    <instrumentation
+    	android:name="android.test.InstrumentationTestRunner"
+    	android:targetPackage="com.android.frameworks.coretests"
+    	android:label="Frameworks Core Tests" />
+</manifest>
diff --git a/tests/CoreTests/android/core/AtParserTest.java b/core/tests/coretests/src/android/bluetooth/AtParserTest.java
similarity index 99%
rename from tests/CoreTests/android/core/AtParserTest.java
rename to core/tests/coretests/src/android/bluetooth/AtParserTest.java
index 09cb6e9..c5aa52b 100644
--- a/tests/CoreTests/android/core/AtParserTest.java
+++ b/core/tests/coretests/src/android/bluetooth/AtParserTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.core;
+package android.bluetooth;
 
 import android.bluetooth.AtCommandHandler;
 import android.bluetooth.AtCommandResult;
diff --git a/tests/CoreTests/android/content/ObserverNodeTest.java b/core/tests/coretests/src/android/content/ObserverNodeTest.java
similarity index 100%
rename from tests/CoreTests/android/content/ObserverNodeTest.java
rename to core/tests/coretests/src/android/content/ObserverNodeTest.java
diff --git a/tests/CoreTests/android/content/SyncStorageEngineTest.java b/core/tests/coretests/src/android/content/SyncStorageEngineTest.java
similarity index 100%
rename from tests/CoreTests/android/content/SyncStorageEngineTest.java
rename to core/tests/coretests/src/android/content/SyncStorageEngineTest.java
diff --git a/tests/CoreTests/android/database/MatrixCursorTest.java b/core/tests/coretests/src/android/database/MatrixCursorTest.java
similarity index 100%
rename from tests/CoreTests/android/database/MatrixCursorTest.java
rename to core/tests/coretests/src/android/database/MatrixCursorTest.java
diff --git a/tests/CoreTests/android/core/AbstractJDBCDriverTest.java b/core/tests/coretests/src/android/database/sqlite/AbstractJDBCDriverTest.java
similarity index 100%
rename from tests/CoreTests/android/core/AbstractJDBCDriverTest.java
rename to core/tests/coretests/src/android/database/sqlite/AbstractJDBCDriverTest.java
diff --git a/tests/CoreTests/android/core/SQLiteJDBCDriverTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteJDBCDriverTest.java
similarity index 100%
rename from tests/CoreTests/android/core/SQLiteJDBCDriverTest.java
rename to core/tests/coretests/src/android/database/sqlite/SQLiteJDBCDriverTest.java
diff --git a/tests/CoreTests/android/core/RecurrenceSetTest.java b/core/tests/coretests/src/android/pim/RecurrenceSetTest.java
similarity index 98%
rename from tests/CoreTests/android/core/RecurrenceSetTest.java
rename to core/tests/coretests/src/android/pim/RecurrenceSetTest.java
index cee324c..64cd6c4 100644
--- a/tests/CoreTests/android/core/RecurrenceSetTest.java
+++ b/core/tests/coretests/src/android/pim/RecurrenceSetTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.core;
+package android.pim;
 
 import android.content.ContentValues;
 import android.pim.ICalendar;
diff --git a/tests/CoreTests/android/util/DayOfMonthCursorTest.java b/core/tests/coretests/src/android/util/DayOfMonthCursorTest.java
similarity index 100%
rename from tests/CoreTests/android/util/DayOfMonthCursorTest.java
rename to core/tests/coretests/src/android/util/DayOfMonthCursorTest.java
diff --git a/tests/CoreTests/android/util/FloatMathTest.java b/core/tests/coretests/src/android/util/FloatMathTest.java
similarity index 100%
rename from tests/CoreTests/android/util/FloatMathTest.java
rename to core/tests/coretests/src/android/util/FloatMathTest.java
diff --git a/tests/CoreTests/android/util/MonthDisplayHelperTest.java b/core/tests/coretests/src/android/util/MonthDisplayHelperTest.java
similarity index 100%
rename from tests/CoreTests/android/util/MonthDisplayHelperTest.java
rename to core/tests/coretests/src/android/util/MonthDisplayHelperTest.java
diff --git a/tests/CoreTests/android/util/StateSetTest.java b/core/tests/coretests/src/android/util/StateSetTest.java
similarity index 100%
rename from tests/CoreTests/android/util/StateSetTest.java
rename to core/tests/coretests/src/android/util/StateSetTest.java
diff --git a/tests/CoreTests/android/view/FocusFinderTest.java b/core/tests/coretests/src/android/view/FocusFinderTest.java
similarity index 100%
rename from tests/CoreTests/android/view/FocusFinderTest.java
rename to core/tests/coretests/src/android/view/FocusFinderTest.java
diff --git a/tests/CoreTests/android/view/ViewGroupAttributesTest.java b/core/tests/coretests/src/android/view/ViewGroupAttributesTest.java
similarity index 100%
rename from tests/CoreTests/android/view/ViewGroupAttributesTest.java
rename to core/tests/coretests/src/android/view/ViewGroupAttributesTest.java
diff --git a/tests/CoreTests/android/webkit/UrlInterceptRegistryTest.java b/core/tests/coretests/src/android/webkit/UrlInterceptRegistryTest.java
similarity index 100%
rename from tests/CoreTests/android/webkit/UrlInterceptRegistryTest.java
rename to core/tests/coretests/src/android/webkit/UrlInterceptRegistryTest.java
diff --git a/tests/CoreTests/com/android/internal/util/PredicatesTest.java b/core/tests/coretests/src/com/android/internal/util/PredicatesTest.java
similarity index 100%
rename from tests/CoreTests/com/android/internal/util/PredicatesTest.java
rename to core/tests/coretests/src/com/android/internal/util/PredicatesTest.java
diff --git a/graphics/java/android/graphics/YuvImage.java b/graphics/java/android/graphics/YuvImage.java
new file mode 100644
index 0000000..4a3bd47
--- /dev/null
+++ b/graphics/java/android/graphics/YuvImage.java
@@ -0,0 +1,171 @@
+/*
+ * 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.graphics;
+
+import java.io.OutputStream;
+
+/**
+ * @hide pending API council approval
+ *
+ * YuvImage contains YUV data and provides a method that compresses a region of
+ * the YUV data to a Jpeg. The YUV data should be provided as a single byte
+ * array irrespective of the number of image planes in it. The stride of each
+ * image plane should be provided as well.
+ *
+ * To compress a rectangle region in the YUV data, users have to specify a
+ * region by width, height and offsets, where each image plane has a
+ * corresponding offset. All offsets are measured as a displacement in bytes
+ * from yuv[0], where yuv[0] is the beginning of the yuv data.
+ */
+public class YuvImage {
+
+    /**
+     * Number of bytes of temp storage we use for communicating between the
+     * native compressor and the java OutputStream.
+     */
+    private final static int WORKING_COMPRESS_STORAGE = 4096;
+
+   /**
+     * The YUV format as defined in {@link PixelFormat}.
+     */
+    private int mFormat;
+
+    /**
+     * The raw YUV data.
+     * In the case of more than one image plane, the image planes must be
+     * concatenated into a single byte array.
+     */
+    private byte[] mData;
+
+    /**
+     * The number of row bytes in each image plane.
+     */
+    private int[] mStrides;
+
+    /**
+     * Construct an YuvImage.
+     *
+     * @param yuv The YUV data. In the case of more than one image plane, all the planes must be
+     *            concatenated into a single byte array.
+     * @param format The YUV data format as defined in {@link PixelFormat}.
+     * @param strides Row bytes of each image plane.
+     */
+    public YuvImage(byte[] yuv, int format, int[] strides) {
+        if ((yuv == null) || (strides == null)) {
+            throw new IllegalArgumentException(
+                    "yuv or strides cannot be null");
+        }
+        mData = yuv;
+        mFormat = format;
+        mStrides = strides;
+    }
+
+    /**
+     * Compress a rectangle region in the YuvImage to a jpeg.
+     * Only PixelFormat.YCbCr_420_SP and PixelFormat.YCbCr_422_I
+     * are supported for now.
+     *
+     * @param width The width of the rectangle region.
+     * @param height The height of the rectangle region.
+     * @param offsets The offsets of the rectangle region in each image plane.
+     *                The offsets are measured as a displacement in bytes from
+     *                yuv[0], where yuv[0] is the beginning of the yuv data.
+     * @param quality  Hint to the compressor, 0-100. 0 meaning compress for
+     *                 small size, 100 meaning compress for max quality.
+     * @param stream   The outputstream to write the compressed data.
+     *
+     * @return true if successfully compressed to the specified stream.
+     *
+     */
+    public boolean compressToJpeg(int width, int height, int[] offsets, int quality,
+            OutputStream stream) {
+        if (!validate(mFormat, width, height, offsets)) {
+            return false;
+        }
+
+        if (quality < 0 || quality > 100) {
+            throw new IllegalArgumentException("quality must be 0..100");
+        }
+
+        if (stream == null) {
+            throw new NullPointerException();
+        }
+
+        return nativeCompressToJpeg(mData, mFormat, width, height, offsets,
+                mStrides, quality, stream, new byte[WORKING_COMPRESS_STORAGE]);
+    }
+
+    /**
+     * @return the YUV data.
+     */
+    public byte[] getYuvData() {
+        return mData;
+    }
+
+    /**
+     * @return the YUV format as defined in {@link PixelFormat}.
+     */
+    public int getYuvFormat() {
+        return mFormat;
+    }
+
+    /**
+     * @return the number of row bytes in each image plane.
+     */
+    public int[] getStrides() {
+        return mStrides;
+    }
+
+    protected boolean validate(int format, int width, int height, int[] offsets) {
+        if (format != PixelFormat.YCbCr_420_SP &&
+                format != PixelFormat.YCbCr_422_I) {
+            throw new IllegalArgumentException(
+                    "only support PixelFormat.YCbCr_420_SP " +
+                    "and PixelFormat.YCbCr_422_I for now");
+        }
+
+        if (offsets.length != mStrides.length) {
+            throw new IllegalArgumentException(
+                    "the number of image planes are mismatched");
+        }
+
+        if (width <= 0  || height <= 0) {
+            throw new IllegalArgumentException(
+                    "width and height must large than 0");
+        }
+
+        int requiredSize;
+        if (format == PixelFormat.YCbCr_420_SP) {
+            requiredSize = height * mStrides[0] +(height >> 1) * mStrides[1];
+        } else {
+            requiredSize = height * mStrides[0];
+        }
+
+        if (requiredSize > mData.length) {
+            throw new IllegalArgumentException(
+                    "width or/and height is larger than the yuv data");
+        }
+
+        return true;
+    }
+
+    //////////// native methods
+
+    private static native boolean nativeCompressToJpeg(byte[] oriYuv,
+            int format, int width, int height, int[] offsets, int[] strides,
+            int quality, OutputStream stream, byte[] tempStorage);
+}
diff --git a/include/media/stagefright/CachingDataSource.h b/include/media/stagefright/CachingDataSource.h
index b0fc4b2..30b7ad9 100644
--- a/include/media/stagefright/CachingDataSource.h
+++ b/include/media/stagefright/CachingDataSource.h
@@ -33,6 +33,8 @@
 
     virtual ssize_t readAt(off_t offset, void *data, size_t size);
 
+    virtual uint32_t flags();
+
 protected:
     virtual ~CachingDataSource();
 
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index f88666a..0c0ace0 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -31,6 +31,10 @@
 
 class DataSource : public RefBase {
 public:
+    enum Flags {
+        kWantsPrefetching = 1,
+    };
+
     static sp<DataSource> CreateFromURI(const char *uri);
 
     DataSource() {}
@@ -45,6 +49,10 @@
     // May return ERROR_UNSUPPORTED.
     virtual status_t getSize(off_t *size);
 
+    virtual uint32_t flags() {
+        return 0;
+    }
+
     ////////////////////////////////////////////////////////////////////////////
 
     bool sniff(String8 *mimeType, float *confidence);
diff --git a/include/media/stagefright/HTTPDataSource.h b/include/media/stagefright/HTTPDataSource.h
index d5dc9e6..3075f1c 100644
--- a/include/media/stagefright/HTTPDataSource.h
+++ b/include/media/stagefright/HTTPDataSource.h
@@ -33,6 +33,10 @@
 
     virtual ssize_t readAt(off_t offset, void *data, size_t size);
 
+    virtual uint32_t flags() {
+        return kWantsPrefetching;
+    }
+
 protected:
     virtual ~HTTPDataSource();
 
@@ -52,6 +56,8 @@
 
     status_t mInitCheck;
 
+    ssize_t sendRangeRequest(size_t offset);
+
     HTTPDataSource(const HTTPDataSource &);
     HTTPDataSource &operator=(const HTTPDataSource &);
 };
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
index 5219772..c506fb8 100644
--- a/include/ui/Camera.h
+++ b/include/ui/Camera.h
@@ -82,6 +82,7 @@
 enum {
     CAMERA_CMD_START_SMOOTH_ZOOM     = 1,
     CAMERA_CMD_STOP_SMOOTH_ZOOM      = 2,
+    CAMERA_CMD_SET_DISPLAY_ORIENTATION = 3,
 };
 
 // camera fatal errors
@@ -209,4 +210,3 @@
 }; // namespace android
 
 #endif
-
diff --git a/include/ui/CameraParameters.h b/include/ui/CameraParameters.h
index a5ea133..cae0676 100644
--- a/include/ui/CameraParameters.h
+++ b/include/ui/CameraParameters.h
@@ -29,12 +29,6 @@
     CameraParameters(const String8 &params) { unflatten(params); }
     ~CameraParameters();
 
-    enum {
-        CAMERA_ORIENTATION_UNKNOWN = 0,
-        CAMERA_ORIENTATION_PORTRAIT = 1,
-        CAMERA_ORIENTATION_LANDSCAPE = 2,
-    };
-
     String8 flatten() const;
     void unflatten(const String8 &params);
 
@@ -63,9 +57,6 @@
     void setPictureFormat(const char *format);
     const char *getPictureFormat() const;
 
-    int getOrientation() const;
-    void setOrientation(int orientation);
-
     void dump() const;
     status_t dump(int fd, const Vector<String16>& args) const;
 
diff --git a/libs/ui/CameraParameters.cpp b/libs/ui/CameraParameters.cpp
index 2e0409b..a94f6b9 100644
--- a/libs/ui/CameraParameters.cpp
+++ b/libs/ui/CameraParameters.cpp
@@ -121,9 +121,6 @@
 const char CameraParameters::FOCUS_MODE_MACRO[] = "macro";
 const char CameraParameters::FOCUS_MODE_FIXED[] = "fixed";
 
-static const char* portrait = "portrait";
-static const char* landscape = "landscape";
-
 CameraParameters::CameraParameters()
                 : mMap()
 {
@@ -282,23 +279,6 @@
     set(KEY_PREVIEW_FORMAT, format);
 }
 
-int CameraParameters::getOrientation() const
-{
-    const char* orientation = get("orientation");
-    if (orientation && !strcmp(orientation, portrait))
-        return CAMERA_ORIENTATION_PORTRAIT;
-    return CAMERA_ORIENTATION_LANDSCAPE;
-}
-
-void CameraParameters::setOrientation(int orientation)
-{
-    if (orientation == CAMERA_ORIENTATION_PORTRAIT) {
-        set("orientation", portrait);
-    } else {
-        set("orientation", landscape);
-    }
-}
-
 const char *CameraParameters::getPreviewFormat() const
 {
     return get(KEY_PREVIEW_FORMAT);
diff --git a/location/tests/locationtests/Android.mk b/location/tests/locationtests/Android.mk
new file mode 100644
index 0000000..902cd96
--- /dev/null
+++ b/location/tests/locationtests/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_PACKAGE_NAME := FrameworksLocationTests
+
+include $(BUILD_PACKAGE)
+
diff --git a/location/tests/locationtests/AndroidManifest.xml b/location/tests/locationtests/AndroidManifest.xml
new file mode 100644
index 0000000..1d9df0f
--- /dev/null
+++ b/location/tests/locationtests/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.frameworks.locationtests">
+
+    <!-- location test permissions -->
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>
+    <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+    
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+    	android:name="android.test.InstrumentationTestRunner"
+    	android:targetPackage="com.android.frameworks.locationtests"
+    	android:label="Frameworks Location Tests" />
+</manifest>
diff --git a/tests/CoreTests/android/location/LocationTest.java b/location/tests/locationtests/src/android/location/LocationTest.java
similarity index 100%
rename from tests/CoreTests/android/location/LocationTest.java
rename to location/tests/locationtests/src/android/location/LocationTest.java
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index ca6230f..1d82e32 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -1,6 +1,10 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
+ifneq ($(BUILD_WITHOUT_PV),true)
+include external/opencore/Config.mk
+endif
+
 LOCAL_SRC_FILES:= \
     android_media_MediaPlayer.cpp \
     android_media_MediaRecorder.cpp \
@@ -19,6 +23,7 @@
     libcutils
 
 ifneq ($(BUILD_WITHOUT_PV),true)
+
 LOCAL_SRC_FILES += \
     android_media_AmrInputStream.cpp
 
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 3813907..dbb52c6 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -31,6 +31,7 @@
         MPEG4Extractor.cpp        \
         MPEG4Writer.cpp           \
         MediaExtractor.cpp        \
+        Prefetcher.cpp            \
         SampleIterator.cpp        \
         SampleTable.cpp           \
         ShoutcastSource.cpp       \
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index f6cd46a..42b9acc 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -19,6 +19,7 @@
 #include <utils/Log.h>
 
 #include "include/AwesomePlayer.h"
+#include "include/Prefetcher.h"
 #include "include/SoftwareRenderer.h"
 
 #include <binder/IPCThreadState.h>
@@ -118,6 +119,8 @@
     mVideoEventPending = false;
     mStreamDoneEvent = new AwesomeEvent(this, 1);
     mStreamDoneEventPending = false;
+    mBufferingEvent = new AwesomeEvent(this, 2);
+    mBufferingEventPending = false;
 
     mQueue.start();
 
@@ -132,11 +135,16 @@
     mClient.disconnect();
 }
 
-void AwesomePlayer::cancelPlayerEvents() {
+void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
     mQueue.cancelEvent(mVideoEvent->eventID());
     mVideoEventPending = false;
     mQueue.cancelEvent(mStreamDoneEvent->eventID());
     mStreamDoneEventPending = false;
+
+    if (!keepBufferingGoing) {
+        mQueue.cancelEvent(mBufferingEvent->eventID());
+        mBufferingEventPending = false;
+    }
 }
 
 void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
@@ -149,12 +157,22 @@
 
     reset_l();
 
-    sp<MediaExtractor> extractor = MediaExtractor::CreateFromURI(uri);
+    sp<DataSource> dataSource = DataSource::CreateFromURI(uri);
+
+    if (dataSource == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
 
     if (extractor == NULL) {
         return UNKNOWN_ERROR;
     }
 
+    if (dataSource->flags() & DataSource::kWantsPrefetching) {
+        mPrefetcher = new Prefetcher;
+    }
+
     return setDataSource_l(extractor);
 }
 
@@ -182,8 +200,6 @@
 }
 
 status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
-    reset_l();
-
     bool haveAudio = false;
     bool haveVideo = false;
     for (size_t i = 0; i < extractor->countTracks(); ++i) {
@@ -253,6 +269,8 @@
 
     mSeeking = false;
     mSeekTimeUs = 0;
+
+    mPrefetcher.clear();
 }
 
 // static
@@ -278,16 +296,38 @@
     }
 }
 
-void AwesomePlayer::notifyListener_l(int msg) {
+void AwesomePlayer::notifyListener_l(int msg, int ext1) {
     if (mListener != NULL) {
         sp<MediaPlayerBase> listener = mListener.promote();
 
         if (listener != NULL) {
-            listener->sendEvent(msg);
+            listener->sendEvent(msg, ext1);
         }
     }
 }
 
+void AwesomePlayer::onBufferingUpdate() {
+    Mutex::Autolock autoLock(mLock);
+    mBufferingEventPending = false;
+
+    if (mDurationUs >= 0) {
+        int64_t cachedDurationUs = mPrefetcher->getCachedDurationUs();
+        int64_t positionUs = 0;
+        if (mVideoRenderer != NULL) {
+            positionUs = mVideoTimeUs;
+        } else if (mAudioPlayer != NULL) {
+            positionUs = mAudioPlayer->getMediaTimeUs();
+        }
+
+        cachedDurationUs += positionUs;
+
+        double percentage = (double)cachedDurationUs / mDurationUs;
+        notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage * 100.0);
+
+        postBufferingEvent_l();
+    }
+}
+
 void AwesomePlayer::onStreamDone() {
     // Posted whenever any stream finishes playing.
 
@@ -361,6 +401,8 @@
         seekAudioIfNecessary_l();
     }
 
+    postBufferingEvent_l();
+
     return OK;
 }
 
@@ -414,7 +456,7 @@
         return OK;
     }
 
-    cancelPlayerEvents();
+    cancelPlayerEvents(true /* keepBufferingGoing */);
 
     if (mAudioPlayer != NULL) {
         mAudioPlayer->pause();
@@ -518,11 +560,15 @@
     return OK;
 }
 
-status_t AwesomePlayer::setAudioSource(const sp<MediaSource> &source) {
+status_t AwesomePlayer::setAudioSource(sp<MediaSource> source) {
     if (source == NULL) {
         return UNKNOWN_ERROR;
     }
 
+    if (mPrefetcher != NULL) {
+        source = mPrefetcher->addSource(source);
+    }
+
     sp<MetaData> meta = source->getFormat();
 
     const char *mime;
@@ -549,11 +595,15 @@
     return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
 }
 
-status_t AwesomePlayer::setVideoSource(const sp<MediaSource> &source) {
+status_t AwesomePlayer::setVideoSource(sp<MediaSource> source) {
     if (source == NULL) {
         return UNKNOWN_ERROR;
     }
 
+    if (mPrefetcher != NULL) {
+        source = mPrefetcher->addSource(source);
+    }
+
     mVideoSource = OMXCodec::Create(
             mClient.interface(), source->getFormat(),
             false, // createEncoder
@@ -580,9 +630,13 @@
     if (code == 1) {
         onStreamDone();
         return;
+    } else if (code == 2) {
+        onBufferingUpdate();
+        return;
     }
 
     Mutex::Autolock autoLock(mLock);
+
     mVideoEventPending = false;
 
     if (mSeeking) {
@@ -718,5 +772,17 @@
     mQueue.postEvent(mStreamDoneEvent);
 }
 
+void AwesomePlayer::postBufferingEvent_l() {
+    if (mPrefetcher == NULL) {
+        return;
+    }
+
+    if (mBufferingEventPending) {
+        return;
+    }
+    mBufferingEventPending = true;
+    mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/CachingDataSource.cpp b/media/libstagefright/CachingDataSource.cpp
index 23f4897..8d04ead 100644
--- a/media/libstagefright/CachingDataSource.cpp
+++ b/media/libstagefright/CachingDataSource.cpp
@@ -65,6 +65,10 @@
     return mSource->initCheck();
 }
 
+uint32_t CachingDataSource::flags() {
+    return mSource->flags();
+}
+
 ssize_t CachingDataSource::readAt(off_t offset, void *data, size_t size) {
     Mutex::Autolock autoLock(mLock);
 
diff --git a/media/libstagefright/HTTPDataSource.cpp b/media/libstagefright/HTTPDataSource.cpp
index 7e8bbc6..135a044 100644
--- a/media/libstagefright/HTTPDataSource.cpp
+++ b/media/libstagefright/HTTPDataSource.cpp
@@ -190,30 +190,12 @@
     mHttp = NULL;
 }
 
-ssize_t HTTPDataSource::readAt(off_t offset, void *data, size_t size) {
-    if (offset >= mBufferOffset
-            && offset < (off_t)(mBufferOffset + mBufferLength)) {
-        size_t num_bytes_available = mBufferLength - (offset - mBufferOffset);
-
-        size_t copy = num_bytes_available;
-        if (copy > size) {
-            copy = size;
-        }
-
-        memcpy(data, (const char *)mBuffer + (offset - mBufferOffset), copy);
-
-        return copy;
-    }
-
-    mBufferOffset = offset;
-    mBufferLength = 0;
-
+ssize_t HTTPDataSource::sendRangeRequest(size_t offset) {
     char host[128];
     sprintf(host, "Host: %s\r\n", mHost);
 
     char range[128];
-    sprintf(range, "Range: bytes=%ld-%ld\r\n\r\n",
-            mBufferOffset, mBufferOffset + kBufferSize - 1);
+    sprintf(range, "Range: bytes=%d-\r\n\r\n", offset);
 
     int http_status;
 
@@ -251,12 +233,44 @@
     char *end;
     unsigned long contentLength = strtoul(value.c_str(), &end, 10);
 
-    ssize_t num_bytes_received = mHttp->receive(mBuffer, contentLength);
+    return contentLength;
+}
 
-    if (num_bytes_received <= 0) {
-        return num_bytes_received;
+ssize_t HTTPDataSource::readAt(off_t offset, void *data, size_t size) {
+    if (offset >= mBufferOffset
+            && offset < (off_t)(mBufferOffset + mBufferLength)) {
+        size_t num_bytes_available = mBufferLength - (offset - mBufferOffset);
+
+        size_t copy = num_bytes_available;
+        if (copy > size) {
+            copy = size;
+        }
+
+        memcpy(data, (const char *)mBuffer + (offset - mBufferOffset), copy);
+
+        return copy;
     }
 
+    ssize_t contentLength = 0;
+    if (mBufferLength <= 0 || offset != mBufferOffset + mBufferLength) {
+        mHttp->disconnect();
+        contentLength = sendRangeRequest(offset);
+
+        if (contentLength > kBufferSize) {
+            contentLength = kBufferSize;
+        }
+    } else {
+        contentLength = kBufferSize;
+    }
+
+    mBufferOffset = offset;
+
+    if (contentLength <= 0) {
+        return contentLength;
+    }
+
+    ssize_t num_bytes_received = mHttp->receive(mBuffer, contentLength);
+
     mBufferLength = (size_t)num_bytes_received;
 
     size_t copy = mBufferLength;
diff --git a/media/libstagefright/Prefetcher.cpp b/media/libstagefright/Prefetcher.cpp
new file mode 100644
index 0000000..862998a
--- /dev/null
+++ b/media/libstagefright/Prefetcher.cpp
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Prefetcher"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "include/Prefetcher.h"
+
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <utils/List.h>
+
+namespace android {
+
+struct PrefetchedSource : public MediaSource {
+    PrefetchedSource(
+            const sp<Prefetcher> &prefetcher,
+            size_t index,
+            const sp<MediaSource> &source);
+
+    virtual status_t start(MetaData *params);
+    virtual status_t stop();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options);
+
+    virtual sp<MetaData> getFormat();
+
+protected:
+    virtual ~PrefetchedSource();
+
+private:
+    friend struct Prefetcher;
+
+    Mutex mLock;
+    Condition mCondition;
+
+    sp<Prefetcher> mPrefetcher;
+    sp<MediaSource> mSource;
+    size_t mIndex;
+    bool mStarted;
+    bool mReachedEOS;
+    int64_t mSeekTimeUs;
+    int64_t mCacheDurationUs;
+
+    List<MediaBuffer *> mCachedBuffers;
+
+    // Returns true iff source is currently caching.
+    bool getCacheDurationUs(int64_t *durationUs);
+
+    void updateCacheDuration_l();
+    void clearCache_l();
+
+    void cacheMore();
+
+    PrefetchedSource(const PrefetchedSource &);
+    PrefetchedSource &operator=(const PrefetchedSource &);
+};
+
+Prefetcher::Prefetcher()
+    : mDone(false),
+      mThreadExited(false) {
+    startThread();
+}
+
+Prefetcher::~Prefetcher() {
+    stopThread();
+}
+
+sp<MediaSource> Prefetcher::addSource(const sp<MediaSource> &source) {
+    Mutex::Autolock autoLock(mLock);
+
+    sp<PrefetchedSource> psource =
+        new PrefetchedSource(this, mSources.size(), source);
+
+    mSources.add(psource);
+
+    return psource;
+}
+
+void Prefetcher::startThread() {
+    mThreadExited = false;
+    mDone = false;
+
+    int res = androidCreateThreadEtc(
+            ThreadWrapper, this, "Prefetcher",
+            ANDROID_PRIORITY_DEFAULT, 0, &mThread);
+
+    CHECK_EQ(res, 1);
+}
+
+void Prefetcher::stopThread() {
+    Mutex::Autolock autoLock(mLock);
+
+    while (!mThreadExited) {
+        mDone = true;
+        mCondition.signal();
+        mCondition.wait(mLock);
+    }
+}
+
+// static
+int Prefetcher::ThreadWrapper(void *me) {
+    static_cast<Prefetcher *>(me)->threadFunc();
+
+    return 0;
+}
+
+// Cache about 10secs for each source.
+static int64_t kMaxCacheDurationUs = 10000000ll;
+
+void Prefetcher::threadFunc() {
+    for (;;) {
+        Mutex::Autolock autoLock(mLock);
+        if (mDone) {
+            mThreadExited = true;
+            mCondition.signal();
+            break;
+        }
+        mCondition.waitRelative(mLock, 10000000ll);
+
+        int64_t minCacheDurationUs = -1;
+        ssize_t minIndex = -1;
+        for (size_t i = 0; i < mSources.size(); ++i) {
+            sp<PrefetchedSource> source = mSources[i].promote();
+
+            if (source == NULL) {
+                continue;
+            }
+
+            int64_t cacheDurationUs;
+            if (!source->getCacheDurationUs(&cacheDurationUs)) {
+                continue;
+            }
+
+            if (cacheDurationUs >= kMaxCacheDurationUs) {
+                continue;
+            }
+
+            if (minIndex < 0 || cacheDurationUs < minCacheDurationUs) {
+                minCacheDurationUs = cacheDurationUs;
+                minIndex = i;
+            }
+        }
+
+        if (minIndex < 0) {
+            continue;
+        }
+
+        sp<PrefetchedSource> source = mSources[minIndex].promote();
+        if (source != NULL) {
+            source->cacheMore();
+        }
+    }
+}
+
+int64_t Prefetcher::getCachedDurationUs() {
+    Mutex::Autolock autoLock(mLock);
+
+    int64_t minCacheDurationUs = -1;
+    ssize_t minIndex = -1;
+    for (size_t i = 0; i < mSources.size(); ++i) {
+        int64_t cacheDurationUs;
+        sp<PrefetchedSource> source = mSources[i].promote();
+        if (source == NULL) {
+            continue;
+        }
+
+        if (!source->getCacheDurationUs(&cacheDurationUs)) {
+            continue;
+        }
+
+        if (cacheDurationUs >= kMaxCacheDurationUs) {
+            continue;
+        }
+
+        if (minIndex < 0 || cacheDurationUs < minCacheDurationUs) {
+            minCacheDurationUs = cacheDurationUs;
+            minIndex = i;
+        }
+    }
+
+    return minCacheDurationUs < 0 ? 0 : minCacheDurationUs;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+PrefetchedSource::PrefetchedSource(
+        const sp<Prefetcher> &prefetcher,
+        size_t index,
+        const sp<MediaSource> &source)
+    : mPrefetcher(prefetcher),
+      mSource(source),
+      mIndex(index),
+      mStarted(false),
+      mReachedEOS(false),
+      mSeekTimeUs(0),
+      mCacheDurationUs(0) {
+}
+
+PrefetchedSource::~PrefetchedSource() {
+    if (mStarted) {
+        stop();
+    }
+}
+
+status_t PrefetchedSource::start(MetaData *params) {
+    Mutex::Autolock autoLock(mLock);
+
+    status_t err = mSource->start(params);
+
+    if (err != OK) {
+        return err;
+    }
+
+    mStarted = true;
+
+    for (;;) {
+        // Buffer 2 secs on startup.
+        if (mReachedEOS || mCacheDurationUs > 2000000) {
+            break;
+        }
+
+        mCondition.wait(mLock);
+    }
+
+    return OK;
+}
+
+status_t PrefetchedSource::stop() {
+    Mutex::Autolock autoLock(mLock);
+
+    clearCache_l();
+
+    status_t err = mSource->stop();
+
+    mStarted = false;
+
+    return err;
+}
+
+status_t PrefetchedSource::read(
+        MediaBuffer **out, const ReadOptions *options) {
+    *out = NULL;
+
+    Mutex::Autolock autoLock(mLock);
+
+    CHECK(mStarted);
+
+    int64_t seekTimeUs;
+    if (options && options->getSeekTo(&seekTimeUs)) {
+        CHECK(seekTimeUs >= 0);
+
+        clearCache_l();
+
+        mReachedEOS = false;
+        mSeekTimeUs = seekTimeUs;
+    }
+
+    while (!mReachedEOS && mCachedBuffers.empty()) {
+        mCondition.wait(mLock);
+    }
+
+    if (mCachedBuffers.empty()) {
+        return ERROR_END_OF_STREAM;
+    }
+
+    *out = *mCachedBuffers.begin();
+    mCachedBuffers.erase(mCachedBuffers.begin());
+    updateCacheDuration_l();
+
+    return OK;
+}
+
+sp<MetaData> PrefetchedSource::getFormat() {
+    return mSource->getFormat();
+}
+
+bool PrefetchedSource::getCacheDurationUs(int64_t *durationUs) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (!mStarted || mReachedEOS) {
+        *durationUs = 0;
+
+        return false;
+    }
+
+    *durationUs = mCacheDurationUs;
+
+    return true;
+}
+
+void PrefetchedSource::cacheMore() {
+    MediaSource::ReadOptions options;
+
+    {
+        Mutex::Autolock autoLock(mLock);
+
+        if (!mStarted) {
+            return;
+        }
+
+        if (mSeekTimeUs >= 0) {
+            options.setSeekTo(mSeekTimeUs);
+            mSeekTimeUs = -1;
+        }
+    }
+
+    MediaBuffer *buffer;
+    status_t err = mSource->read(&buffer, &options);
+
+    Mutex::Autolock autoLock(mLock);
+
+    if (err != OK) {
+        mReachedEOS = true;
+        mCondition.signal();
+
+        return;
+    }
+
+    CHECK(buffer != NULL);
+
+    MediaBuffer *copy = new MediaBuffer(buffer->range_length());
+    memcpy(copy->data(),
+           (const uint8_t *)buffer->data() + buffer->range_offset(),
+           buffer->range_length());
+
+    sp<MetaData> from = buffer->meta_data();
+    sp<MetaData> to = copy->meta_data();
+
+    int64_t timeUs;
+    if (from->findInt64(kKeyTime, &timeUs)) {
+        to->setInt64(kKeyTime, timeUs);
+    }
+
+    buffer->release();
+    buffer = NULL;
+
+    mCachedBuffers.push_back(copy);
+    updateCacheDuration_l();
+    mCondition.signal();
+}
+
+void PrefetchedSource::updateCacheDuration_l() {
+    if (mCachedBuffers.size() < 2) {
+        mCacheDurationUs = 0;
+    } else {
+        int64_t firstTimeUs, lastTimeUs;
+        CHECK((*mCachedBuffers.begin())->meta_data()->findInt64(
+                    kKeyTime, &firstTimeUs));
+        CHECK((*--mCachedBuffers.end())->meta_data()->findInt64(
+                    kKeyTime, &lastTimeUs));
+
+        mCacheDurationUs = lastTimeUs - firstTimeUs;
+    }
+}
+
+void PrefetchedSource::clearCache_l() {
+    List<MediaBuffer *>::iterator it = mCachedBuffers.begin();
+    while (it != mCachedBuffers.end()) {
+        (*it)->release();
+
+        it = mCachedBuffers.erase(it);
+    }
+
+    updateCacheDuration_l();
+}
+
+}  // namespace android
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index b28a12c..c2e46c0 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -26,10 +26,11 @@
 
 namespace android {
 
+struct AudioPlayer;
 struct MediaBuffer;
 struct MediaExtractor;
 struct MediaSource;
-struct AudioPlayer;
+struct Prefetcher;
 struct TimeSource;
 
 struct AwesomeRenderer : public RefBase {
@@ -109,13 +110,18 @@
     bool mVideoEventPending;
     sp<TimedEventQueue::Event> mStreamDoneEvent;
     bool mStreamDoneEventPending;
+    sp<TimedEventQueue::Event> mBufferingEvent;
+    bool mBufferingEventPending;
 
     void postVideoEvent_l(int64_t delayUs = -1);
+    void postBufferingEvent_l();
     void postStreamDoneEvent_l();
 
     MediaBuffer *mLastVideoBuffer;
     MediaBuffer *mVideoBuffer;
 
+    sp<Prefetcher> mPrefetcher;
+
     status_t setDataSource_l(const sp<MediaExtractor> &extractor);
     void reset_l();
     status_t seekTo_l(int64_t timeUs);
@@ -123,17 +129,19 @@
     void initRenderer_l();
     void seekAudioIfNecessary_l();
 
-    void cancelPlayerEvents();
+    void cancelPlayerEvents(bool keepBufferingGoing = false);
 
-    status_t setAudioSource(const sp<MediaSource> &source);
-    status_t setVideoSource(const sp<MediaSource> &source);
+    status_t setAudioSource(sp<MediaSource> source);
+    status_t setVideoSource(sp<MediaSource> source);
 
     void onEvent(int32_t code);
 
     static void AudioNotify(void *me, int what);
     void onStreamDone();
 
-    void notifyListener_l(int msg);
+    void notifyListener_l(int msg, int ext1 = 0);
+
+    void onBufferingUpdate();
 
     AwesomePlayer(const AwesomePlayer &);
     AwesomePlayer &operator=(const AwesomePlayer &);
diff --git a/media/libstagefright/include/Prefetcher.h b/media/libstagefright/include/Prefetcher.h
new file mode 100644
index 0000000..7a97785
--- /dev/null
+++ b/media/libstagefright/include/Prefetcher.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PREFETCHER_H_
+
+#define PREFETCHER_H_
+
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct MediaSource;
+struct PrefetchedSource;
+
+struct Prefetcher : public RefBase {
+    Prefetcher();
+
+    // Given an existing MediaSource returns a new MediaSource
+    // that will benefit from prefetching/caching the original one.
+    sp<MediaSource> addSource(const sp<MediaSource> &source);
+
+    int64_t getCachedDurationUs();
+
+protected:
+    virtual ~Prefetcher();
+
+private:
+    Mutex mLock;
+    Condition mCondition;
+
+    Vector<wp<PrefetchedSource> > mSources;
+    android_thread_id_t mThread;
+    bool mDone;
+    bool mThreadExited;
+
+    void startThread();
+    void stopThread();
+
+    static int ThreadWrapper(void *me);
+    void threadFunc();
+
+    Prefetcher(const Prefetcher &);
+    Prefetcher &operator=(const Prefetcher &);
+};
+
+}  // namespace android
+
+#endif  // PREFETCHER_H_
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
index 5127255..6087268 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
@@ -274,6 +274,7 @@
     //video thumbnail
     public static final String THUMBNAIL_OUTPUT = "/sdcard/media_api/videoThumbnail.png";
     public static final String GOLDEN_THUMBNAIL_OUTPUT = "/sdcard/media_api/goldenThumbnail.png";
+    public static final String GOLDEN_THUMBNAIL_OUTPUT_2 = "/sdcard/media_api/goldenThumbnail2.png";
     
     //Metadata Utility
     public static final String[] THUMBNAIL_CAPTURE_TEST_FILES = {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
index 4e30f91..ee6067ab 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
@@ -420,7 +420,7 @@
   
     @LargeTest
     public void testGetThumbnail() throws Exception {
-      boolean getThumbnail = CodecTest.getThumbnail(MediaNames.VIDEO_H264_AAC, MediaNames.GOLDEN_THUMBNAIL_OUTPUT);
+      boolean getThumbnail = CodecTest.getThumbnail(MediaNames.VIDEO_H264_AAC, MediaNames.GOLDEN_THUMBNAIL_OUTPUT_2);
       assertTrue("Get Thumbnail", getThumbnail);         
     }
     
diff --git a/packages/DefaultContainerService/Android.mk b/packages/DefaultContainerService/Android.mk
new file mode 100755
index 0000000..2f1d6ab
--- /dev/null
+++ b/packages/DefaultContainerService/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := DefaultContainerService
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
new file mode 100755
index 0000000..fd77148
--- /dev/null
+++ b/packages/DefaultContainerService/AndroidManifest.xml
@@ -0,0 +1,14 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.defcontainer">
+    <uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER"/>
+
+    <application android:process="def.container.service"
+                 android:label="@string/service_name">
+
+        <service android:name=".DefaultContainerService"
+                 android:enabled="true"
+                 android:exported="true"
+                 android:permission="android.permission.COPY_PROTECTED_DATA"/>
+    </application>
+
+</manifest>
diff --git a/packages/DefaultContainerService/res/values/strings.xml b/packages/DefaultContainerService/res/values/strings.xml
new file mode 100644
index 0000000..2897f34
--- /dev/null
+++ b/packages/DefaultContainerService/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- service name  -->
+    <string name="service_name">Media Container Service</string>
+</resources>
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
new file mode 100644
index 0000000..d36207b
--- /dev/null
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -0,0 +1,305 @@
+package com.android.defcontainer;
+
+import com.android.internal.app.IMediaContainerService;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Debug;
+import android.os.IBinder;
+import android.os.IMountService;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.app.Service;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import android.os.FileUtils;
+
+
+/*
+ * This service copies a downloaded apk to a file passed in as
+ * a ParcelFileDescriptor or to a newly created container specified
+ * by parameters. The DownloadManager gives access to this process
+ * based on its uid. This process also needs the ACCESS_DOWNLOAD_MANAGER
+ * permission to access apks downloaded via the download manager.
+ */
+public class DefaultContainerService extends Service {
+    private static final String TAG = "DefContainer";
+    private static final boolean localLOGV = false;
+
+    private IMediaContainerService.Stub mBinder = new IMediaContainerService.Stub() {
+        /*
+         * Creates a new container and copies resource there.
+         * @param paackageURI the uri of resource to be copied. Can be either
+         * a content uri or a file uri
+         * @param containerId the id of the secure container that should
+         * be used for creating a secure container into which the resource
+         * will be copied.
+         * @param key Refers to key used for encrypting the secure container
+         * @param resFileName Name of the target resource file(relative to newly
+         * created secure container)
+         * @return Returns the new cache path where the resource has been copied into
+         *
+         */
+        public String copyResourceToContainer(final Uri packageURI,
+                final String containerId,
+                final String key, final String resFileName) {
+            if (packageURI == null || containerId == null) {
+                return null;
+            }
+            return copyResourceInner(packageURI, containerId, key, resFileName);
+        }
+
+        /*
+         * Copy specified resource to output stream
+         * @param packageURI the uri of resource to be copied. Should be a
+         * file uri
+         * @param outStream Remote file descriptor to be used for copying
+         * @return Returns true if copy succeded or false otherwise.
+         */
+        public boolean copyResource(final Uri packageURI,
+                ParcelFileDescriptor outStream) {
+            if (packageURI == null ||  outStream == null) {
+                return false;
+            }
+            ParcelFileDescriptor.AutoCloseOutputStream
+            autoOut = new ParcelFileDescriptor.AutoCloseOutputStream(outStream);
+            return copyFile(packageURI, autoOut);
+        }
+    };
+
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+    private IMountService getMountService() {
+        return IMountService.Stub.asInterface(ServiceManager.getService("mount"));
+    }
+
+    private String copyResourceInner(Uri packageURI, String newCacheId, String key, String resFileName) {
+        // Create new container at newCachePath
+        String codePath = packageURI.getPath();
+        String newCachePath = null;
+        final int CREATE_FAILED = 1;
+        final int COPY_FAILED = 2;
+        final int FINALIZE_FAILED = 3;
+        final int PASS = 4;
+        int errCode = CREATE_FAILED;
+        // Create new container
+        if ((newCachePath = createSdDir(packageURI, newCacheId, key)) != null) {
+            File resFile = new File(newCachePath, resFileName);
+            errCode = COPY_FAILED;
+            if (localLOGV) Log.i(TAG, "Trying to copy " + codePath + " to " + resFile);
+            // Copy file from codePath
+            if (FileUtils.copyFile(new File(codePath), resFile)) {
+                errCode = FINALIZE_FAILED;
+                if (finalizeSdDir(newCacheId)) {
+                    errCode = PASS;
+                }
+            }
+        }
+        // Print error based on errCode
+        String errMsg = "";
+        switch (errCode) {
+            case CREATE_FAILED:
+                errMsg = "CREATE_FAILED";
+                break;
+            case COPY_FAILED:
+                errMsg = "COPY_FAILED";
+                destroySdDir(newCacheId);
+                break;
+            case FINALIZE_FAILED:
+                errMsg = "FINALIZE_FAILED";
+                destroySdDir(newCacheId);
+                break;
+            default:
+                errMsg = "PASS";
+                unMountSdDir(newCacheId);
+                break;
+        }
+        Log.i(TAG, "Status: " + errMsg);
+        if (errCode != PASS) {
+            return null;
+        }
+        return newCachePath;
+    }
+
+    private String createSdDir(final Uri packageURI,
+            String containerId, String sdEncKey) {
+        File tmpPackageFile = new File(packageURI.getPath());
+        // Create mount point via MountService
+        IMountService mountService = getMountService();
+        long len = tmpPackageFile.length();
+        int mbLen = (int) (len/(1024*1024));
+        if ((len - (mbLen * 1024 * 1024)) > 0) {
+            mbLen++;
+        }
+        if (localLOGV) Log.i(TAG, "mbLen="+mbLen);
+        String cachePath = null;
+        int ownerUid = Process.myUid();
+        try {
+            cachePath = mountService.createSecureContainer(containerId,
+                mbLen,
+                "vfat", sdEncKey, ownerUid);
+            if (localLOGV) Log.i(TAG, "Trying to create secure container for  "
+                    + containerId + ", cachePath =" + cachePath);
+            return cachePath;
+        } catch(IllegalStateException e) {
+            Log.e(TAG, "Failed to create storage on sdcard with exception: " + e);
+        } catch(RemoteException e) {
+            Log.e(TAG, "MounteService not running?");
+            return null;
+        }
+        // TODO just fail here and let the user delete later on.
+        try {
+            mountService.destroySecureContainer(containerId);
+            if (localLOGV) Log.i(TAG, "Destroying cache for " + containerId
+                    + ", cachePath =" + cachePath);
+        } catch(IllegalStateException e) {
+            Log.e(TAG, "Failed to destroy existing cache: " + e);
+            return null;
+        } catch(RemoteException e) {
+            Log.e(TAG, "MounteService not running?");
+            return null;
+        }
+       try {
+            cachePath = mountService.createSecureContainer(containerId,
+                mbLen,
+                "vfat", sdEncKey, ownerUid);
+            if (localLOGV) Log.i(TAG, "Trying to install again " + containerId
+                   + ", cachePath =" + cachePath);
+            return cachePath;
+        } catch(IllegalStateException e) {
+            Log.e(TAG, "Failed to create storage on sdcard with exception: " + e);
+        } catch(RemoteException e) {
+            Log.e(TAG, "MounteService not running?");
+        }
+        return null;
+    }
+
+    private boolean destroySdDir(String containerId) {
+        try {
+            // We need to destroy right away
+            getMountService().destroySecureContainer(containerId);
+            return true;
+        } catch (IllegalStateException e) {
+            Log.i(TAG, "Failed to destroy container : " + containerId);
+        } catch(RemoteException e) {
+            Log.e(TAG, "MounteService not running?");
+        }
+        return false;
+    }
+
+    private boolean finalizeSdDir(String containerId){
+        try {
+            getMountService().finalizeSecureContainer(containerId);
+            return true;
+        } catch (IllegalStateException e) {
+            Log.i(TAG, "Failed to finalize container for pkg : " + containerId);
+        } catch(RemoteException e) {
+            Log.e(TAG, "MounteService not running?");
+        }
+        return false;
+    }
+
+    private boolean unMountSdDir(String containerId) {
+        try {
+            getMountService().unmountSecureContainer(containerId);
+            return true;
+        } catch (IllegalStateException e) {
+            Log.e(TAG, "Failed to unmount id:  " + containerId + " with exception " + e);
+        } catch(RemoteException e) {
+            Log.e(TAG, "MounteService not running?");
+        }
+        return false;
+    }
+
+    private String mountSdDir(String containerId, String key) {
+        try {
+            return getMountService().mountSecureContainer(containerId, key, Process.myUid());
+        } catch (IllegalStateException e) {
+            Log.e(TAG, "Failed to mount id: " +
+                    containerId + " with exception " + e);
+        } catch(RemoteException e) {
+            Log.e(TAG, "MounteService not running?");
+        }
+        return null;
+    }
+
+    public static boolean copyToFile(InputStream inputStream, FileOutputStream out) {
+        try {
+            byte[] buffer = new byte[4096];
+            int bytesRead;
+            while ((bytesRead = inputStream.read(buffer)) >= 0) {
+                out.write(buffer, 0, bytesRead);
+            }
+            return true;
+        } catch (IOException e) {
+            Log.i(TAG, "Exception : " + e + " when copying file");
+            return false;
+        }
+    }
+
+    public static boolean copyToFile(File srcFile, FileOutputStream out) {
+        InputStream inputStream = null;
+        try {
+            inputStream = new FileInputStream(srcFile);
+            return copyToFile(inputStream, out);
+        } catch (IOException e) {
+            return false;
+        } finally {
+            try { if (inputStream != null) inputStream.close(); } catch (IOException e) {}
+        }
+    }
+
+    private  boolean copyFile(Uri pPackageURI, FileOutputStream outStream) {
+        if (pPackageURI.getScheme().equals("file")) {
+            final File srcPackageFile = new File(pPackageURI.getPath());
+            // We copy the source package file to a temp file and then rename it to the
+            // destination file in order to eliminate a window where the package directory
+            // scanner notices the new package file but it's not completely copied yet.
+            if (!copyToFile(srcPackageFile, outStream)) {
+                Log.e(TAG, "Couldn't copy file: " + srcPackageFile);
+                return false;
+            }
+        } else if (pPackageURI.getScheme().equals("content")) {
+            ParcelFileDescriptor fd = null;
+            try {
+                fd = getContentResolver().openFileDescriptor(pPackageURI, "r");
+            } catch (FileNotFoundException e) {
+                Log.e(TAG, "Couldn't open file descriptor from download service. Failed with exception " + e);
+                return false;
+            }
+            if (fd == null) {
+                Log.e(TAG, "Couldn't open file descriptor from download service (null).");
+                return false;
+            } else {
+                if (localLOGV) {
+                    Log.v(TAG, "Opened file descriptor from download service.");
+                }
+                ParcelFileDescriptor.AutoCloseInputStream
+                dlStream = new ParcelFileDescriptor.AutoCloseInputStream(fd);
+                // We copy the source package file to a temp file and then rename it to the
+                // destination file in order to eliminate a window where the package directory
+                // scanner notices the new package file but it's not completely copied yet.
+                if (!copyToFile(dlStream, outStream)) {
+                    Log.e(TAG, "Couldn't copy " + pPackageURI + " to temp file.");
+                    return false;
+                }
+            }
+        } else {
+            Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI);
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/preloaded-classes b/preloaded-classes
index 90bbb37..d108883 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -694,9 +694,7 @@
 com.ibm.icu4jni.charset.CharsetEncoderICU
 com.ibm.icu4jni.charset.CharsetICU
 com.ibm.icu4jni.text.CollationAttribute
-com.ibm.icu4jni.text.DecimalFormat
-com.ibm.icu4jni.text.DecimalFormatSymbols
-com.ibm.icu4jni.text.NativeDecimalFormat$UNumberFormatAttribute
+com.ibm.icu4jni.text.NativeDecimalFormat
 com.ibm.icu4jni.text.RuleBasedCollator
 com.ibm.icu4jni.util.Resources$DefaultTimeZones
 dalvik.system.DexFile
diff --git a/services/java/com/android/server/BootReceiver.java b/services/java/com/android/server/BootReceiver.java
index debbbb4..fbb4411 100644
--- a/services/java/com/android/server/BootReceiver.java
+++ b/services/java/com/android/server/BootReceiver.java
@@ -89,14 +89,14 @@
         }
 
         ContentResolver cr = context.getContentResolver();
-        logBootFile(cr, db, "/cache/recovery/log", "SYSTEM_RECOVERY_LOG");
-        logBootFile(cr, db, "/proc/last_kmsg", "SYSTEM_LAST_KMSG");
-        logBootFile(cr, db, "/data/dontpanic/apanic_console", "APANIC_CONSOLE");
-        logBootFile(cr, db, "/data/dontpanic/apanic_threads", "APANIC_THREADS");
+        logBootFile(cr, db, props, "/cache/recovery/log", "SYSTEM_RECOVERY_LOG");
+        logBootFile(cr, db, props, "/proc/last_kmsg", "SYSTEM_LAST_KMSG");
+        logBootFile(cr, db, props, "/data/dontpanic/apanic_console", "APANIC_CONSOLE");
+        logBootFile(cr, db, props, "/data/dontpanic/apanic_threads", "APANIC_THREADS");
     }
 
-    private void logBootFile(ContentResolver cr, DropBoxManager db, String filename, String tag)
-            throws IOException {
+    private void logBootFile(ContentResolver cr, DropBoxManager db,
+            CharSequence headers, String filename, String tag) throws IOException {
         if (cr == null || db == null || !db.isTagEnabled(tag)) return;  // Logging disabled
 
         File file = new File(filename);
@@ -108,10 +108,8 @@
         if (lastTime == fileTime) return;  // Already logged this particular file
         Settings.Secure.putLong(cr, setting, fileTime);
 
-        StringBuilder report = new StringBuilder();
-        report.append("Build: ").append(Build.FINGERPRINT).append("\n");
-        report.append("Kernel: ");
-        report.append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"));
+        StringBuilder report = new StringBuilder(headers);
+        report.append("\n");
         report.append(FileUtils.readTextFile(new File(filename), LOG_SIZE, "[[TRUNCATED]]\n"));
         db.addText(tag, report.toString());
     }
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index fbd5317..ebd6f3d 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -23,19 +23,23 @@
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
+import android.app.Activity;
 import android.app.DeviceAdmin;
 import android.app.DeviceAdminInfo;
 import android.app.DevicePolicyManager;
 import android.app.IDevicePolicyManager;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Binder;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.IPowerManager;
 import android.os.RecoverySystem;
+import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
@@ -64,16 +68,68 @@
     ActiveAdmin mActiveAdmin;
     
     static class ActiveAdmin {
-        ActiveAdmin(DeviceAdminInfo _info) {
-            info = _info;
-        }
-        
         final DeviceAdminInfo info;
-        int getUid() { return info.getActivityInfo().applicationInfo.uid; }
         
         int passwordMode = DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED;
         int minimumPasswordLength = 0;
         long maximumTimeToUnlock = 0;
+        int maximumFailedPasswordsForWipe = 0;
+        
+        ActiveAdmin(DeviceAdminInfo _info) {
+            info = _info;
+        }
+        
+        int getUid() { return info.getActivityInfo().applicationInfo.uid; }
+        
+        void writeToXml(XmlSerializer out)
+                throws IllegalArgumentException, IllegalStateException, IOException {
+            if (passwordMode != DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED) {
+                out.startTag(null, "password-mode");
+                out.attribute(null, "value", Integer.toString(passwordMode));
+                out.endTag(null, "password-mode");
+                if (minimumPasswordLength > 0) {
+                    out.startTag(null, "min-password-length");
+                    out.attribute(null, "value", Integer.toString(minimumPasswordLength));
+                    out.endTag(null, "mn-password-length");
+                }
+            }
+            if (maximumTimeToUnlock != DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED) {
+                out.startTag(null, "max-time-to-unlock");
+                out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
+                out.endTag(null, "max-time-to-unlock");
+            }
+            if (maximumFailedPasswordsForWipe != 0) {
+                out.startTag(null, "max-failed-password-wipe");
+                out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
+                out.endTag(null, "max-failed-password-wipe");
+            }
+        }
+        
+        void readFromXml(XmlPullParser parser)
+                throws XmlPullParserException, IOException {
+            int outerDepth = parser.getDepth();
+            int type;
+            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                   && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                    continue;
+                }
+                String tag = parser.getName();
+                if ("password-mode".equals(tag)) {
+                    passwordMode = Integer.parseInt(
+                            parser.getAttributeValue(null, "value"));
+                } else if ("min-password-length".equals(tag)) {
+                    minimumPasswordLength = Integer.parseInt(
+                            parser.getAttributeValue(null, "value"));
+                } else if ("max-time-to-unlock".equals(tag)) {
+                    maximumTimeToUnlock = Long.parseLong(
+                            parser.getAttributeValue(null, "value"));
+                } else if ("max-failed-password-wipe".equals(tag)) {
+                    maximumFailedPasswordsForWipe = Integer.parseInt(
+                            parser.getAttributeValue(null, "value"));
+                }
+            }
+        }
     }
     
     /**
@@ -91,25 +147,42 @@
         return mIPowerManager;
     }
     
-    ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
+    ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
+        ActiveAdmin admin = mActiveAdmin;
+        if (admin != null
+                && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
+                && who.getClassName().equals(admin.info.getActivityInfo().name)) {
+            return admin;
+        }
+        return null;
+    }
+    
+    ActiveAdmin getActiveAdminForCallerLocked(ComponentName who)
             throws SecurityException {
-        if (mActiveAdmin != null && mActiveAdmin.getUid() == Binder.getCallingUid()) {
+        ActiveAdmin admin = mActiveAdmin;
+        if (admin != null && admin.getUid() == Binder.getCallingUid()) {
             if (who != null) {
-                if (!who.getPackageName().equals(mActiveAdmin.info.getActivityInfo().packageName)
-                        || !who.getClassName().equals(mActiveAdmin.info.getActivityInfo().name)) {
+                if (!who.getPackageName().equals(admin.info.getActivityInfo().packageName)
+                        || !who.getClassName().equals(admin.info.getActivityInfo().name)) {
                     throw new SecurityException("Current admin is not " + who);
                 }
             }
-            if (!mActiveAdmin.info.usesPolicy(reqPolicy)) {
-                throw new SecurityException("Admin " + mActiveAdmin.info.getComponent()
-                        + " did not specify uses-policy for: "
-                        + mActiveAdmin.info.getTagForPolicy(reqPolicy));
-            }
             return mActiveAdmin;
         }
         throw new SecurityException("Current admin is not owned by uid " + Binder.getCallingUid());
     }
     
+    ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
+            throws SecurityException {
+        ActiveAdmin admin = getActiveAdminForCallerLocked(who);
+        if (!admin.info.usesPolicy(reqPolicy)) {
+            throw new SecurityException("Admin " + admin.info.getComponent()
+                    + " did not specify uses-policy for: "
+                    + admin.info.getTagForPolicy(reqPolicy));
+        }
+        return admin;
+    }
+    
     void sendAdminCommandLocked(ActiveAdmin admin, String action) {
         Intent intent = new Intent(action);
         intent.setComponent(admin.info.getComponent());
@@ -182,25 +255,17 @@
             if (ap != null) {
                 out.startTag(null, "admin");
                 out.attribute(null, "name", ap.info.getComponent().flattenToString());
-                if (ap.passwordMode != DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED) {
-                    out.startTag(null, "password-mode");
-                    out.attribute(null, "value", Integer.toString(ap.passwordMode));
-                    out.endTag(null, "password-mode");
-                    if (ap.minimumPasswordLength > 0) {
-                        out.startTag(null, "min-password-length");
-                        out.attribute(null, "value", Integer.toString(ap.minimumPasswordLength));
-                        out.endTag(null, "mn-password-length");
-                    }
-                }
-                if (ap.maximumTimeToUnlock != DevicePolicyManager.PASSWORD_MODE_UNSPECIFIED) {
-                    out.startTag(null, "max-time-to-unlock");
-                    out.attribute(null, "value", Long.toString(ap.maximumTimeToUnlock));
-                    out.endTag(null, "max-time-to-unlock");
-                }
+                ap.writeToXml(out);
                 out.endTag(null, "admin");
             }
             out.endTag(null, "policies");
 
+            if (mFailedPasswordAttempts != 0) {
+                out.startTag(null, "failed-password-attempts");
+                out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
+                out.endTag(null, "failed-password-attempts");
+            }
+            
             out.endDocument();
             stream.close();
             journal.commit();
@@ -220,51 +285,41 @@
         JournaledFile journal = makeJournaledFile();
         FileInputStream stream = null;
         File file = journal.chooseForRead();
-        boolean success = false;
         try {
             stream = new FileInputStream(file);
             XmlPullParser parser = Xml.newPullParser();
             parser.setInput(stream, null);
 
-            int type = parser.next();
-            while (type != XmlPullParser.START_TAG) {
-                type = parser.next();
+            int type;
+            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                    && type != XmlPullParser.START_TAG) {
             }
             String tag = parser.getName();
-            if ("policies".equals(tag)) {
-                ActiveAdmin ap = null;
-                do {
-                    type = parser.next();
-                    if (type == XmlPullParser.START_TAG) {
-                        tag = parser.getName();
-                        if (ap == null) {
-                            if ("admin".equals(tag)) {
-                                DeviceAdminInfo dai = findAdmin(
-                                        ComponentName.unflattenFromString(
-                                                parser.getAttributeValue(null, "name")));
-                                if (dai != null) {
-                                    ap = new ActiveAdmin(dai);
-                                }
-                            }
-                        } else if ("password-mode".equals(tag)) {
-                            ap.passwordMode = Integer.parseInt(
-                                    parser.getAttributeValue(null, "value"));
-                        } else if ("min-password-length".equals(tag)) {
-                            ap.minimumPasswordLength = Integer.parseInt(
-                                    parser.getAttributeValue(null, "value"));
-                        } else if ("max-time-to-unlock".equals(tag)) {
-                            ap.maximumTimeToUnlock = Long.parseLong(
-                                    parser.getAttributeValue(null, "value"));
-                        }
-                    } else if (type == XmlPullParser.END_TAG) {
-                        tag = parser.getName();
-                        if (ap != null && "admin".equals(tag)) {
-                            mActiveAdmin = ap;
-                            ap = null;
-                        }
+            if (!"policies".equals(tag)) {
+                throw new XmlPullParserException(
+                        "Settings do not start with policies tag: found " + tag);
+            }
+            type = parser.next();
+            int outerDepth = parser.getDepth();
+            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                   && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                    continue;
+                }
+                tag = parser.getName();
+                if ("admin".equals(tag)) {
+                    DeviceAdminInfo dai = findAdmin(
+                            ComponentName.unflattenFromString(
+                                    parser.getAttributeValue(null, "name")));
+                    if (dai != null) {
+                        ActiveAdmin ap = new ActiveAdmin(dai);
+                        ap.readFromXml(parser);
+                        mActiveAdmin = ap;
                     }
-                } while (type != XmlPullParser.END_DOCUMENT);
-                success = true;
+                } else if ("failed-password-attempts".equals(tag)) {
+                    mFailedPasswordAttempts = Integer.parseInt(
+                            parser.getAttributeValue(null, "value"));
+                }
             }
         } catch (NullPointerException e) {
             Log.w(TAG, "failed parsing " + file + " " + e);
@@ -285,10 +340,6 @@
             // Ignore
         }
 
-        if (!success) {
-            Log.w(TAG, "No valid start tag found in policies file");
-        }
-        
         long timeMs = getMaximumTimeToLock();
         if (timeMs <= 0) {
             timeMs = Integer.MAX_VALUE;
@@ -418,6 +469,27 @@
         }
     }
     
+    public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
+        synchronized (this) {
+            // This API can only be called by an active device admin,
+            // so try to retrieve it to check that the caller is one.
+            getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_WIPE_DATA);
+            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
+            if (ap.maximumFailedPasswordsForWipe != num) {
+                ap.maximumFailedPasswordsForWipe = num;
+                saveSettingsLocked();
+            }
+        }
+    }
+    
+    public int getMaximumFailedPasswordsForWipe() {
+        synchronized (this) {
+            return mActiveAdmin != null ? mActiveAdmin.maximumFailedPasswordsForWipe : 0;
+        }
+    }
+    
     public boolean resetPassword(String password) {
         int mode;
         synchronized (this) {
@@ -488,20 +560,53 @@
         }
     }
     
+    void wipeDataLocked(int flags) {
+        try {
+            RecoverySystem.rebootWipeUserData(mContext);
+        } catch (IOException e) {
+            Log.w(TAG, "Failed requesting data wipe", e);
+        }
+    }
+    
     public void wipeData(int flags) {
         synchronized (this) {
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(null,
                     DeviceAdminInfo.USES_POLICY_WIPE_DATA);
+            long ident = Binder.clearCallingIdentity();
+            try {
+                wipeDataLocked(flags);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
-        long ident = Binder.clearCallingIdentity();
-        try {
-            RecoverySystem.rebootWipeUserData(mContext);
-        } catch (IOException e) {
-            Log.w(TAG, "Failed requesting data wipe", e);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
+    }
+    
+    public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.BIND_DEVICE_ADMIN, null);
+        
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
+            if (admin == null) {
+                try {
+                    result.sendResult(null);
+                } catch (RemoteException e) {
+                }
+                return;
+            }
+            Intent intent = new Intent(DeviceAdmin.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
+            intent.setComponent(admin.info.getComponent());
+            mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    try {
+                        result.sendResult(getResultExtras(false));
+                    } catch (RemoteException e) {
+                    }
+                }
+            }, null, Activity.RESULT_OK, null, null);
         }
     }
     
@@ -516,7 +621,10 @@
                 try {
                     mActivePasswordMode = mode;
                     mActivePasswordLength = length;
-                    mFailedPasswordAttempts = 0;
+                    if (mFailedPasswordAttempts != 0) {
+                        mFailedPasswordAttempts = 0;
+                        saveSettingsLocked();
+                    }
                     sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_CHANGED,
                             DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
                 } finally {
@@ -534,6 +642,11 @@
             long ident = Binder.clearCallingIdentity();
             try {
                 mFailedPasswordAttempts++;
+                saveSettingsLocked();
+                int max = getMaximumFailedPasswordsForWipe();
+                if (max > 0 && mFailedPasswordAttempts >= max) {
+                    wipeDataLocked(0);
+                }
                 sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_FAILED,
                         DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
             } finally {
@@ -551,6 +664,7 @@
                 long ident = Binder.clearCallingIdentity();
                 try {
                     mFailedPasswordAttempts = 0;
+                    saveSettingsLocked();
                     sendAdminCommandLocked(DeviceAdmin.ACTION_PASSWORD_SUCCEEDED,
                             DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
                 } finally {
diff --git a/services/java/com/android/server/Installer.java b/services/java/com/android/server/Installer.java
index 6a7d432..88b1f02 100644
--- a/services/java/com/android/server/Installer.java
+++ b/services/java/com/android/server/Installer.java
@@ -263,10 +263,15 @@
         return execute(builder.toString());
     }
 
-    public int setForwardLockPerm(String packageName, int gid) {
+    /*
+     * @param packagePathSuffix The name of the path relative to install
+     * directory. Say if the path name is /data/app/com.test-1.apk,
+     * the package suffix path will be com.test-1
+     */
+    public int setForwardLockPerm(String packagePathSuffix, int gid) {
         StringBuilder builder = new StringBuilder("protect");
         builder.append(' ');
-        builder.append(packageName);
+        builder.append(packagePathSuffix);
         builder.append(' ');
         builder.append(gid);
         return execute(builder.toString());
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 85a2e0b..0b7cfae 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -553,7 +553,7 @@
                         if (st == VolumeState.NoMedia) {
                             state = Environment.MEDIA_REMOVED;
                         } else if (st == VolumeState.Idle) {
-                            state = Environment.MEDIA_UNMOUNTED;
+                            state = null;
                             try {
                                 mountVolume(path);
                             } catch (Exception ex) {
@@ -569,7 +569,9 @@
                             throw new Exception(String.format("Unexpected state %d", st));
                         }
                     }
-                    updatePublicVolumeState(path, state);
+                    if (state != null) {
+                        updatePublicVolumeState(path, state);
+                    }
                 } catch (Exception e) {
                     Log.e(TAG, "Error processing initial volume state", e);
                     updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
@@ -1056,11 +1058,21 @@
     }
 
     public String[] getSecureContainerList() throws IllegalStateException {
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.ASEC_ACCESS)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires ASEC_ACCESS permission");
+        }
         return mConnector.doListCommand("list_asec", VoldResponseCode.AsecListResult);
     }
 
     public String createSecureContainer(String id, int sizeMb, String fstype,
                                     String key, int ownerUid) throws IllegalStateException {
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.ASEC_CREATE)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires ASEC_CREATE permission");
+        }
         String cmd = String.format("create_asec %s %d %s %s %d",
                                    id, sizeMb, fstype, key, ownerUid);
         mConnector.doCommand(cmd);
@@ -1068,15 +1080,31 @@
     }
 
     public void finalizeSecureContainer(String id) throws IllegalStateException {
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.ASEC_CREATE)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires ASEC_CREATE permission");
+        }
         mConnector.doCommand(String.format("finalize_asec %s", id));
     }
 
     public void destroySecureContainer(String id) throws IllegalStateException {
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.ASEC_DESTROY)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires ASEC_DESTROY permission");
+        }
         mConnector.doCommand(String.format("destroy_asec %s", id));
     }
    
     public String mountSecureContainer(String id, String key,
                                        int ownerUid) throws IllegalStateException {
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.ASEC_MOUNT_UNMOUNT)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires ASEC_MOUNT_UNMOUNT permission");
+        }
+        mConnector.doCommand(String.format("destroy_asec %s", id));
         String cmd = String.format("mount_asec %s %s %d",
                                    id, key, ownerUid);
         mConnector.doCommand(cmd);
@@ -1084,16 +1112,31 @@
     }
 
     public void unmountSecureContainer(String id) throws IllegalStateException {
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.ASEC_MOUNT_UNMOUNT)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires ASEC_MOUNT_UNMOUNT permission");
+        }
         String cmd = String.format("unmount_asec %s", id);
         mConnector.doCommand(cmd);
     }
 
     public void renameSecureContainer(String oldId, String newId) throws IllegalStateException {
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.ASEC_RENAME)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires ASEC_RENAME permission");
+        }
         String cmd = String.format("rename_asec %s %s", oldId, newId);
         mConnector.doCommand(cmd);
     }
 
     public String getSecureContainerPath(String id) throws IllegalStateException {
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.ASEC_ACCESS)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires ASEC_ACCESS permission");
+        }
         ArrayList<String> rsp = mConnector.doCommand("asec_path " + id);
 
         for (String line : rsp) {
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 1307972..1cf3bad 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import com.android.internal.app.IMediaContainerService;
 import com.android.internal.app.ResolverActivity;
 import com.android.common.FastXmlSerializer;
 import com.android.common.XmlUtils;
@@ -31,6 +32,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
+import android.content.ServiceConnection;
 import android.content.IntentSender.SendIntentException;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
@@ -62,6 +64,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.HandlerThread;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
@@ -283,26 +286,79 @@
     final HashMap<String, ArrayList<String>> mPendingBroadcasts
             = new HashMap<String, ArrayList<String>>();
     static final int SEND_PENDING_BROADCAST = 1;
-    static final int DESTROY_SD_CONTAINER = 2;
+    static final int MCS_BOUND = 3;
+    static final int END_COPY = 4;
+    static final int INIT_COPY = 5;
+    static final int MCS_UNBIND = 6;
     // Delay time in millisecs
     static final int BROADCAST_DELAY = 10 * 1000;
-    static final int DESTROY_SD_CONTAINER_DELAY = 30 * 1000;
+    private ServiceConnection mDefContainerConn = new ServiceConnection() {
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            IMediaContainerService imcs =
+                IMediaContainerService.Stub.asInterface(service);
+            Message msg = mHandler.obtainMessage(MCS_BOUND, imcs);
+            mHandler.sendMessage(msg);
+        }
+
+        public void onServiceDisconnected(ComponentName name) {
+        }
+    };
 
     class PackageHandler extends Handler {
+        final ArrayList<InstallArgs> mPendingInstalls =
+            new ArrayList<InstallArgs>();
+        // Service Connection to remote media container service to copy
+        // package uri's from external media onto secure containers
+        // or internal storage.
+        private IMediaContainerService mContainerService = null;
+
         PackageHandler(Looper looper) {
             super(looper);
         }
         public void handleMessage(Message msg) {
             switch (msg.what) {
-                case DESTROY_SD_CONTAINER:
-                    String pkgName = (String) msg.obj;
-                    if (pkgName != null) {
-                        // Too bad we cannot handle the errors from destroying the containers.
-                        if (!destroySdDir(pkgName)) {
-                            Log.e(TAG, "Failed to destroy container for pkg : " + pkgName);
+                case INIT_COPY: {
+                    InstallArgs args = (InstallArgs) msg.obj;
+                    args.createCopyFile();
+                    Intent service = new Intent().setComponent(new ComponentName(
+                            "com.android.defcontainer",
+                            "com.android.defcontainer.DefaultContainerService"));
+                    if (mContainerService != null) {
+                        // No need to add to pending list. Use remote stub directly
+                        handleStartCopy(args);
+                    } else {
+                        if (mContext.bindService(service, mDefContainerConn,
+                                Context.BIND_AUTO_CREATE)) {
+                            mPendingInstalls.add(args);
+                        } else {
+                            Log.e(TAG, "Failed to bind to media container service");
+                            // Indicate install failure TODO add new error code
+                            processPendingInstall(args,
+                                    PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE);
                         }
                     }
                     break;
+                }
+                case MCS_BOUND: {
+                    // Initialize mContainerService if needed.
+                    if (msg.obj != null) {
+                        mContainerService = (IMediaContainerService) msg.obj;
+                    }
+                    if (mPendingInstalls.size() > 0) {
+                        InstallArgs args = mPendingInstalls.remove(0);
+                        if (args != null) {
+                            handleStartCopy(args);
+                        }
+                    }
+                    break;
+                }
+                case MCS_UNBIND : {
+                    if (mPendingInstalls.size() == 0) {
+                        mContext.unbindService(mDefContainerConn);
+                        mContainerService = null;
+                    }
+                    break;
+                }
                 case SEND_PENDING_BROADCAST : {
                     String packages[];
                     ArrayList components[];
@@ -343,7 +399,37 @@
                 }
             }
         }
+
+        // Utility method to initiate copying apk via media
+        // container service.
+        private void handleStartCopy(InstallArgs args) {
+            int ret = PackageManager.INSTALL_SUCCEEDED;
+            if (mContainerService == null) {
+                // Install error
+                ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+            } else {
+                ret = args.copyApk(mContainerService);
+            }
+            mHandler.sendEmptyMessage(MCS_UNBIND);
+            processPendingInstall(args, ret);
+        }
     }
+
+    static boolean installOnSd(int flags) {
+        if (((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) ||
+                ((flags & PackageManager.INSTALL_ON_SDCARD) == 0)) {
+            return false;
+        }
+        return true;
+    }
+
+    static boolean isFwdLocked(int flags) {
+        if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
+            return true;
+        }
+        return false;
+    }
+
     public static final IPackageManager main(Context context, boolean factoryTest) {
         PackageManagerService m = new PackageManagerService(context, factoryTest);
         ServiceManager.addService("package", m);
@@ -2022,11 +2108,12 @@
             int parseFlags,
             int scanMode) {
         mLastScanError = PackageManager.INSTALL_SUCCEEDED;
+        String scanPath = scanFile.getPath();
         parseFlags |= mDefParseFlags;
-        PackageParser pp = new PackageParser(scanFile.getPath());
+        PackageParser pp = new PackageParser(scanPath);
         pp.setSeparateProcesses(mSeparateProcesses);
         final PackageParser.Package pkg = pp.parsePackage(scanFile,
-                scanFile.getPath(),
+                scanPath,
                 mMetrics, parseFlags);
         if (pkg == null) {
             mLastScanError = pp.getParseError();
@@ -2066,7 +2153,8 @@
                         // Just remove the loaded entries from package lists.
                         mPackages.remove(ps.name);
                     }
-                    deletePackageResourcesLI(ps.name, ps.codePathString, ps.resourcePathString);
+                    InstallArgs args = new FileInstallArgs(ps.codePathString, ps.resourcePathString);
+                    args.cleanUpResourcesLI();
                     mSettings.enableSystemPackageLP(ps.name);
                 }
             }
@@ -2077,6 +2165,18 @@
         if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
             parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
         }
+
+        if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0) {
+            if (ps != null && ps.resourcePathString != null) {
+                pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
+            } else {
+                // Should not happen at all. Just log an error.
+                Log.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
+            }
+        } else {
+            pkg.applicationInfo.publicSourceDir = pkg.mScanPath;
+        }
+        pkg.applicationInfo.sourceDir = pkg.mScanPath;
         // Note that we invoke the following method only if we are about to unpack an application
         return scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE);
     }
@@ -2230,41 +2330,8 @@
         }
 
         // Initialize package source and resource directories
-        File destResourceFile = null;
-        File destCodeFile = null;
-        if ((scanMode & SCAN_NO_PATHS) == 0) {
-            boolean fwdLocked = (parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0;
-            final String pkgFileName = pkgName + ".apk";
-            File destDir = null;
-
-            if (fwdLocked) {
-                destDir = mDrmAppPrivateInstallDir;
-                destResourceFile = new File(mAppInstallDir, pkgName + ".zip");
-            } else {
-                boolean onSd = (parseFlags & PackageParser.PARSE_ON_SDCARD) != 0;
-                if (!onSd) {
-                    destDir = mAppInstallDir;
-                } else {
-                    String cachePath = getSdDir(pkgName);
-                    if (cachePath == null) {
-                        Log.e(TAG, "Secure container path for pkg: " + pkgName + " at location: " + cachePath +
-                                " not found");
-                        mLastScanError = PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
-                        return null;
-                    }
-                    destDir = new File(cachePath);
-                }
-                destResourceFile = new File(destDir, pkgFileName);
-            }
-            destCodeFile = new File(destDir, pkgFileName);
-            pkg.mPath = destCodeFile.getAbsolutePath();
-        } else {
-            pkg.mPath = pkg.mScanPath;
-            destCodeFile = new File(pkg.mScanPath);
-            destResourceFile = new File(pkg.mScanPath);
-        }
-        pkg.applicationInfo.sourceDir = destCodeFile.getAbsolutePath();
-        pkg.applicationInfo.publicSourceDir = destResourceFile.getAbsolutePath();
+        File destCodeFile = new File(pkg.applicationInfo.sourceDir);
+        File destResourceFile = new File(pkg.applicationInfo.publicSourceDir);
 
         SharedUserSetting suid = null;
         PackageSetting pkgSetting = null;
@@ -2568,21 +2635,17 @@
 
         // We don't expect installation to fail beyond this point,
         if ((scanMode&SCAN_MONITOR) != 0) {
-            pkg.mPath = destCodeFile.getAbsolutePath();
             mAppDirs.put(pkg.mPath, pkg);
         }
 
         // Request the ActivityManager to kill the process(only for existing packages)
         // so that we do not end up in a confused state while the user is still using the older
         // version of the application while the new one gets installed.
-        IActivityManager am = ActivityManagerNative.getDefault();
-        if ((am != null) && ((parseFlags & PackageManager.INSTALL_REPLACE_EXISTING ) != 0)) {
-            try {
-                am.killApplicationWithUid(pkg.applicationInfo.packageName,
+        if ((parseFlags & PackageManager.INSTALL_REPLACE_EXISTING ) != 0) {
+            killApplication(pkg.applicationInfo.packageName,
                         pkg.applicationInfo.uid);
-            } catch (RemoteException e) {
-            }
         }
+
         synchronized (mPackages) {
             // Add the new setting to mSettings
             mSettings.insertPackageSettingLP(pkgSetting, pkg);
@@ -2835,6 +2898,19 @@
         return pkg;
     }
 
+    private void killApplication(String pkgName, int uid) {
+        // Request the ActivityManager to kill the process(only for existing packages)
+        // so that we do not end up in a confused state while the user is still using the older
+        // version of the application while the new one gets installed.
+        IActivityManager am = ActivityManagerNative.getDefault();
+        if (am != null) {
+            try {
+                am.killApplicationWithUid(pkgName, uid);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
     // The following constants are returned by cachePackageSharedLibsForAbiLI
     // to indicate if native shared libraries were found in the package.
     // Values are:
@@ -3866,26 +3942,51 @@
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.INSTALL_PACKAGES, null);
 
+        Message msg = mHandler.obtainMessage(INIT_COPY);
+        msg.obj = createInstallArgs(packageURI, observer, flags, installerPackageName);
+        mHandler.sendMessage(msg);
+    }
+
+    private InstallArgs createInstallArgs(Uri packageURI, IPackageInstallObserver observer,
+            int flags, String installerPackageName) {
+        if (installOnSd(flags)) {
+            return new SdInstallArgs(packageURI, observer, flags,
+                    installerPackageName);
+        } else {
+            return new FileInstallArgs(packageURI, observer, flags,
+                    installerPackageName);
+        }
+    }
+
+    private InstallArgs createInstallArgs(int flags, String fullCodePath, String fullResourcePath) {
+        if (installOnSd(flags)) {
+            return new SdInstallArgs(fullCodePath, fullResourcePath);
+        } else {
+            return new FileInstallArgs(fullCodePath, fullResourcePath);
+        }
+    }
+
+    private void processPendingInstall(final InstallArgs args, final int currentStatus) {
         // Queue up an async operation since the package installation may take a little while.
         mHandler.post(new Runnable() {
             public void run() {
                 mHandler.removeCallbacks(this);
                  // Result object to be returned
                 PackageInstalledInfo res = new PackageInstalledInfo();
-                res.returnCode = PackageManager.INSTALL_SUCCEEDED;
+                res.returnCode = currentStatus;
                 res.uid = -1;
                 res.pkg = null;
                 res.removedInfo = new PackageRemovedInfo();
-                // Make a temporary copy of file from given packageURI
-                File tmpPackageFile = copyTempInstallFile(packageURI, res);
-                if (tmpPackageFile != null) {
+                args.doPreInstall(res.returnCode);
+                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
                     synchronized (mInstallLock) {
-                        installPackageLI(packageURI, flags, true, installerPackageName, tmpPackageFile, res);
+                        installPackageLI(args, true, res);
                     }
+                    args.doPostInstall(res.returnCode);
                 }
-                if (observer != null) {
+                if (args.observer != null) {
                     try {
-                        observer.packageInstalled(res.name, res.returnCode);
+                        args.observer.packageInstalled(res.name, res.returnCode);
                     } catch (RemoteException e) {
                         Log.i(TAG, "Observer no longer exists.");
                     }
@@ -3908,12 +4009,403 @@
                                 res.pkg.applicationInfo.packageName,
                                 extras);
                     }
+                    if (res.removedInfo.args != null) {
+                        // Remove the replaced package's older resources safely now
+                        synchronized (mInstallLock) {
+                            res.removedInfo.args.cleanUpResourcesLI();
+                        }
+                    }
                 }
                 Runtime.getRuntime().gc();
             }
         });
     }
 
+    static abstract class InstallArgs {
+        final IPackageInstallObserver observer;
+        final int flags;
+        final Uri packageURI;
+        final String installerPackageName;
+
+        InstallArgs(Uri packageURI,
+                IPackageInstallObserver observer, int flags,
+                String installerPackageName) {
+            this.packageURI = packageURI;
+            this.flags = flags;
+            this.observer = observer;
+            this.installerPackageName = installerPackageName;
+        }
+
+        abstract void createCopyFile();
+        abstract int copyApk(IMediaContainerService imcs);
+        abstract void doPreInstall(int status);
+        abstract boolean doRename(int status, String pkgName, String oldCodePath);
+        abstract void doPostInstall(int status);
+        abstract String getCodePath();
+        abstract String getResourcePath();
+        // Need installer lock especially for dex file removal.
+        abstract void cleanUpResourcesLI();
+    }
+
+    class FileInstallArgs extends InstallArgs {
+        File installDir;
+        String codeFileName;
+        String resourceFileName;
+
+        FileInstallArgs(Uri packageURI,
+                IPackageInstallObserver observer, int flags,
+                String installerPackageName) {
+            super(packageURI, observer, flags, installerPackageName);
+        }
+
+        FileInstallArgs(String fullCodePath, String fullResourcePath) {
+            super(null, null, 0, null);
+            File codeFile = new File(fullCodePath);
+            installDir = codeFile.getParentFile();
+            codeFileName = fullCodePath;
+            resourceFileName = fullResourcePath;
+        }
+
+        void createCopyFile() {
+            boolean fwdLocked = isFwdLocked(flags);
+            installDir = fwdLocked ? mDrmAppPrivateInstallDir : mAppInstallDir;
+            codeFileName = createTempPackageFile(installDir).getPath();
+            resourceFileName = getResourcePathFromCodePath();
+        }
+
+        String getCodePath() {
+            return codeFileName;
+        }
+
+        int copyApk(IMediaContainerService imcs) {
+            // Get a ParcelFileDescriptor to write to the output file
+            File codeFile = new File(codeFileName);
+            ParcelFileDescriptor out = null;
+            try {
+            out = ParcelFileDescriptor.open(codeFile,
+                    ParcelFileDescriptor.MODE_READ_WRITE);
+            } catch (FileNotFoundException e) {
+                Log.e(TAG, "Failed to create file descritpor for : " + codeFileName);
+                return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+            }
+            // Copy the resource now
+            int ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+            try {
+                if (imcs.copyResource(packageURI, out)) {
+                    ret = PackageManager.INSTALL_SUCCEEDED;
+                }
+            } catch (RemoteException e) {
+            } finally {
+                try { if (out != null) out.close(); } catch (IOException e) {}
+            }
+            return ret;
+        }
+
+        void doPreInstall(int status) {
+            if (status != PackageManager.INSTALL_SUCCEEDED) {
+                cleanUp();
+            }
+        }
+
+        boolean doRename(int status, final String pkgName, String oldCodePath) {
+            if (status != PackageManager.INSTALL_SUCCEEDED) {
+                cleanUp();
+                return false;
+            } else {
+                // Rename based on packageName
+                File codeFile = new File(getCodePath());
+                String apkName = getNextCodePath(oldCodePath, pkgName, ".apk");
+                File desFile = new File(installDir, apkName + ".apk");
+                if (!codeFile.renameTo(desFile)) {
+                    return false;
+                }
+                // Reset paths since the file has been renamed.
+                codeFileName = desFile.getPath();
+                resourceFileName = getResourcePathFromCodePath();
+                // Set permissions
+                if (!setPermissions(pkgName)) {
+                    // Failed setting permissions.
+                    return false;
+                }
+                return true;
+            }
+        }
+
+        void doPostInstall(int status) {
+            if (status != PackageManager.INSTALL_SUCCEEDED) {
+                cleanUp();
+            }
+        }
+
+        String getResourcePath() {
+            return resourceFileName;
+        }
+
+        String getResourcePathFromCodePath() {
+            String codePath = getCodePath();
+            if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
+                String apkNameOnly = getApkName(codePath);
+                return mAppInstallDir.getPath() + "/" + apkNameOnly + ".zip";
+            } else {
+                return codePath;
+            }
+        }
+
+        private boolean cleanUp() {
+            boolean ret = true;
+            String sourceDir = getCodePath();
+            String publicSourceDir = getResourcePath();
+            if (sourceDir != null) {
+                File sourceFile = new File(sourceDir);
+                if (!sourceFile.exists()) {
+                    Log.w(TAG, "Package source " + sourceDir + " does not exist.");
+                    ret = false;
+                }
+                // Delete application's code and resources
+                sourceFile.delete();
+            }
+            if (publicSourceDir != null && !publicSourceDir.equals(sourceDir)) {
+                final File publicSourceFile = new File(publicSourceDir);
+                if (!publicSourceFile.exists()) {
+                    Log.w(TAG, "Package public source " + publicSourceFile + " does not exist.");
+                }
+                if (publicSourceFile.exists()) {
+                    publicSourceFile.delete();
+                }
+            }
+            return ret;
+        }
+
+        void cleanUpResourcesLI() {
+            String sourceDir = getCodePath();
+            if (cleanUp() && mInstaller != null) {
+                int retCode = mInstaller.rmdex(sourceDir);
+                if (retCode < 0) {
+                    Log.w(TAG, "Couldn't remove dex file for package: "
+                            +  " at location "
+                            + sourceDir + ", retcode=" + retCode);
+                    // we don't consider this to be a failure of the core package deletion
+                }
+            }
+        }
+
+        private boolean setPermissions(String pkgName) {
+            // TODO Do this in a more elegant way later on. for now just a hack
+            if (!isFwdLocked(flags)) {
+                final int filePermissions =
+                    FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP
+                    |FileUtils.S_IROTH;
+                int retCode = FileUtils.setPermissions(getCodePath(), filePermissions, -1, -1);
+                if (retCode != 0) {
+                    Log.e(TAG, "Couldn't set new package file permissions for " +
+                            getCodePath()
+                            + ". The return code was: " + retCode);
+                    // TODO Define new internal error
+                    return false;
+                }
+                return true;
+            }
+            return true;
+        }
+    }
+
+    class SdInstallArgs extends InstallArgs {
+        String cid;
+        String cachePath;
+        static final String RES_FILE_NAME = "pkg.apk";
+
+        SdInstallArgs(Uri packageURI,
+                IPackageInstallObserver observer, int flags,
+                String installerPackageName) {
+           super(packageURI, observer, flags, installerPackageName);
+        }
+
+        SdInstallArgs(String fullCodePath, String fullResourcePath) {
+            super(null, null, 0, null);
+            // Extract cid from fullCodePath
+            int eidx = fullCodePath.lastIndexOf("/");
+            String subStr1 = fullCodePath.substring(0, eidx);
+            int sidx = subStr1.lastIndexOf("/");
+            cid = subStr1.substring(sidx+1, eidx);
+            cachePath = subStr1;
+        }
+
+        void createCopyFile() {
+            cid = getTempContainerId();
+        }
+
+        int copyApk(IMediaContainerService imcs) {
+            try {
+                cachePath = imcs.copyResourceToContainer(
+                        packageURI, cid,
+                        getEncryptKey(), RES_FILE_NAME);
+            } catch (RemoteException e) {
+            }
+
+            if (cachePath != null) {
+                // Mount container once its created with system_uid
+                cachePath = mountSdDir(cid, Process.SYSTEM_UID);
+            }
+            if (cachePath == null) {
+                return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
+            } else {
+                return PackageManager.INSTALL_SUCCEEDED;
+            }
+        }
+
+        @Override
+        String getCodePath() {
+            return cachePath + "/" + RES_FILE_NAME;
+        }
+
+        @Override
+        String getResourcePath() {
+            return cachePath + "/" + RES_FILE_NAME;
+        }
+
+        void doPreInstall(int status) {
+            if (status != PackageManager.INSTALL_SUCCEEDED) {
+                // Destroy container
+                destroySdDir(cid);
+            }
+        }
+
+        boolean doRename(int status, final String pkgName,
+                String oldCodePath) {
+            String newCacheId = getNextCodePath(oldCodePath, pkgName, "/" + RES_FILE_NAME);
+            // STOPSHIP TEMPORARY HACK FOR RENAME
+            // Create new container at newCachePath
+            String codePath = getCodePath();
+            String newCachePath = null;
+            final int CREATE_FAILED = 1;
+            final int COPY_FAILED = 3;
+            final int FINALIZE_FAILED = 5;
+            final int PASS = 7;
+            int errCode = CREATE_FAILED;
+            if ((newCachePath = createSdDir(new File(codePath), newCacheId)) != null) {
+                errCode = COPY_FAILED;
+                // Copy file from codePath
+                if (FileUtils.copyFile(new File(codePath), new File(newCachePath, RES_FILE_NAME))) {
+                    errCode = FINALIZE_FAILED;
+                    if (finalizeSdDir(newCacheId)) {
+                        errCode = PASS;
+                    }
+                }
+            }
+            // Print error based on errCode
+            String errMsg = "";
+            switch (errCode) {
+                case CREATE_FAILED:
+                    errMsg = "CREATE_FAILED";
+                    break;
+                case COPY_FAILED:
+                    errMsg = "COPY_FAILED";
+                    destroySdDir(newCacheId);
+                    break;
+                case FINALIZE_FAILED:
+                    errMsg = "FINALIZE_FAILED";
+                    destroySdDir(newCacheId);
+                    break;
+                default:
+                    errMsg = "PASS";
+                break;
+            }
+            // Destroy the temporary container
+            destroySdDir(cid);
+            Log.i(TAG, "Status: " + errMsg);
+            if (errCode != PASS) {
+                return false;
+            }
+            cid = newCacheId;
+            cachePath = newCachePath;
+
+            return true;
+        }
+
+        void doPostInstall(int status) {
+            if (status != PackageManager.INSTALL_SUCCEEDED) {
+                cleanUp();
+            } else {
+                // Unmount container
+                // Rename and remount based on package name and new uid
+            }
+        }
+
+        private void cleanUp() {
+            // Destroy secure container
+            destroySdDir(cid);
+        }
+
+        void cleanUpResourcesLI() {
+            String sourceFile = getCodePath();
+            // Remove dex file
+            if (mInstaller != null) {
+                int retCode = mInstaller.rmdex(sourceFile.toString());
+                if (retCode < 0) {
+                    Log.w(TAG, "Couldn't remove dex file for package: "
+                            + " at location "
+                            + sourceFile.toString() + ", retcode=" + retCode);
+                    // we don't consider this to be a failure of the core package deletion
+                }
+            }
+            cleanUp();
+        }
+    };
+
+    // Utility method used to create code paths based on package name and available index.
+    private static String getNextCodePath(String oldCodePath, String prefix, String suffix) {
+        String idxStr = "";
+        int idx = 1;
+        if (oldCodePath != null) {
+            int eidx = -1;
+            if (suffix != null) {
+                eidx = oldCodePath.indexOf(suffix);
+            }
+            if (eidx == -1) {
+                eidx = oldCodePath.length();
+            }
+            int sidx = oldCodePath.indexOf(prefix);
+            if (sidx == -1) {
+                sidx = 0;
+            }
+            String subStr = oldCodePath.substring(sidx + prefix.length(), eidx);
+            if (subStr != null) {
+                if (subStr.startsWith("-")) {
+                    subStr = subStr.substring(1);
+                }
+                try {
+                    idx = Integer.parseInt(subStr);
+                    if (idx <= 1) {
+                        idx++;
+                    } else {
+                        idx--;
+                    }
+                } catch(NumberFormatException e) {
+                }
+            }
+        }
+        idxStr = "-" + Integer.toString(idx);
+        return prefix + idxStr;
+    }
+
+    // Utility method that returns the relative package path with respect
+    // to the installation directory. Like say for /data/data/com.test-1.apk
+    // string com.test-1 is returned.
+    static String getApkName(String codePath) {
+        if (codePath == null) {
+            return null;
+        }
+        int sidx = codePath.lastIndexOf("/");
+        int eidx = codePath.lastIndexOf(".");
+        if (eidx == -1) {
+            eidx = codePath.length();
+        } else if (eidx == 0) {
+            Log.w(TAG, " Invalid code path, "+ codePath + " Not a valid apk name");
+            return null;
+        }
+        return codePath.substring(sidx+1, eidx);
+    }
+
     class PackageInstalledInfo {
         String name;
         int uid;
@@ -3932,7 +4424,6 @@
         // Remember this for later, in case we need to rollback this install
         boolean dataDirExists;
         String pkgName = pkg.packageName;
-        boolean onSd = (parseFlags & PackageParser.PARSE_ON_SDCARD) != 0;
 
         if (useEncryptedFilesystemForPackage(pkg)) {
             dataDirExists = (new File(mSecureAppDataDir, pkgName)).exists();
@@ -3950,14 +4441,6 @@
             }
         }
         mLastScanError = PackageManager.INSTALL_SUCCEEDED;
-        if (onSd) {
-            // Create secure container mount point for package
-            String cPath = createSdDir(new File(pkg.mScanPath), pkgName);
-            if (cPath == null) {
-                mLastScanError = res.returnCode = PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
-                return;
-            }
-        }
         PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode);
         if (newPackage == null) {
             Log.w(TAG, "Package couldn't be installed in " + pkg.mPath);
@@ -3965,21 +4448,9 @@
                 res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
             }
         } else {
-            File destPackageFile = new File(pkg.mPath);
-            if (destPackageFile.exists()) {
-                // It's safe to do this because we know (from the above check) that the file
-                // isn't currently used for an installed package.
-                destPackageFile.delete();
-            }
             updateSettingsLI(newPackage,
                     installerPackageName,
                     res);
-            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
-                // Check if container can be finalized
-                if(onSd && !finalizeSdDir(pkgName)) {
-                    res.returnCode = PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
-                }
-            }
             // delete the partially installed application. the data directory will have to be
             // restored if it was already existing
             if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
@@ -3988,15 +4459,11 @@
                 // scanPackageLocked, unless those directories existed before we even tried to
                 // install.
                 deletePackageLI(
-                        pkgName, true,
+                        pkgName, false,
                         dataDirExists ? PackageManager.DONT_DELETE_DATA : 0,
                                 res.removedInfo);
             }
         }
-        if (onSd && res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
-            // Destroy cache
-            destroySdDir(pkgName);
-        }
     }
 
     private void replacePackageLI(PackageParser.Package pkg,
@@ -4039,7 +4506,7 @@
 
         parseFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
         // First delete the existing package while retaining the data directory
-        if (!deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA,
+        if (!deletePackageLI(pkgName, true, PackageManager.DONT_DELETE_DATA,
                 res.removedInfo)) {
             // If the existing package was'nt successfully deleted
             res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
@@ -4063,17 +4530,10 @@
 
         if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
             // If we deleted an exisiting package, the old source and resource files that we
-            // were keeping around in case we needed them (see below) can now be deleted
-            final ApplicationInfo deletedPackageAppInfo = deletedPackage.applicationInfo;
-            final ApplicationInfo installedPackageAppInfo =
-                newPackage.applicationInfo;
-            deletePackageResourcesLI(pkgName,
-                    !deletedPackageAppInfo.sourceDir
-                            .equals(installedPackageAppInfo.sourceDir)
-                            ? deletedPackageAppInfo.sourceDir : null,
-                    !deletedPackageAppInfo.publicSourceDir
-                            .equals(installedPackageAppInfo.publicSourceDir)
-                            ? deletedPackageAppInfo.publicSourceDir : null);
+            // were keeping around in case we needed them (see below) can now be deleted.
+            // This info will be set on the res.removedInfo to clean up later on as post
+            // install action.
+
             //update signature on the new package setting
             //this should always succeed, since we checked the
             //signature earlier.
@@ -4100,22 +4560,15 @@
                     Log.e(TAG, "Failed allocating storage when restoring pkg : " + pkgName);
                     return;
                 }
-                File restoreTmpFile = createTempPackageFile();
-                if (restoreTmpFile == null) {
-                    Log.e(TAG, "Failed creating temp file when restoring pkg :  " + pkgName);
-                    return;
-                }
-                if (!FileUtils.copyFile(restoreFile, restoreTmpFile)) {
-                    Log.e(TAG, "Failed copying temp file when restoring pkg : " + pkgName);
-                    return;
-                }
                 PackageInstalledInfo restoreRes = new PackageInstalledInfo();
                 restoreRes.removedInfo = new PackageRemovedInfo();
-                installPackageLI(
-                        Uri.fromFile(restoreFile),
-                        isForwardLocked(deletedPackage)
-                        ? PackageManager.INSTALL_FORWARD_LOCK
-                                : 0, false, oldInstallerPackageName, restoreTmpFile, restoreRes);
+                // Parse old package
+                parseFlags |= ~PackageManager.INSTALL_REPLACE_EXISTING;
+                scanPackageLI(restoreFile, parseFlags, scanMode);
+                synchronized (mPackages) {
+                    grantPermissionsLP(deletedPackage, false);
+                    mSettings.writeLP();
+                }
                 if (restoreRes.returnCode != PackageManager.INSTALL_SUCCEEDED) {
                     Log.e(TAG, "Failed restoring pkg : " + pkgName + " after failed upgrade");
                 }
@@ -4220,24 +4673,11 @@
                 return;
             }
         }
-        // XXX There are probably some big issues here: upon doing
-        // the rename, we have reached the point of no return (the
-        // original .apk is gone!), so we can't fail.  Yet... we can.
-        File scanFile = new File(newPackage.mScanPath);
-        if (!scanFile.renameTo(new File(newPackage.mPath))) {
-            Log.e(TAG, "Couldn't move package file: " + newPackage.mScanPath + " to: " + newPackage.mPath);
-            // TODO rename should work. Workaround
-            if (!FileUtils.copyFile(scanFile, new File(newPackage.mPath))) {
-                Log.e(TAG, "Couldn't move package file to: " + newPackage.mPath);
-                res.returnCode =  PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-            }
+        res.returnCode = setPermissionsLI(newPackage);
+        if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+            return;
         } else {
-            res.returnCode = setPermissionsLI(newPackage);
-            if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
-                return;
-            } else {
-                Log.d(TAG, "New package installed in " + newPackage.mPath);
-            }
+            Log.d(TAG, "New package installed in " + newPackage.mPath);
         }
         if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
             if (mInstaller != null) {
@@ -4258,67 +4698,11 @@
         }
     }
 
-    private File copyTempInstallFile(Uri pPackageURI,
-            PackageInstalledInfo res) {
-        File tmpPackageFile = createTempPackageFile();
-        int retCode = PackageManager.INSTALL_SUCCEEDED;
-        if (tmpPackageFile == null) {
-            res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-            return null;
-        }
-
-        if (pPackageURI.getScheme().equals("file")) {
-            final File srcPackageFile = new File(pPackageURI.getPath());
-            // We copy the source package file to a temp file and then rename it to the
-            // destination file in order to eliminate a window where the package directory
-            // scanner notices the new package file but it's not completely copied yet.
-            if (!FileUtils.copyFile(srcPackageFile, tmpPackageFile)) {
-                Log.e(TAG, "Couldn't copy package file to temp file.");
-                retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-            }
-        } else if (pPackageURI.getScheme().equals("content")) {
-            ParcelFileDescriptor fd = null;
-            try {
-                fd = mContext.getContentResolver().openFileDescriptor(pPackageURI, "r");
-            } catch (FileNotFoundException e) {
-                Log.e(TAG, "Couldn't open file descriptor from download service. Failed with exception " + e);
-                retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-            }
-            if (fd == null) {
-                Log.e(TAG, "Couldn't open file descriptor from download service (null).");
-                retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-            } else {
-                if (Config.LOGV) {
-                    Log.v(TAG, "Opened file descriptor from download service.");
-                }
-                ParcelFileDescriptor.AutoCloseInputStream
-                        dlStream = new ParcelFileDescriptor.AutoCloseInputStream(fd);
-                // We copy the source package file to a temp file and then rename it to the
-                // destination file in order to eliminate a window where the package directory
-                // scanner notices the new package file but it's not completely copied yet.
-                if (!FileUtils.copyToFile(dlStream, tmpPackageFile)) {
-                    Log.e(TAG, "Couldn't copy package stream to temp file.");
-                    retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-                }
-            }
-        } else {
-            Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI);
-            retCode = PackageManager.INSTALL_FAILED_INVALID_URI;
-        }
-
-        res.returnCode = retCode;
-        if (retCode != PackageManager.INSTALL_SUCCEEDED) {
-            if (tmpPackageFile != null && tmpPackageFile.exists()) {
-                tmpPackageFile.delete();
-            }
-            return null;
-        }
-        return tmpPackageFile;
-    }
-
-    private void installPackageLI(Uri pPackageURI,
-            int pFlags, boolean newInstall, String installerPackageName,
-            File tmpPackageFile, PackageInstalledInfo res) {
+    private void installPackageLI(InstallArgs args,
+            boolean newInstall, PackageInstalledInfo res) {
+        int pFlags = args.flags;
+        String installerPackageName = args.installerPackageName;
+        File tmpPackageFile = new File(args.getCodePath());
         boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
         boolean onSd = ((pFlags & PackageManager.INSTALL_ON_SDCARD) != 0);
         boolean replacingExistingPackage = false;
@@ -4353,14 +4737,25 @@
                 break main_flow;
             }
 
+            // Get rid of all references to package scan path via parser.
+            pp = null;
+            String oldCodePath = null;
             synchronized (mPackages) {
                 //check if installing already existing package
                 if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0
                         && mPackages.containsKey(pkgName)) {
                     replacingExistingPackage = true;
+                    oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
                 }
             }
 
+            if (!args.doRename(res.returnCode, pkgName, oldCodePath)) {
+                res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+                break main_flow;
+            }
+            // TODO rename  pkg.mScanPath In scanPackageLI let it just set values based on mScanPath
+            pkg.applicationInfo.sourceDir = pkg.mScanPath= pkg.mPath = args.getCodePath();
+            pkg.applicationInfo.publicSourceDir = args.getResourcePath();
             if(replacingExistingPackage) {
                 replacePackageLI(pkg, parseFlags, scanMode,
                         installerPackageName, res);
@@ -4369,15 +4764,16 @@
                         installerPackageName,res);
             }
         } finally {
-            if (tmpPackageFile != null && tmpPackageFile.exists()) {
-                tmpPackageFile.delete();
+            if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
             }
         }
     }
 
     private int setPermissionsLI(PackageParser.Package newPackage) {
         String pkgName = newPackage.packageName;
-        int retCode;
+        int retCode = 0;
+        // TODO Gross hack but fix later. Ideally move this to be a post installation
+        // check after alloting uid.
         if ((newPackage.applicationInfo.flags
                 & ApplicationInfo.FLAG_FORWARD_LOCK) != 0) {
             File destResourceFile = new File(newPackage.applicationInfo.publicSourceDir);
@@ -4391,7 +4787,7 @@
                 //TODO clean up the extracted public files
             }
             if (mInstaller != null) {
-                retCode = mInstaller.setForwardLockPerm(pkgName,
+                retCode = mInstaller.setForwardLockPerm(getApkName(newPackage.mPath),
                         newPackage.applicationInfo.uid);
             } else {
                 final int filePermissions =
@@ -4400,15 +4796,16 @@
                                                    newPackage.applicationInfo.uid);
             }
         } else {
-            final int filePermissions =
-                    FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP
-                    |FileUtils.S_IROTH;
-            retCode = FileUtils.setPermissions(newPackage.mPath, filePermissions, -1, -1);
+            // The permissions on the resource file was set when it was copied for
+            // non forward locked apps and apps on sdcard
         }
+
         if (retCode != 0) {
             Log.e(TAG, "Couldn't set new package file permissions for " +
                     newPackage.mPath
                        + ". The return code was: " + retCode);
+            // TODO Define new internal error
+            return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
         }
         return PackageManager.INSTALL_SUCCEEDED;
     }
@@ -4491,10 +4888,10 @@
         }
     }
 
-    private File createTempPackageFile() {
+    private File createTempPackageFile(File installDir) {
         File tmpPackageFile;
         try {
-            tmpPackageFile = File.createTempFile("vmdl", ".tmp", mAppInstallDir);
+            tmpPackageFile = File.createTempFile("vmdl", ".tmp", installDir);
         } catch (IOException e) {
             Log.e(TAG, "Couldn't create temp file for downloaded package file.");
             return null;
@@ -4570,6 +4967,13 @@
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras);
             }
         }
+        // Delete the resources here after sending the broadcast to let
+        // other processes clean up before deleting resources.
+        synchronized (mInstallLock) {
+            if (info.args != null) {
+                info.args.cleanUpResourcesLI();
+            }
+        }
         return res;
     }
 
@@ -4578,6 +4982,8 @@
         int uid = -1;
         int removedUid = -1;
         boolean isRemovedPackageSystemUpdate = false;
+        // Clean up resources deleted packages.
+        InstallArgs args = null;
 
         void sendBroadcast(boolean fullRemove, boolean replacing) {
             Bundle extras = new Bundle(1);
@@ -4707,36 +5113,6 @@
         return true;
     }
 
-    private void deletePackageResourcesLI(String packageName,
-            String sourceDir, String publicSourceDir) {
-        if (sourceDir != null) {
-            File sourceFile = new File(sourceDir);
-            if (!sourceFile.exists()) {
-                Log.w(TAG, "Package source " + sourceDir + " does not exist.");
-            }
-            // Delete application's code and resources
-            sourceFile.delete();
-            if (mInstaller != null) {
-                int retCode = mInstaller.rmdex(sourceFile.toString());
-                if (retCode < 0) {
-                    Log.w(TAG, "Couldn't remove dex file for package: "
-                            + packageName + " at location "
-                            + sourceFile.toString() + ", retcode=" + retCode);
-                    // we don't consider this to be a failure of the core package deletion
-                }
-            }
-        }
-        if (publicSourceDir != null && !publicSourceDir.equals(sourceDir)) {
-            final File publicSourceFile = new File(publicSourceDir);
-            if (!publicSourceFile.exists()) {
-                Log.w(TAG, "Package public source " + publicSourceFile + " does not exist.");
-            }
-            if (publicSourceFile.exists()) {
-                publicSourceFile.delete();
-            }
-        }
-    }
-
     private boolean deleteInstalledPackageLI(PackageParser.Package p,
             boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) {
         ApplicationInfo applicationInfo = p.applicationInfo;
@@ -4753,7 +5129,12 @@
 
         // Delete application code and resources
         if (deleteCodeAndResources) {
-            deletePackageResourcesLI(applicationInfo.packageName,
+            // TODO can pick up from PackageSettings as well
+            int installFlags = ((p.applicationInfo.flags & ApplicationInfo.FLAG_ON_SDCARD)!=0) ?
+                    PackageManager.INSTALL_ON_SDCARD : 0;
+            installFlags |= ((p.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK)!=0) ?
+                    PackageManager.INSTALL_FORWARD_LOCK : 0;
+            outInfo.args = createInstallArgs(installFlags,
                     applicationInfo.sourceDir, applicationInfo.publicSourceDir);
         }
         return true;
@@ -4798,12 +5179,6 @@
             Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
             return false;
         }
-        boolean onSd = (p.applicationInfo.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0;
-        // Mount sd container if needed
-        if (onSd) {
-            // TODO Better error handling from MountService api later
-            mountSdDir(p.packageName, Process.SYSTEM_UID) ;
-        }
         boolean ret = false;
         if ( (p.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
             Log.i(TAG, "Removing system package:"+p.packageName);
@@ -4812,22 +5187,10 @@
             ret = deleteSystemPackageLI(p, flags, outInfo);
         } else {
             Log.i(TAG, "Removing non-system package:"+p.packageName);
+            // Kill application pre-emptively especially for apps on sd.
+            killApplication(packageName, p.applicationInfo.uid);
             ret = deleteInstalledPackageLI (p, deleteCodeAndResources, flags, outInfo);
         }
-        if (ret && onSd) {
-            if (deleteCodeAndResources) {
-                // Post a delayed destroy on the container since there might
-                // be active processes holding open file handles to package
-                // resources which will get killed by the process killer when
-                // destroying the container. This might even kill the current
-                // process and crash the system. Delay the destroy a bit so
-                // that the active processes get to handle the uninstall broadcasts.
-                sendDelayedDestroySdDir(packageName);
-            } else {
-                // Just unmount the directory
-                unMountSdDir(packageName);
-            }
-        }
         return ret;
     }
 
@@ -7520,11 +7883,31 @@
     final private String mSdEncryptKey = "AppsOnSD";
     final private String mSdEncryptAlg = "AES";
     private boolean mMediaMounted = false;
+    private static final int MAX_CONTAINERS = 250;
 
-    private MountService getMountService() {
+
+    static MountService getMountService() {
         return (MountService) ServiceManager.getService("mount");
     }
 
+    private String getEncryptKey() {
+        try {
+            String sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString(mSdEncryptKey);
+            if (sdEncKey == null) {
+                sdEncKey = SystemKeyStore.getInstance().
+                        generateNewKeyHexString(128, mSdEncryptAlg, mSdEncryptKey);
+                if (sdEncKey == null) {
+                    Log.e(TAG, "Failed to create encryption keys");
+                    return null;
+                }
+            }
+            return sdEncKey;
+        } catch (NoSuchAlgorithmException nsae) {
+            Log.e(TAG, "Failed to create encryption keys with exception: " + nsae);
+            return null;
+        }
+    }
+
    private String createSdDir(File tmpPackageFile, String pkgName) {
         // Create mount point via MountService
         MountService mountService = getMountService();
@@ -7535,8 +7918,6 @@
         }
         if (DEBUG_SD_INSTALL) Log.i(TAG, "mbLen="+mbLen);
         String cachePath = null;
-        // Remove any pending destroy messages
-        mHandler.removeMessages(DESTROY_SD_CONTAINER, pkgName);
         String sdEncKey;
         try {
             sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString(mSdEncryptKey);
@@ -7597,7 +7978,13 @@
 
    private boolean unMountSdDir(String pkgName) {
        // STOPSHIP unmount directory
-       return true;
+       try {
+           getMountService().unmountSecureContainer(pkgName);
+           return true;
+       } catch (IllegalStateException e) {
+           Log.e(TAG, "Failed to unmount : " + pkgName + " with exception " + e);
+       }
+       return false;
    }
 
    private String getSdDir(String pkgName) {
@@ -7622,10 +8009,6 @@
 
    private boolean destroySdDir(String pkgName) {
        try {
-           if (mHandler.hasMessages(DESTROY_SD_CONTAINER, pkgName)) {
-               // Don't have to send message again
-               mHandler.removeMessages(DESTROY_SD_CONTAINER, pkgName);
-           }
            // We need to destroy right away
            getMountService().destroySecureContainer(pkgName);
            return true;
@@ -7635,7 +8018,7 @@
        }
    }
 
-   private String[] getSecureContainerList() {
+   static String[] getSecureContainerList() {
        try {
            return getMountService().getSecureContainerList();
        } catch (IllegalStateException e) {
@@ -7644,13 +8027,47 @@
        return null;
    }
 
-   private void sendDelayedDestroySdDir(String pkgName) {
-       if (mHandler.hasMessages(DESTROY_SD_CONTAINER, pkgName)) {
-           // Don't have to send message again
-           return;
+   static String getTempContainerId() {
+       String prefix = "smdl1tmp";
+       int tmpIdx = 1;
+       String list[] = getSecureContainerList();
+       if (list != null) {
+           int idx = 0;
+           int idList[] = new int[MAX_CONTAINERS];
+           boolean neverFound = true;
+           for (String name : list) {
+               // Ignore null entries
+               if (name == null) {
+                   continue;
+               }
+               int sidx = name.indexOf(prefix);
+               if (sidx == -1) {
+                   // Not a temp file. just ignore
+                   continue;
+               }
+               String subStr = name.substring(sidx + prefix.length());
+               idList[idx] = -1;
+               if (subStr != null) {
+                   try {
+                       int cid = Integer.parseInt(subStr);
+                       idList[idx++] = cid;
+                       neverFound = false;
+                   } catch (NumberFormatException e) {
+                   }
+               }
+           }
+           if (!neverFound) {
+               // Sort idList
+               Arrays.sort(idList);
+               for (int j = 1; j <= idList.length; j++) {
+                   if (idList[j-1] != j) {
+                       tmpIdx = j;
+                       break;
+                   }
+               }
+           }
        }
-       Message msg = mHandler.obtainMessage(DESTROY_SD_CONTAINER, pkgName);
-       mHandler.sendMessageDelayed(msg, DESTROY_SD_CONTAINER_DELAY);
+       return prefix + tmpIdx;
    }
 
    public void updateExternalMediaStatus(final boolean mediaStatus) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 44b6624..c2c6e76 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -61,6 +61,7 @@
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageManager;
 import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PathPermission;
 import android.content.pm.ProviderInfo;
@@ -8845,7 +8846,26 @@
                 sb.append("Process: system_server\n");
             } else {
                 sb.append("Process: ").append(process.processName).append("\n");
-                sb.append("Flags: 0x").append(Integer.toString(process.info.flags, 16)).append("\n");
+            }
+            if (process != null) {
+                int flags = process.info.flags;
+                IPackageManager pm = ActivityThread.getPackageManager();
+                sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n");
+                for (String pkg : process.pkgList) {
+                    sb.append("Package: ").append(pkg);
+                    try {
+                        PackageInfo pi = pm.getPackageInfo(pkg, 0);
+                        if (pi != null) {
+                            sb.append(" v").append(pi.versionCode);
+                            if (pi.versionName != null) {
+                                sb.append(" (").append(pi.versionName).append(")");
+                            }
+                        }
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Error getting package info: " + pkg, e);
+                    }
+                    sb.append("\n");
+                }
             }
             if (activity != null) {
                 sb.append("Activity: ").append(activity.shortComponentName).append("\n");
diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java
deleted file mode 100644
index 9e1af31..0000000
--- a/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java
+++ /dev/null
@@ -1,48 +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 com.android.telephonytest;
-
-import junit.framework.TestSuite;
-
-import android.test.InstrumentationTestRunner;
-import android.test.InstrumentationTestSuite;
-
-/**
- * Instrumentation Test Runner for all Telephony unit tests.
- *
- * Running all tests:
- *
- *   runtest telephony-unit
- * or
- *   adb shell am instrument -w com.android.telephonytest/.TelephonyUnitTestRunner
- */
-
-public class TelephonyUnitTestRunner extends InstrumentationTestRunner {
-
-    @Override
-    public TestSuite getAllTests() {
-        TestSuite suite = new InstrumentationTestSuite(this);
-        suite.addTestSuite(com.android.telephonytest.unit.CallerInfoUnitTest.class);
-        suite.addTestSuite(com.android.telephonytest.unit.PhoneNumberUtilsUnitTest.class);
-        return suite;
-    }
-
-    @Override
-    public ClassLoader getLoader() {
-        return TelephonyUnitTestRunner.class.getClassLoader();
-    }
-}
diff --git a/telephony/tests/TelephonyTest/Android.mk b/telephony/tests/telephonytests/Android.mk
similarity index 80%
rename from telephony/tests/TelephonyTest/Android.mk
rename to telephony/tests/telephonytests/Android.mk
index 1ef8448..45e265a 100644
--- a/telephony/tests/TelephonyTest/Android.mk
+++ b/telephony/tests/telephonytests/Android.mk
@@ -7,6 +7,6 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_PACKAGE_NAME := telephonytest
+LOCAL_PACKAGE_NAME := FrameworksTelephonyTests
 
 include $(BUILD_PACKAGE)
diff --git a/telephony/tests/TelephonyTest/AndroidManifest.xml b/telephony/tests/telephonytests/AndroidManifest.xml
similarity index 83%
rename from telephony/tests/TelephonyTest/AndroidManifest.xml
rename to telephony/tests/telephonytests/AndroidManifest.xml
index b2a481b..70aeebc 100644
--- a/telephony/tests/TelephonyTest/AndroidManifest.xml
+++ b/telephony/tests/telephonytests/AndroidManifest.xml
@@ -16,7 +16,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.telephonytest">
+    package="com.android.frameworks.telephonytests">
 
     <application>
         <uses-library android:name="android.test.runner" />
@@ -28,9 +28,9 @@
             </intent-filter>
         </activity>
     </application>
-    <instrumentation android:name=".TelephonyUnitTestRunner"
-        android:targetPackage="com.android.telephonytest"
-        android:label="Telephony unit tests InstrumentationRunner">
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="com.android.frameworks.telephonytests"
+        android:label="Frameworks Telephony Tests">
     </instrumentation>
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
 </manifest>
diff --git a/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java b/telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java
similarity index 100%
rename from tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
rename to telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java
diff --git a/tests/CoreTests/com/android/internal/telephony/PhoneNumberWatcherTest.java b/telephony/tests/telephonytests/src/android/telephony/PhoneNumberWatcherTest.java
similarity index 100%
rename from tests/CoreTests/com/android/internal/telephony/PhoneNumberWatcherTest.java
rename to telephony/tests/telephonytests/src/android/telephony/PhoneNumberWatcherTest.java
diff --git a/tests/CoreTests/com/android/internal/telephony/ATResponseParserTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/ATResponseParserTest.java
similarity index 100%
rename from tests/CoreTests/com/android/internal/telephony/ATResponseParserTest.java
rename to telephony/tests/telephonytests/src/com/android/internal/telephony/ATResponseParserTest.java
diff --git a/tests/CoreTests/com/android/internal/telephony/AdnRecordTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/AdnRecordTest.java
similarity index 100%
rename from tests/CoreTests/com/android/internal/telephony/AdnRecordTest.java
rename to telephony/tests/telephonytests/src/com/android/internal/telephony/AdnRecordTest.java
diff --git a/tests/CoreTests/com/android/internal/telephony/GsmAlphabetTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmAlphabetTest.java
similarity index 100%
rename from tests/CoreTests/com/android/internal/telephony/GsmAlphabetTest.java
rename to telephony/tests/telephonytests/src/com/android/internal/telephony/GsmAlphabetTest.java
diff --git a/tests/CoreTests/com/android/internal/telephony/SMSDispatcherTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java
similarity index 100%
rename from tests/CoreTests/com/android/internal/telephony/SMSDispatcherTest.java
rename to telephony/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java
diff --git a/tests/CoreTests/com/android/internal/telephony/SimPhoneBookTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/SimPhoneBookTest.java
similarity index 100%
rename from tests/CoreTests/com/android/internal/telephony/SimPhoneBookTest.java
rename to telephony/tests/telephonytests/src/com/android/internal/telephony/SimPhoneBookTest.java
diff --git a/tests/CoreTests/com/android/internal/telephony/SimSmsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/SimSmsTest.java
similarity index 100%
rename from tests/CoreTests/com/android/internal/telephony/SimSmsTest.java
rename to telephony/tests/telephonytests/src/com/android/internal/telephony/SimSmsTest.java
diff --git a/tests/CoreTests/com/android/internal/telephony/SimUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/SimUtilsTest.java
similarity index 100%
rename from tests/CoreTests/com/android/internal/telephony/SimUtilsTest.java
rename to telephony/tests/telephonytests/src/com/android/internal/telephony/SimUtilsTest.java
diff --git a/tests/CoreTests/com/android/internal/telephony/TelephonyUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/TelephonyUtilsTest.java
similarity index 100%
rename from tests/CoreTests/com/android/internal/telephony/TelephonyUtilsTest.java
rename to telephony/tests/telephonytests/src/com/android/internal/telephony/TelephonyUtilsTest.java
diff --git a/tests/CoreTests/com/android/internal/telephony/TestPhoneNotifier.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java
similarity index 100%
rename from tests/CoreTests/com/android/internal/telephony/TestPhoneNotifier.java
rename to telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java
similarity index 100%
rename from tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java
rename to telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/GSMTestHandler.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java
similarity index 100%
rename from tests/CoreTests/com/android/internal/telephony/gsm/GSMTestHandler.java
rename to telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java
diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java b/telephony/tests/telephonytests/src/com/android/telephonytest/unit/CallerInfoUnitTest.java
similarity index 100%
rename from telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java
rename to telephony/tests/telephonytests/src/com/android/telephonytest/unit/CallerInfoUnitTest.java
diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java b/telephony/tests/telephonytests/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java
similarity index 100%
rename from telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java
rename to telephony/tests/telephonytests/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java
diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java
index 69d55c1..d7dd601 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java
@@ -17,14 +17,17 @@
 package com.android.unit_tests;
 
 import android.content.ContentValues;
+import android.content.Context;
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.database.DatabaseUtils;
 import android.database.CharArrayBuffer;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteStatement;
+import android.os.Environment;
 import android.os.Handler;
 import android.os.Parcel;
+import android.test.AndroidTestCase;
 import android.test.PerformanceTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -41,7 +44,7 @@
 import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_COLUMNNAME_INDEX;
 import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_DEFAULT_INDEX;
 
-public class DatabaseGeneralTest extends TestCase implements PerformanceTestCase {
+public class DatabaseGeneralTest extends AndroidTestCase implements PerformanceTestCase {
 
     private static final String sString1 = "this is a test";
     private static final String sString2 = "and yet another test";
@@ -55,7 +58,8 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mDatabaseFile = new File("/sqlite_stmt_journals", "database_test.db");
+        File dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE);
+        mDatabaseFile = new File(dbDir, "database_test.db");
         if (mDatabaseFile.exists()) {
             mDatabaseFile.delete();
         }
diff --git a/tests/AndroidTests/src/com/android/unit_tests/internal/util/HanziToPinyinTest.java b/tests/AndroidTests/src/com/android/unit_tests/internal/util/HanziToPinyinTest.java
new file mode 100644
index 0000000..8e1ff0b
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/internal/util/HanziToPinyinTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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 com.android.unit_tests.internal.util;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Locale;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import com.android.internal.util.HanziToPinyin;
+import com.android.internal.util.HanziToPinyin.Token;
+
+import junit.framework.TestCase;
+
+public class HanziToPinyinTest extends TestCase {
+    private final static String ONE_HANZI = "\u675C";
+    private final static String TWO_HANZI = "\u675C\u9D51";
+    private final static String ASSIC = "test";
+    private final static String ONE_UNKNOWN = "\uFF71";
+    private final static String MISC = "test\u675C   Test with space\uFF71\uFF71\u675C";
+
+    @SmallTest
+    public void testGetToken() throws Exception {
+        ArrayList<Token> tokens = HanziToPinyin.getInstance().get(ONE_HANZI);
+        assertEquals(tokens.size(), 1);
+        assertEquals(tokens.get(0).type, Token.PINYIN);
+        assertTrue(tokens.get(0).target.equalsIgnoreCase("DU"));
+
+        tokens = HanziToPinyin.getInstance().get(TWO_HANZI);
+        assertEquals(tokens.size(), 2);
+        assertEquals(tokens.get(0).type, Token.PINYIN);
+        assertEquals(tokens.get(1).type, Token.PINYIN);
+        assertTrue(tokens.get(0).target.equalsIgnoreCase("DU"));
+        assertTrue(tokens.get(1).target.equalsIgnoreCase("JUAN"));
+
+        tokens = HanziToPinyin.getInstance().get(ASSIC);
+        assertEquals(tokens.size(), 1);
+        assertEquals(tokens.get(0).type, Token.LATIN);
+
+        tokens = HanziToPinyin.getInstance().get(ONE_UNKNOWN);
+        assertEquals(tokens.size(), 1);
+        assertEquals(tokens.get(0).type, Token.UNKNOWN);
+
+        tokens = HanziToPinyin.getInstance().get(MISC);
+        assertEquals(tokens.size(), 7);
+        assertEquals(tokens.get(0).type, Token.LATIN);
+        assertEquals(tokens.get(1).type, Token.PINYIN);
+        assertEquals(tokens.get(2).type, Token.LATIN);
+        assertEquals(tokens.get(3).type, Token.LATIN);
+        assertEquals(tokens.get(4).type, Token.LATIN);
+        assertEquals(tokens.get(5).type, Token.UNKNOWN);
+        assertEquals(tokens.get(6).type, Token.PINYIN);
+    }
+}
diff --git a/tests/CoreTests/android/core/CoreTests.java b/tests/CoreTests/android/core/CoreTests.java
deleted file mode 100644
index 442fe0f..0000000
--- a/tests/CoreTests/android/core/CoreTests.java
+++ /dev/null
@@ -1,65 +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.core;
-
-import com.android.internal.telephony.TelephonyTests;
-
-import junit.framework.TestSuite;
-
-import android.graphics.ColorStateListTest;
-import android.location.LocationManagerProximityTest;
-import android.location.LocationTest;
-import android.test.AndroidTestRunnerTest;
-import android.test.InstrumentationTestRunnerTest;
-import android.util.*;
-import android.view.FocusFinderTest;
-import android.view.ViewGroupAttributesTest;
-import android.webkit.*;
-
-public class CoreTests extends TestSuite {
-    
-    /**
-     * To run these tests:
-     * $ mmm java/tests && adb sync
-     * $ adb shell am instrument -w \
-     *    -e class android.core.CoreTests \
-     *    android.core/android.test.InstrumentationTestRunner
-     */
-    public static TestSuite suite() {
-        TestSuite suite = new TestSuite(CoreTests.class.getName());
-
-        // Re-enable StateListDrawableTest when we are running in the
-        // framework-test directory which allows access to package private
-        // access for MockView
-        // suite.addTestSuite(StateListDrawableTest.class);
-        suite.addTestSuite(DayOfMonthCursorTest.class);
-        suite.addTestSuite(MonthDisplayHelperTest.class);
-        suite.addTestSuite(StateSetTest.class);
-        suite.addTestSuite(ColorStateListTest.class);
-        suite.addTestSuite(FocusFinderTest.class);
-        suite.addTestSuite(ViewGroupAttributesTest.class);
-        suite.addTest(TelephonyTests.suite());
-        suite.addTestSuite(FloatMathTest.class);
-        suite.addTest(JavaTests.suite());
-        suite.addTestSuite(LocationTest.class);
-        suite.addTestSuite(LocationManagerProximityTest.class);
-        suite.addTestSuite(AndroidTestRunnerTest.class);
-        suite.addTestSuite(InstrumentationTestRunnerTest.class);
-        
-        return suite;
-    }
-}
diff --git a/tests/CoreTests/android/core/JavaTests.java b/tests/CoreTests/android/core/JavaTests.java
deleted file mode 100644
index bd8cbf0..0000000
--- a/tests/CoreTests/android/core/JavaTests.java
+++ /dev/null
@@ -1,86 +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.core;
-
-import junit.framework.TestSuite;
-
-public class JavaTests {
-    public static TestSuite suite() {
-        TestSuite suite = new TestSuite(JavaTests.class.getName());
-
-        //Disabling until bug http://b/issue?id=1200337 is resolved
-        //suite.addTestSuite(RequestAPITest.class);
-        suite.addTestSuite(MathTest.class);
-        suite.addTestSuite(StrictMathTest.class);
-        suite.addTestSuite(HashMapPerfTest.class);
-        suite.addTestSuite(TreeMapTest.class);
-        suite.addTestSuite(FloatDoubleTest.class);
-        suite.addTestSuite(Sha1Test.class);
-        suite.addTestSuite(NIOTest.class);
-        suite.addTestSuite(ReflectArrayTest.class);
-        //Commenting out until we find a better way to exclude from continuous testing.
-        //suite.addTestSuite(URLTest.class);
-        suite.addTestSuite(URITest.class);
-        suite.addTestSuite(RegexTest.class);
-        suite.addTestSuite(HashMapTest.class);
-        suite.addTestSuite(ArrayListTest.class);
-        suite.addTestSuite(BooleanTest.class);
-        suite.addTestSuite(StringTest.class);
-        suite.addTestSuite(BufferedReaderTest.class);
-        suite.addTestSuite(CharArrayReaderTest.class);
-        suite.addTestSuite(PushbackReaderTest.class);
-        suite.addTestSuite(StringReaderTest.class);
-        suite.addTestSuite(StreamTokenizerTest.class);
-        suite.addTestSuite(ByteArrayInputStreamTest.class);
-        suite.addTestSuite(DataInputStreamTest.class);
-        suite.addTestSuite(BufferedInputStreamTest.class);
-        suite.addTestSuite(PushbackInputStreamTest.class);
-        suite.addTestSuite(ByteArrayOutputStreamTest.class);
-        suite.addTestSuite(DataOutputStreamTest.class);
-        suite.addTestSuite(BufferedOutputStreamTest.class);
-        suite.addTestSuite(CharArrayWriterTest.class);
-        suite.addTestSuite(StringWriterTest.class);
-        suite.addTestSuite(PrintWriterTest.class);
-        suite.addTestSuite(BufferedWriterTest.class);
-        suite.addTestSuite(ClassTest.class);
-        //To be unccommented when Bug #799327 is fixed.
-        //suite.addTestSuite(ClassLoaderTest.class);
-        suite.addTestSuite(LineNumberReaderTest.class);
-        suite.addTestSuite(InputStreamReaderTest.class);
-        suite.addTestSuite(OutputStreamWriterTest.class);
-        suite.addTestSuite(EnumTest.class);
-        suite.addTestSuite(ParseIntTest.class);
-        suite.addTestSuite(PipedStreamTest.class);
-        suite.addTestSuite(LocaleTest.class);
-        //Commenting out until we find a better way to exclude from continuous testing.
-        //suite.addTestSuite(InetAddrTest.class);
-        suite.addTestSuite(SocketTest.class);
-        suite.addTestSuite(ChecksumTest.class);
-        suite.addTestSuite(DeflateTest.class);
-        suite.addTestSuite(ZipStreamTest.class);
-        suite.addTestSuite(GZIPStreamTest.class);
-        suite.addTestSuite(ZipFileTest.class);
-        suite.addTestSuite(FileTest.class);
-        suite.addTestSuite(SQLiteJDBCDriverTest.class);
-        suite.addTestSuite(AtParserTest.class);
-        suite.addTestSuite(DatagramTest.class);
-        suite.addTestSuite(CryptoTest.class);
-        suite.addTestSuite(MiscRegressionTest.class);
-
-        return suite;
-    }
-}
diff --git a/tests/CoreTests/android/location/LocationManagerProximityTest.java b/tests/CoreTests/android/location/LocationManagerProximityTest.java
deleted file mode 100644
index e82d878..0000000
--- a/tests/CoreTests/android/location/LocationManagerProximityTest.java
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright (C) 2008 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 android.location;
-
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.location.Criteria;
-import android.location.Location;
-import android.location.LocationManager;
-import android.provider.Settings;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.Suppress;
-import android.util.Log;
-
-/**
- * Tests for LocationManager.addProximityAlert
- * 
- * TODO: add tests for more scenarios
- * 
- * To run:
- *  adb shell am instrument -e class android.location.LocationManagerProximityTest \
- *     -w android.core/android.test.InstrumentationTestRunner
- *     
- * This test requires that the "Allow mock locations" setting be enabled.
- * To ensure reliable results, all location providers should be disabled.
- * 
- */
-@Suppress
-@MediumTest
-public class LocationManagerProximityTest extends AndroidTestCase {
-
-    private static final int UPDATE_LOCATION_WAIT_TIME = 1000;
-    private static final int PROXIMITY_WAIT_TIME = 2000;
-
-    private LocationManager mLocationManager;
-    private PendingIntent mPendingIntent;
-    private TestIntentReceiver mIntentReceiver;
-
-    private static final String LOG_TAG = "LocationProximityTest";
-
-    private static final String PROVIDER_NAME = "test";
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        // test that mock locations are allowed so a more descriptive error message can be logged
-        if (Settings.Secure.getInt(getContext().getContentResolver(),
-            Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 0) {
-            fail("Mock locations are currently disabled in Settings - this test requires " +
-                 "mock locations");
-        }
-
-        mLocationManager = (LocationManager) getContext().
-                getSystemService(Context.LOCATION_SERVICE);
-        if (mLocationManager.getProvider(PROVIDER_NAME) != null) {
-            mLocationManager.removeTestProvider(PROVIDER_NAME);
-        }
-        
-        mLocationManager.addTestProvider(PROVIDER_NAME, true, //requiresNetwork,
-                false, // requiresSatellite,
-                true, // requiresCell,
-                false, // hasMonetaryCost,
-                false, // supportsAltitude,
-                false, // supportsSpeed, s
-                false, // upportsBearing,
-                Criteria.POWER_MEDIUM, // powerRequirement
-                Criteria.ACCURACY_FINE); // accuracy
-        mLocationManager.setTestProviderEnabled(PROVIDER_NAME, true);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        mLocationManager.removeTestProvider(PROVIDER_NAME);
-
-        if (mPendingIntent != null) {
-            mLocationManager.removeProximityAlert(mPendingIntent);
-        }
-        if (mIntentReceiver != null) {
-            getContext().unregisterReceiver(mIntentReceiver);
-        }
-    }
-
-    /**
-     * Tests basic proximity alert when entering proximity
-     */
-    public void testEnterProximity() throws Exception {
-        doTestEnterProximity(10000);
-    }
-
-    /**
-     * Tests proximity alert when entering proximity, with no expiration 
-     */
-    public void testEnterProximity_noexpire() throws Exception {
-        doTestEnterProximity(-1);
-    }
-
-    /**
-     * Helper variant for testing enter proximity scenario 
-     * TODO: add additional parameters as more scenarios are added
-     * 
-     * @param expiration - expiry of proximity alert 
-     */
-    private void doTestEnterProximity(long expiration) throws Exception {
-        // update location to outside proximity range
-        synchronousSendLocation(30, 30);
-        registerProximityListener(0, 0, 1000, expiration);
-        sendLocation(0, 0);
-        waitForAlert();
-        assertProximityType(true);
-    }
-
-    /**
-     * Tests basic proximity alert when exiting proximity
-     */
-    public void testExitProximity() throws Exception {
-        // first do enter proximity scenario
-        doTestEnterProximity(-1);
-
-        // now update to trigger exit proximity proximity
-        mIntentReceiver.clearReceivedIntents();
-        sendLocation(20, 20);
-        waitForAlert();
-        assertProximityType(false);
-    }
-
-    /**
-     * Registers the proximity intent receiver
-     */
-    private void registerProximityListener(double latitude, double longitude, 
-            float radius, long expiration) {
-        String intentKey = "testProximity";
-        Intent proximityIntent = new Intent(intentKey);
-        mPendingIntent = PendingIntent.getBroadcast(getContext(), 0, 
-                proximityIntent, PendingIntent.FLAG_CANCEL_CURRENT);
-        mIntentReceiver = new TestIntentReceiver(intentKey);
-
-        mLocationManager.addProximityAlert(latitude, longitude, radius, 
-                expiration, mPendingIntent);
-
-        getContext().registerReceiver(mIntentReceiver, 
-                mIntentReceiver.getFilter());
-
-    }
-
-    /**
-     * Blocks until proximity intent notification is received
-     * @throws InterruptedException
-     */
-    private void waitForAlert() throws InterruptedException {
-        Log.d(LOG_TAG, "Waiting for proximity update");
-        synchronized (mIntentReceiver) {
-            mIntentReceiver.wait(PROXIMITY_WAIT_TIME);
-        }
-
-        assertNotNull("Did not receive proximity alert", 
-                mIntentReceiver.getLastReceivedIntent());
-    }
-
-    /**
-     * Asserts that the received intent had the enter proximity property set as
-     * expected
-     * @param expectedEnterProximity - true if enter proximity expected, false if
-     *   exit expected
-     */
-    private void assertProximityType(boolean expectedEnterProximity) 
-            throws Exception {
-        boolean proximityTest = mIntentReceiver.getLastReceivedIntent().
-                getBooleanExtra(LocationManager.KEY_PROXIMITY_ENTERING, 
-                !expectedEnterProximity);
-        assertEquals("proximity alert not set to expected enter proximity value",
-                expectedEnterProximity, proximityTest);
-    }
-
-    /**
-     * Synchronous variant of sendLocation
-     */
-    private void synchronousSendLocation(final double latitude, 
-            final double longitude)
-            throws InterruptedException {
-        sendLocation(latitude, longitude, this);
-        // wait for location to be set
-        synchronized (this) {
-            wait(UPDATE_LOCATION_WAIT_TIME);
-        }
-    }
-
-    /**
-     * Asynchronously update the mock location provider without notification
-     */
-    private void sendLocation(final double latitude, final double longitude) {
-        sendLocation(latitude, longitude, null);
-    }
-
-    /**
-     * Asynchronously update the mock location provider with given latitude and
-     * longitude
-     * 
-     * @param latitude - update location
-     * @param longitude - update location
-     * @param observer - optionally, object to notify when update is sent.If
-     *            null, no update will be sent
-     */
-    private void sendLocation(final double latitude, final double longitude, 
-            final Object observer) {
-        Thread locationUpdater = new Thread() {
-            @Override
-            public void run() {
-                Location loc = new Location(PROVIDER_NAME);
-                loc.setLatitude(latitude);
-                loc.setLongitude(longitude);
-
-                loc.setTime(java.lang.System.currentTimeMillis());
-                Log.d(LOG_TAG, "Sending update for " + PROVIDER_NAME);
-                mLocationManager.setTestProviderLocation(PROVIDER_NAME, loc);
-                if (observer != null) {
-                    synchronized (observer) {
-                        observer.notify();
-                    }
-                }
-            }
-        };
-        locationUpdater.start();
-
-    }
-
-    /**
-     * Helper class that receives a proximity intent and notifies the main class
-     * when received
-     */
-    private static class TestIntentReceiver extends BroadcastReceiver {
-
-        private String mExpectedAction;
-        private Intent mLastReceivedIntent;
-
-        public TestIntentReceiver(String expectedAction) {
-            mExpectedAction = expectedAction;
-            mLastReceivedIntent = null;
-        }
-
-        public IntentFilter getFilter() {
-            IntentFilter filter = new IntentFilter(mExpectedAction);
-            return filter;
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (intent != null && mExpectedAction.equals(intent.getAction())) {
-                Log.d(LOG_TAG, "Intent Received: " + intent.toString());
-                mLastReceivedIntent = intent;
-                synchronized (this) {
-                    notify();
-                }
-            }
-        }
-
-        public Intent getLastReceivedIntent() {
-            return mLastReceivedIntent;
-        }
-        
-        public void clearReceivedIntents() {
-            mLastReceivedIntent = null;
-        }
-    }
-}
diff --git a/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java b/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java
deleted file mode 100644
index fdfafe1..0000000
--- a/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-import com.android.internal.telephony.AdnRecordTest;
-import com.android.internal.telephony.gsm.GSMPhoneTest;
-import com.android.internal.telephony.GsmAlphabetTest;
-import com.android.internal.telephony.SMSDispatcherTest;
-import com.android.internal.telephony.SimPhoneBookTest;
-import com.android.internal.telephony.SimSmsTest;
-import com.android.internal.telephony.SimUtilsTest;
-
-import junit.framework.TestSuite;
-
-/**
- * To run these tests:
- * $ mmm java/tests && adb sync
- * $ adb shell am instrument -w \
- *    -e class com.android.internal.telephony.TelephonyTests \
- *    android.core/android.test.InstrumentationTestRunner
- */
-public class TelephonyTests {
-    public static TestSuite suite() {
-        TestSuite suite = new TestSuite(TelephonyTests.class.getName());
-
-        suite.addTestSuite(PhoneNumberWatcherTest.class);
-        suite.addTestSuite(ATResponseParserTest.class);
-        suite.addTestSuite(PhoneNumberUtilsTest.class);
-        suite.addTestSuite(SMSDispatcherTest.class);
-        //suite.addTestSuite(GSMPhoneTest.class);
-        suite.addTestSuite(AdnRecordTest.class);
-        suite.addTestSuite(GsmAlphabetTest.class);
-        suite.addTestSuite(SimUtilsTest.class);
-        suite.addTestSuite(SimPhoneBookTest.class);
-        suite.addTestSuite(SimSmsTest.class);
-        suite.addTestSuite(TelephonyUtilsTest.class);
-
-        return suite;
-    }
-}