Merge "Don't let email addresses in database names get into the EventLog."
diff --git a/Android.mk b/Android.mk
index a48ef45..06db5822 100644
--- a/Android.mk
+++ b/Android.mk
@@ -111,6 +111,7 @@
 	core/java/android/content/pm/IPackageDeleteObserver.aidl \
 	core/java/android/content/pm/IPackageInstallObserver.aidl \
 	core/java/android/content/pm/IPackageManager.aidl \
+	core/java/android/content/pm/IPackageMoveObserver.aidl \
 	core/java/android/content/pm/IPackageStatsObserver.aidl \
 	core/java/android/database/IContentObserver.aidl \
 	core/java/android/hardware/ISensorService.aidl \
@@ -275,7 +276,7 @@
 # Search through the base framework dirs for these packages.
 # The result will be relative to frameworks/base.
 fwbase_dirs_to_document := \
-	test-runner \
+	test-runner/src \
 	$(patsubst $(LOCAL_PATH)/%,%, \
 	  $(wildcard \
 	    $(foreach dir, $(FRAMEWORKS_BASE_JAVA_SRC_DIRS), \
diff --git a/api/current.xml b/api/current.xml
index eb1c6d6..33a8020 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -716,6 +716,17 @@
  visibility="public"
 >
 </field>
+<field name="MOVE_PACKAGE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.MOVE_PACKAGE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="PERSISTENT_ACTIVITY"
  type="java.lang.String"
  transient="false"
@@ -13833,7 +13844,7 @@
 >
 <parameter name="parcel" type="android.os.Parcel">
 </parameter>
-<parameter name="flags" type="int">
+<parameter name="flagz" type="int">
 </parameter>
 </method>
 <field name="CREATOR"
@@ -38899,6 +38910,17 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_PHYSICAL_DOCK_STATE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.extra.PHYSICAL_DOCK_STATE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="EXTRA_REMOTE_INTENT_TOKEN"
  type="java.lang.String"
  transient="false"
@@ -42617,6 +42639,16 @@
  visibility="public"
 >
 </field>
+<field name="backupAgentName"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="className"
  type="java.lang.String"
  transient="false"
@@ -60401,6 +60433,102 @@
 </parameter>
 </constructor>
 </class>
+<class name="ImageFormat"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="ImageFormat"
+ type="android.graphics.ImageFormat"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getBitsPerPixel"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="format" type="int">
+</parameter>
+</method>
+<field name="JPEG"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="256"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="NV16"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="NV21"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RGB_565"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="UNKNOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="YUY2"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="20"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 <class name="Interpolator"
  extends="java.lang.Object"
  abstract="false"
@@ -64462,7 +64590,7 @@
  value="256"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -64616,7 +64744,7 @@
  value="17"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -64627,7 +64755,7 @@
  value="20"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -64638,7 +64766,7 @@
  value="16"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -78725,6 +78853,17 @@
  visibility="public"
 >
 </field>
+<field name="PASSIVE_PROVIDER"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;passive&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="LocationProvider"
  extends="java.lang.Object"
@@ -84485,6 +84624,28 @@
 <parameter name="srcQuality" type="int">
 </parameter>
 </constructor>
+<method name="autoPause"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="autoResume"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="load"
  return="int"
  abstract="false"
@@ -84626,6 +84787,19 @@
 <parameter name="loop" type="int">
 </parameter>
 </method>
+<method name="setOnLoadCompleteListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.media.SoundPool.OnLoadCompleteListener">
+</parameter>
+</method>
 <method name="setPriority"
  return="void"
  abstract="false"
@@ -84700,6 +84874,31 @@
 </parameter>
 </method>
 </class>
+<interface name="SoundPool.OnLoadCompleteListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onLoadComplete"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="soundPool" type="android.media.SoundPool">
+</parameter>
+<parameter name="sampleId" type="int">
+</parameter>
+<parameter name="status" type="int">
+</parameter>
+</method>
+</interface>
 <class name="ThumbnailUtils"
  extends="java.lang.Object"
  abstract="false"
@@ -119379,6 +119578,17 @@
  visibility="public"
 >
 </field>
+<field name="OperationFailedStorageBusy"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="OperationFailedStorageMounted"
  type="int"
  transient="false"
@@ -130533,6 +130743,17 @@
  visibility="public"
 >
 </field>
+<field name="INTENT_ACTION_MUSIC_PLAYER"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.MUSIC_PLAYER&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="INTENT_ACTION_STILL_IMAGE_CAMERA"
  type="java.lang.String"
  transient="false"
@@ -136927,6 +137148,21 @@
 <parameter name="context" type="android.content.Context">
 </parameter>
 </method>
+<method name="createRecognitionManager"
+ return="android.speech.RecognitionManager"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="serviceComponent" type="android.content.ComponentName">
+</parameter>
+</method>
 <method name="destroy"
  return="void"
  abstract="false"
@@ -137325,6 +137561,30 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<method name="getVoiceDetailsIntent"
+ return="android.content.Intent"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<field name="ACTION_GET_LANGUAGE_DETAILS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.speech.action.GET_LANGUAGE_DETAILS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ACTION_RECOGNIZE_SPEECH"
  type="java.lang.String"
  transient="false"
@@ -137347,6 +137607,17 @@
  visibility="public"
 >
 </field>
+<field name="DETAILS_META_DATA"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.speech.DETAILS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="EXTRA_LANGUAGE"
  type="java.lang.String"
  transient="false"
@@ -137369,6 +137640,17 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_LANGUAGE_PREFERENCE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.speech.extra.LANGUAGE_PREFERENCE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="EXTRA_MAX_RESULTS"
  type="java.lang.String"
  transient="false"
@@ -137468,6 +137750,17 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_SUPPORTED_LANGUAGES"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.speech.extra.SUPPORTED_LANGUAGES&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="LANGUAGE_MODEL_FREE_FORM"
  type="java.lang.String"
  transient="false"
@@ -172819,6 +173112,19 @@
  visibility="public"
 >
 </method>
+<method name="dispatchConfigurationChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="newConfig" type="android.content.res.Configuration">
+</parameter>
+</method>
 <method name="dispatchDisplayHint"
  return="void"
  abstract="false"
@@ -174510,6 +174816,19 @@
  visibility="public"
 >
 </method>
+<method name="onConfigurationChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="newConfig" type="android.content.res.Configuration">
+</parameter>
+</method>
 <method name="onCreateContextMenu"
  return="void"
  abstract="false"
@@ -190894,6 +191213,17 @@
  visibility="public"
 >
 </method>
+<method name="getBlockNetworkLoads"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getBuiltInZoomControls"
  return="boolean"
  abstract="false"
@@ -191322,6 +191652,19 @@
 <parameter name="flag" type="boolean">
 </parameter>
 </method>
+<method name="setBlockNetworkLoads"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="flag" type="boolean">
+</parameter>
+</method>
 <method name="setBuiltInZoomControls"
  return="void"
  abstract="false"
@@ -201436,6 +201779,19 @@
  native="false"
  synchronized="false"
  static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="color" type="int">
+</parameter>
+</method>
+<method name="setColorFilter"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
  final="false"
  deprecated="not deprecated"
  visibility="public"
diff --git a/camera/libcameraservice/FakeCamera.cpp b/camera/libcameraservice/FakeCamera.cpp
index 3daf47d..6749899 100644
--- a/camera/libcameraservice/FakeCamera.cpp
+++ b/camera/libcameraservice/FakeCamera.cpp
@@ -234,7 +234,7 @@
             uint8_t   y0, y1, u, v;
 
             pixels =  inputRGB[i];
-            temp = (ALPHA*(pixels & 0x001F) + BETA*(pixels>>11) );
+            temp = (BETA*(pixels & 0x001F) + ALPHA*(pixels>>11) );
             y0   = y_tab[(temp>>SHIFT1) + ((pixels>>3) & 0x00FC)];
 
             G_ds    += (pixels>>1) & 0x03E0;
@@ -242,7 +242,7 @@
             R_ds    += (pixels>>6) & 0x03E0;
 
             pixels =  inputRGB[i+1];
-            temp = (ALPHA*(pixels & 0x001F) + BETA*(pixels>>11) );
+            temp = (BETA*(pixels & 0x001F) + ALPHA*(pixels>>11) );
             y1   = y_tab[(temp>>SHIFT1) + ((pixels>>3) & 0x00FC)];
 
             G_ds    += (pixels>>1) & 0x03E0;
@@ -255,8 +255,8 @@
 
             tmp = R_ds - B_ds;
 
-            u = cb_tab[(((R_ds-G_ds)<<SHIFT2) + DELTA*tmp)>>(SHIFT2+2)];
-            v = cr_tab[(((B_ds-G_ds)<<SHIFT2) - GAMMA*tmp)>>(SHIFT2+2)];
+            u = cb_tab[(((B_ds-G_ds)<<SHIFT2) - GAMMA*tmp)>>(SHIFT2+2)];
+            v = cr_tab[(((R_ds-G_ds)<<SHIFT2) + DELTA*tmp)>>(SHIFT2+2)];
 
             tempY[0] = y0;
             tempY[1] = y1;
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index 39e14e4..6a79c6d5 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -268,7 +268,10 @@
     char anr_traces_path[PATH_MAX];
     strlcpy(anr_traces_path, traces_path, sizeof(anr_traces_path));
     strlcat(anr_traces_path, ".anr", sizeof(anr_traces_path));
-    rename(traces_path, anr_traces_path);
+    if (rename(traces_path, anr_traces_path) && errno != ENOENT) {
+        fprintf(stderr, "rename(%s, %s): %s\n", traces_path, anr_traces_path, strerror(errno));
+        return NULL;  // Can't rename old traces.txt -- no permission? -- leave it alone instead
+    }
 
     /* create a new, empty traces.txt file to receive stack dumps */
     int fd = open(traces_path, O_CREAT | O_WRONLY | O_TRUNC, 0666);  /* -rw-rw-rw- */
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index ff16c6e..fc5707d 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -600,6 +600,7 @@
             } else if (opt.equals("-t")) {
                 installFlags |= PackageManager.INSTALL_ALLOW_TEST;
             } else if (opt.equals("-s")) {
+                // Override if -s option is specified.
                 installFlags |= PackageManager.INSTALL_EXTERNAL;
             } else {
                 System.err.println("Error: Unknown option: " + opt);
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index f7cb2273..942a303 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -157,13 +157,18 @@
     long numIterationsLeft = gNumRepetitions;
     MediaSource::ReadOptions options;
 
+    int64_t sumDecodeUs = 0;
+
     while (numIterationsLeft-- > 0) {
         long numFrames = 0;
 
         MediaBuffer *buffer;
 
         for (;;) {
+            int64_t startDecodeUs = getNowUs();
             status_t err = rawSource->read(&buffer, &options);
+            int64_t delayDecodeUs = getNowUs() - startDecodeUs;
+
             options.clearSeekTo();
 
             if (err != OK) {
@@ -182,6 +187,8 @@
                 fflush(stdout);
             }
 
+            sumDecodeUs += delayDecodeUs;
+
             buffer->release();
             buffer = NULL;
 
@@ -210,6 +217,8 @@
 
     int64_t delay = getNowUs() - startTime;
     printf("avg. %.2f fps\n", n * 1E6 / delay);
+    printf("avg. time to decode one buffer %.2f usecs\n",
+           (double)sumDecodeUs / n);
 
     printf("decoded a total of %d frame(s).\n", n);
 }
diff --git a/common/java/com/android/common/OperationScheduler.java b/common/java/com/android/common/OperationScheduler.java
index c7b12d3..0c7ca83 100644
--- a/common/java/com/android/common/OperationScheduler.java
+++ b/common/java/com/android/common/OperationScheduler.java
@@ -158,12 +158,35 @@
             time = Math.max(time, moratoriumTimeMillis);
         }
         time = Math.max(time, lastSuccessTimeMillis + options.minTriggerMillis);
-        time = Math.max(time, lastErrorTimeMillis + options.backoffFixedMillis +
-                options.backoffIncrementalMillis * errorCount);
+        if (errorCount > 0) {
+            time = Math.max(time, lastErrorTimeMillis + options.backoffFixedMillis +
+                    options.backoffIncrementalMillis * errorCount);
+        }
         return time;
     }
 
     /**
+     * Return the last time the operation completed.  Does not modify any state.
+     *
+     * @return the wall clock time when {@link #onSuccess()} was last called.
+     */
+    public long getLastSuccessTimeMillis() {
+        return mStorage.getLong(PREFIX + "lastSuccessTimeMillis", 0);
+    }
+
+    /**
+     * Return the last time the operation was attempted.  Does not modify any state.
+     *
+     * @return the wall clock time when {@link #onSuccess()} or {@link
+     * #onTransientError()} was last called.
+     */
+    public long getLastAttemptTimeMillis() {
+        return Math.max(
+                mStorage.getLong(PREFIX + "lastSuccessTimeMillis", 0),
+                mStorage.getLong(PREFIX + "lastErrorTimeMillis", 0));
+    }
+
+    /**
      * Fetch a {@link SharedPreferences} property, but force it to be before
      * a certain time, updating the value if necessary.  This is to recover
      * gracefully from clock rollbacks which could otherwise strand our timers.
@@ -273,9 +296,7 @@
      * where there is reason to hope things might start working better.
      */
     public void resetTransientError() {
-        mStorage.edit()
-                .remove(PREFIX + "lastErrorTimeMillis")
-                .remove(PREFIX + "errorCount").commit();
+        mStorage.edit().remove(PREFIX + "errorCount").commit();
     }
 
     /**
diff --git a/common/tests/src/com/android/common/OperationSchedulerTest.java b/common/tests/src/com/android/common/OperationSchedulerTest.java
index 28178b5..f728eea 100644
--- a/common/tests/src/com/android/common/OperationSchedulerTest.java
+++ b/common/tests/src/com/android/common/OperationSchedulerTest.java
@@ -28,6 +28,8 @@
         OperationScheduler scheduler = new OperationScheduler(storage);
         OperationScheduler.Options options = new OperationScheduler.Options();
         assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
+        assertEquals(0, scheduler.getLastSuccessTimeMillis());
+        assertEquals(0, scheduler.getLastAttemptTimeMillis());
 
         long beforeTrigger = System.currentTimeMillis();
         scheduler.setTriggerTimeMillis(beforeTrigger + 1000000);
@@ -49,6 +51,9 @@
         long beforeError = System.currentTimeMillis();
         scheduler.onTransientError();
         long afterError = System.currentTimeMillis();
+        assertEquals(0, scheduler.getLastSuccessTimeMillis());
+        assertTrue(beforeError <= scheduler.getLastAttemptTimeMillis());
+        assertTrue(afterError >= scheduler.getLastAttemptTimeMillis());
         assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
         options.backoffFixedMillis = 1000000;
         options.backoffIncrementalMillis = 500000;
@@ -59,9 +64,18 @@
         beforeError = System.currentTimeMillis();
         scheduler.onTransientError();
         afterError = System.currentTimeMillis();
+        assertTrue(beforeError <= scheduler.getLastAttemptTimeMillis());
+        assertTrue(afterError >= scheduler.getLastAttemptTimeMillis());
         assertTrue(beforeError + 2000000 <= scheduler.getNextTimeMillis(options));
         assertTrue(afterError + 2000000 >= scheduler.getNextTimeMillis(options));
 
+        // Reset transient error: no backoff interval
+        scheduler.resetTransientError();
+        assertEquals(0, scheduler.getLastSuccessTimeMillis());
+        assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
+        assertTrue(beforeError <= scheduler.getLastAttemptTimeMillis());
+        assertTrue(afterError >= scheduler.getLastAttemptTimeMillis());
+
         // Permanent error holds true even if transient errors are reset
         // However, we remember that the transient error was reset...
         scheduler.onPermanentError();
@@ -75,6 +89,10 @@
         long beforeSuccess = System.currentTimeMillis();
         scheduler.onSuccess();
         long afterSuccess = System.currentTimeMillis();
+        assertTrue(beforeSuccess <= scheduler.getLastAttemptTimeMillis());
+        assertTrue(afterSuccess >= scheduler.getLastAttemptTimeMillis());
+        assertTrue(beforeSuccess <= scheduler.getLastSuccessTimeMillis());
+        assertTrue(afterSuccess >= scheduler.getLastSuccessTimeMillis());
         assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
 
         // The moratorium is not reset by success!
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 4761f98..bf9e07d 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -66,10 +66,10 @@
      * The event types an {@link AccessibilityService} is interested in.
      *
      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED
+     * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_LONG_CLICKED
      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_FOCUSED
      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SELECTED
      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED
-     * @see android.view.accessibility.AccessibilityEvent#TYPE_ACTIVITY_STARTED
      * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED
      * @see android.view.accessibility.AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED
      */
@@ -115,7 +115,7 @@
         return 0;
     }
 
-    public void writeToParcel(Parcel parcel, int flags) {
+    public void writeToParcel(Parcel parcel, int flagz) {
         parcel.writeInt(eventTypes);
         parcel.writeStringArray(packageNames);
         parcel.writeInt(feedbackType);
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index be2bdbe..8bc7428 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -296,8 +296,7 @@
      * <ul>
      * <li> {@link AccountManager#KEY_INTENT}, or
      * <li> {@link AccountManager#KEY_ACCOUNT_NAME} and {@link AccountManager#KEY_ACCOUNT_TYPE} of
-     * the account that was added, plus {@link AccountManager#KEY_AUTHTOKEN} if an authTokenType
-     * was supplied, or
+     * the account that was added, or
      * <li> {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} to
      * indicate an error
      * </ul>
@@ -368,8 +367,7 @@
      * <ul>
      * <li> {@link AccountManager#KEY_INTENT}, or
      * <li> {@link AccountManager#KEY_ACCOUNT_NAME} and {@link AccountManager#KEY_ACCOUNT_TYPE} of
-     * the account that was added, plus {@link AccountManager#KEY_AUTHTOKEN} if an authTokenType
-     * was supplied, or
+     * the account that was added, or
      * <li> {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} to
      * indicate an error
      * </ul>
@@ -378,7 +376,7 @@
      */
     public abstract Bundle updateCredentials(AccountAuthenticatorResponse response,
             Account account, String authTokenType, Bundle options) throws NetworkErrorException;
-    
+
     /**
      * Checks if the account supports all the specified authenticator specific features.
      * @param response to send the result back to the AccountManager, will never be null
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index be15ac9..43a0f30 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -67,6 +67,8 @@
  * cause the running thread to block until the result is returned. Keep in mind that one
  * should not block the main thread in this way. Instead one should either use a callback,
  * thus making the call asynchronous, or make the blocking call on a separate thread.
+ * getResult() will throw an {@link IllegalStateException} if you call it from the main thread
+ * before the request has completed, i.e. before the callback has been invoked.
  * <p>
  * If one wants to ensure that the callback is invoked from a specific handler then they should
  * pass the handler to the request. This makes it easier to ensure thread-safety by running
@@ -149,6 +151,8 @@
      * Get the password that is associated with the account. Returns null if the account does
      * not exist.
      * <p>
+     * It is safe to call this method from the main thread.
+     * <p>
      * Requires that the caller has permission
      * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
      * with the same UID as the Authenticator for the account.
@@ -166,6 +170,8 @@
      * Get the user data named by "key" that is associated with the account.
      * Returns null if the account does not exist or if it does not have a value for key.
      * <p>
+     * It is safe to call this method from the main thread.
+     * <p>
      * Requires that the caller has permission
      * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
      * with the same UID as the Authenticator for the account.
@@ -185,6 +191,8 @@
      * @return an array that contains all the authenticators known to the AccountManager service.
      * This array will be empty if there are no authenticators and will never return null.
      * <p>
+     * It is safe to call this method from the main thread.
+     * <p>
      * No permission is required to make this call.
      */
     public AuthenticatorDescription[] getAuthenticatorTypes() {
@@ -201,6 +209,8 @@
      * @return an array that contains all the accounts known to the AccountManager service.
      * This array will be empty if there are no accounts and will never return null.
      * <p>
+     * It is safe to call this method from the main thread.
+     * <p>
      * Requires that the caller has permission {@link android.Manifest.permission#GET_ACCOUNTS}
      */
     public Account[] getAccounts() {
@@ -219,6 +229,8 @@
      * @return an array that contains the accounts that match the specified type. This array
      * will be empty if no accounts match. It will never return null.
      * <p>
+     * It is safe to call this method from the main thread.
+     * <p>
      * Requires that the caller has permission {@link android.Manifest.permission#GET_ACCOUNTS}
      */
     public Account[] getAccountsByType(String type) {
@@ -243,6 +255,22 @@
      * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
      * which will then block until the request completes.
      * <p>
+     * Do not block the main thread waiting this method's result.
+     * <p>
+     * Not allowed from main thread (but allowed from other threads):
+     * <pre>
+     * Boolean result = hasFeatures(account, features, callback, handler).getResult();
+     * </pre>
+     * Allowed from main thread:
+     * <pre>
+     * hasFeatures(account, features, new AccountManagerCallback<Boolean>() {
+     *    public void run(AccountManagerFuture<Boolean> future) {
+     *        Boolean result = future.getResult();
+     *        // use result
+     *    }
+     * }, handler);
+     * </pre>
+     * <p>
      * Requires that the caller has permission {@link android.Manifest.permission#GET_ACCOUNTS}.
      *
      * @param account The {@link Account} to test
@@ -274,6 +302,8 @@
     /**
      * Add an account to the AccountManager's set of known accounts.
      * <p>
+     * It is safe to call this method from the main thread.
+     * <p>
      * Requires that the caller has permission
      * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
      * with the same UID as the Authenticator for the account.
@@ -304,6 +334,22 @@
      * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
      * which will then block until the request completes.
      * <p>
+     * Do not block the main thread waiting this method's result.
+     * <p>
+     * Not allowed from main thread (but allowed from other threads):
+     * <pre>
+     * Boolean result = removeAccount(account, callback, handler).getResult();
+     * </pre>
+     * Allowed from main thread:
+     * <pre>
+     * removeAccount(account, new AccountManagerCallback<Boolean>() {
+     *    public void run(AccountManagerFuture<Boolean> future) {
+     *        Boolean result = future.getResult();
+     *        // use result
+     *    }
+     * }, handler);
+     * </pre>
+     * <p>
      * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
      *
      * @param account The {@link Account} to remove
@@ -334,6 +380,8 @@
      * Removes the given authtoken. If this authtoken does not exist for the given account type
      * then this call has no effect.
      * <p>
+     * It is safe to call this method from the main thread.
+     * <p>
      * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
      * @param accountType the account type of the authtoken to invalidate
      * @param authToken the authtoken to invalidate
@@ -353,6 +401,8 @@
      * asking the authenticaticor to generate one. If the account or the
      * authtoken do not exist then null is returned.
      * <p>
+     * It is safe to call this method from the main thread.
+     * <p>
      * Requires that the caller has permission
      * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
      * with the same UID as the Authenticator for the account.
@@ -381,6 +431,8 @@
      * Sets the password for the account. The password may be null. If the account does not exist
      * then this call has no affect.
      * <p>
+     * It is safe to call this method from the main thread.
+     * <p>
      * Requires that the caller has permission
      * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
      * with the same UID as the Authenticator for the account.
@@ -404,6 +456,8 @@
      * Sets the password for account to null. If the account does not exist then this call
      * has no effect.
      * <p>
+     * It is safe to call this method from the main thread.
+     * <p>
      * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
      * @param account the account whose password is to be cleared. Must not be null.
      */
@@ -424,6 +478,8 @@
      * Sets account's userdata named "key" to the specified value. If the account does not
      * exist then this call has no effect.
      * <p>
+     * It is safe to call this method from the main thread.
+     * <p>
      * Requires that the caller has permission
      * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
      * with the same UID as the Authenticator for the account.
@@ -452,6 +508,8 @@
      * Sets the authtoken named by "authTokenType" to the value specified by authToken.
      * If the account does not exist then this call has no effect.
      * <p>
+     * It is safe to call this method from the main thread.
+     * <p>
      * Requires that the caller has permission
      * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
      * with the same UID as the Authenticator for the account.
@@ -473,6 +531,8 @@
      * {@link #getAuthToken(Account, String, boolean, AccountManagerCallback, Handler)}
      * then extracts and returns the value of {@link #KEY_AUTHTOKEN} from its result.
      * <p>
+     * It is not safe to call this method from the main thread. See {@link #getAuthToken}.
+     * <p>
      * Requires that the caller has permission {@link android.Manifest.permission#USE_CREDENTIALS}.
      * @param account the account whose authtoken is to be retrieved, must not be null
      * @param authTokenType the type of authtoken to retrieve
@@ -505,9 +565,8 @@
      * in the result.
      * <p>
      * If the authenticator needs to prompt the user for credentials it will return an intent to
-     * the activity that will do the prompting. If an activity is supplied then that activity
-     * will be used to launch the intent and the result will come from it. Otherwise a result will
-     * be returned that contains the intent.
+     * an activity that will do the prompting. The supplied activity will be used to launch the
+     * intent and the result will come from the launched activity.
      * <p>
      * This call returns immediately but runs asynchronously and the result is accessed via the
      * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
@@ -518,6 +577,23 @@
      * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
      * which will then block until the request completes.
      * <p>
+     * Do not block the main thread waiting this method's result.
+     * <p>
+     * Not allowed from main thread (but allowed from other threads):
+     * <pre>
+     * Bundle result = getAuthToken(
+     *   account, authTokenType, options, activity, callback, handler).getResult();
+     * </pre>
+     * Allowed from main thread:
+     * <pre>
+     * getAuthToken(account, authTokenType, options, activity, new AccountManagerCallback<Bundle>() {
+     *    public void run(AccountManagerFuture<Bundle> future) {
+     *        Bundle result = future.getResult();
+     *        // use result
+     *    }
+     * }, handler);
+     * </pre>
+     * <p>
      * Requires that the caller has permission {@link android.Manifest.permission#USE_CREDENTIALS}.
      *
      * @param account The account whose credentials are to be updated.
@@ -525,8 +601,9 @@
      * May be null.
      * @param options authenticator specific options for the request
      * @param activity If the authenticator returns a {@link #KEY_INTENT} in the result then
-     * the intent will be started with this activity. If activity is null then the result will
-     * be returned as-is.
+     * the intent will be started with this activity. If you do not with to have the intent
+     * started automatically then use the other form,
+     * {@link #getAuthToken(Account, String, boolean, AccountManagerCallback, android.os.Handler)}
      * @param callback A callback to invoke when the request completes. If null then
      * no callback is invoked.
      * @param handler The {@link Handler} to use to invoke the callback. If null then the
@@ -578,6 +655,23 @@
      * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
      * which will then block until the request completes.
      * <p>
+     * Do not block the main thread waiting this method's result.
+     * <p>
+     * Not allowed from main thread (but allowed from other threads):
+     * <pre>
+     * Bundle result = getAuthToken(
+     *   account, authTokenType, notifyAuthFailure, callback, handler).getResult();
+     * </pre>
+     * Allowed from main thread:
+     * <pre>
+     * getAuthToken(account, authTokenType, notifyAuthFailure, new AccountManagerCallback<Bundle>() {
+     *    public void run(AccountManagerFuture<Bundle> future) {
+     *        Bundle result = future.getResult();
+     *        // use result
+     *    }
+     * }, handler);
+     * </pre>
+     * <p>
      * Requires that the caller has permission {@link android.Manifest.permission#USE_CREDENTIALS}.
      *
      * @param account The account whose credentials are to be updated.
@@ -625,6 +719,23 @@
      * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
      * which will then block until the request completes.
      * <p>
+     * Do not block the main thread waiting this method's result.
+     * <p>
+     * Not allowed from main thread (but allowed from other threads):
+     * <pre>
+     * Bundle result = addAccount(
+     *   account, authTokenType, features, options, activity, callback, handler).getResult();
+     * </pre>
+     * Allowed from main thread:
+     * <pre>
+     * addAccount(account, authTokenType, features, options, activity, new AccountManagerCallback<Bundle>() {
+     *    public void run(AccountManagerFuture<Bundle> future) {
+     *        Bundle result = future.getResult();
+     *        // use result
+     *    }
+     * }, handler);
+     * </pre>
+     * <p>
      * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
      *
      * @param accountType The type of account to add. This must not be null.
@@ -646,7 +757,6 @@
      * <ul>
      * <li> {@link #KEY_INTENT}, or
      * <li> {@link #KEY_ACCOUNT_NAME}, {@link #KEY_ACCOUNT_TYPE}
-     * and {@link #KEY_AUTHTOKEN} (if an authTokenType was specified).
      * </ul>
      */
     public AccountManagerFuture<Bundle> addAccount(final String accountType,
@@ -667,6 +777,51 @@
         }.start();
     }
 
+    /**
+     * Queries for accounts that match the given account type and feature set.
+     * <p>
+     * This call returns immediately but runs asynchronously and the result is accessed via the
+     * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
+     * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
+     * method asynchronously then they will generally pass in a callback object that will get
+     * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
+     * they will generally pass null for the callback and instead call
+     * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
+     * which will then block until the request completes.
+     * <p>
+     * Do not block the main thread waiting this method's result.
+     * <p>
+     * Not allowed from main thread (but allowed from other threads):
+     * <pre>
+     * Account[] result =
+     *   getAccountsByTypeAndFeatures(accountType, features, callback, handler).getResult();
+     * </pre>
+     * Allowed from main thread:
+     * <pre>
+     * getAccountsByTypeAndFeatures(accountType, features, new AccountManagerCallback<Account[]>() {
+     *    public void run(AccountManagerFuture<Account[]> future) {
+     *         Account[] result = future.getResult();
+     *        // use result
+     *    }
+     * }, handler);
+     * </pre>
+     * <p>
+     * Requires that the caller has permission {@link android.Manifest.permission#GET_ACCOUNTS}.
+     *
+     * @param type The type of {@link Account} to return. If null is passed in then an empty
+     * array will be returned.
+     * @param features the features with which to filter the accounts list. Each returned account
+     * will have all specified features. This may be null, which will mean the account list will
+     * not be filtered by features, making this functionally identical to
+     * {@link #getAccountsByType(String)}.
+     * @param callback A callback to invoke when the request completes. If null then
+     * no callback is invoked.
+     * @param handler The {@link Handler} to use to invoke the callback. If null then the
+     * main thread's {@link Handler} is used.
+     * @return an {@link AccountManagerFuture} that represents the future result of the call.
+     * The future result is a an {@link Account} array that contains accounts of the specified
+     * type that match all the requested features.
+     */
     public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
             final String type, final String[] features,
             AccountManagerCallback<Account[]> callback, Handler handler) {
@@ -709,6 +864,23 @@
      * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
      * which will then block until the request completes.
      * <p>
+     * Do not block the main thread waiting this method's result.
+     * <p>
+     * Not allowed from main thread (but allowed from other threads):
+     * <pre>
+     * Bundle result = confirmCredentials(
+     *   account, options, activity, callback, handler).getResult();
+     * </pre>
+     * Allowed from main thread:
+     * <pre>
+     * confirmCredentials(account, options, activity, new AccountManagerCallback<Bundle>() {
+     *    public void run(AccountManagerFuture<Bundle> future) {
+     *        Bundle result = future.getResult();
+     *        // use result
+     *    }
+     * }, handler);
+     * </pre>
+     * <p>
      * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
      *
      * @param account The account whose credentials are to be checked
@@ -757,6 +929,23 @@
      * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
      * which will then block until the request completes.
      * <p>
+     * Do not block the main thread waiting this method's result.
+     * <p>
+     * Not allowed from main thread (but allowed from other threads):
+     * <pre>
+     * Bundle result = updateCredentials(
+     *   account, authTokenType, options, activity, callback, handler).getResult();
+     * </pre>
+     * Allowed from main thread:
+     * <pre>
+     * updateCredentials(account, authTokenType, options, activity, new AccountManagerCallback<Bundle>() {
+     *    public void run(AccountManagerFuture<Bundle> future) {
+     *        Bundle result = future.getResult();
+     *        // use result
+     *    }
+     * }, handler);
+     * </pre>
+     * <p>
      * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
      *
      * @param account The account whose credentials are to be updated.
@@ -775,7 +964,7 @@
      * <ul>
      * <li> {@link #KEY_INTENT}, which is to be used to prompt the user for the credentials
      * <li> {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE} if the user enters the correct
-     * credentials, and optionally a {@link #KEY_AUTHTOKEN} if an authTokenType was provided.
+     * credentials.
      * </ul>
      * If the user presses "back" then the request will be canceled.
      */
@@ -807,6 +996,22 @@
      * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
      * which will then block until the request completes.
      * <p>
+     * Do not block the main thread waiting this method's result.
+     * <p>
+     * Not allowed from main thread (but allowed from other threads):
+     * <pre>
+     * Bundle result = editProperties(accountType, activity, callback, handler).getResult();
+     * </pre>
+     * Allowed from main thread:
+     * <pre>
+     * editProperties(accountType, activity, new AccountManagerCallback<Bundle>() {
+     *    public void run(AccountManagerFuture<Bundle> future) {
+     *        Bundle result = future.getResult();
+     *        // use result
+     *    }
+     * }, handler);
+     * </pre>
+     * <p>
      * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
      *
      * @param accountType The account type of the authenticator whose properties are to be edited.
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 7850124..770554e 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -466,7 +466,8 @@
 
         public TestFeaturesSession(IAccountManagerResponse response,
                 Account account, String[] features) {
-            super(response, account.type, false /* expectActivityLaunch */);
+            super(response, account.type, false /* expectActivityLaunch */,
+                    true /* stripAuthTokenFromResult */);
             mFeatures = features;
             mAccount = account;
         }
@@ -520,7 +521,8 @@
     private class RemoveAccountSession extends Session {
         final Account mAccount;
         public RemoveAccountSession(IAccountManagerResponse response, Account account) {
-            super(response, account.type, false /* expectActivityLaunch */);
+            super(response, account.type, false /* expectActivityLaunch */,
+                    true /* stripAuthTokenFromResult */);
             mAccount = account;
         }
 
@@ -794,7 +796,8 @@
                 }
             }
 
-            new Session(response, account.type, expectActivityLaunch) {
+            new Session(response, account.type, expectActivityLaunch,
+                    false /* stripAuthTokenFromResult */) {
                 protected String toDebugString(long now) {
                     if (loginOptions != null) loginOptions.keySet();
                     return super.toDebugString(now) + ", getAuthToken"
@@ -945,7 +948,8 @@
         checkManageAccountsPermission();
         long identityToken = clearCallingIdentity();
         try {
-            new Session(response, accountType, expectActivityLaunch) {
+            new Session(response, accountType, expectActivityLaunch,
+                    true /* stripAuthTokenFromResult */) {
                 public void run() throws RemoteException {
                     mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
                             options);
@@ -970,7 +974,8 @@
         checkManageAccountsPermission();
         long identityToken = clearCallingIdentity();
         try {
-            new Session(response, account.type, expectActivityLaunch) {
+            new Session(response, account.type, expectActivityLaunch,
+                    true /* stripAuthTokenFromResult */) {
                 public void run() throws RemoteException {
                     mAuthenticator.confirmCredentials(this, account, options);
                 }
@@ -990,7 +995,8 @@
         checkManageAccountsPermission();
         long identityToken = clearCallingIdentity();
         try {
-            new Session(response, account.type, expectActivityLaunch) {
+            new Session(response, account.type, expectActivityLaunch,
+                    true /* stripAuthTokenFromResult */) {
                 public void run() throws RemoteException {
                     mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
                 }
@@ -1012,7 +1018,8 @@
         checkManageAccountsPermission();
         long identityToken = clearCallingIdentity();
         try {
-            new Session(response, accountType, expectActivityLaunch) {
+            new Session(response, accountType, expectActivityLaunch,
+                    true /* stripAuthTokenFromResult */) {
                 public void run() throws RemoteException {
                     mAuthenticator.editProperties(this, mAccountType);
                 }
@@ -1034,7 +1041,8 @@
 
         public GetAccountsByTypeAndFeatureSession(IAccountManagerResponse response,
             String type, String[] features) {
-            super(response, type, false /* expectActivityLaunch */);
+            super(response, type, false /* expectActivityLaunch */,
+                    true /* stripAuthTokenFromResult */);
             mFeatures = features;
         }
 
@@ -1176,11 +1184,14 @@
 
         IAccountAuthenticator mAuthenticator = null;
 
+        private final boolean mStripAuthTokenFromResult;
+
         public Session(IAccountManagerResponse response, String accountType,
-                boolean expectActivityLaunch) {
+                boolean expectActivityLaunch, boolean stripAuthTokenFromResult) {
             super();
             if (response == null) throw new IllegalArgumentException("response is null");
             if (accountType == null) throw new IllegalArgumentException("accountType is null");
+            mStripAuthTokenFromResult = stripAuthTokenFromResult;
             mResponse = response;
             mAccountType = accountType;
             mExpectActivityLaunch = expectActivityLaunch;
@@ -1319,6 +1330,9 @@
                         response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
                                 "null bundle returned");
                     } else {
+                        if (mStripAuthTokenFromResult) {
+                            result.remove(AccountManager.KEY_AUTHTOKEN);
+                        }
                         response.onResult(result);
                     }
                 } catch (RemoteException e) {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 56e44c8..13cc3ba 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1392,7 +1392,7 @@
             r.startsNotResumed = notResumed;
             r.createdConfig = config;
 
-            synchronized (mRelaunchingActivities) {
+            synchronized (mPackages) {
                 mRelaunchingActivities.add(r);
             }
 
@@ -1523,8 +1523,11 @@
         }
 
         public void scheduleConfigurationChanged(Configuration config) {
-            synchronized (mRelaunchingActivities) {
-                mPendingConfiguration = config;
+            synchronized (mPackages) {
+                if (mPendingConfiguration == null ||
+                        mPendingConfiguration.isOtherSeqNewer(config)) {
+                    mPendingConfiguration = config;
+                }
             }
             queueOrSendMessage(H.CONFIGURATION_CHANGED, config);
         }
@@ -2060,6 +2063,7 @@
             = new HashMap<IBinder, Service>();
     AppBindData mBoundApplication;
     Configuration mConfiguration;
+    Configuration mResConfiguration;
     Application mInitialApplication;
     final ArrayList<Application> mAllApplications
             = new ArrayList<Application>();
@@ -2073,14 +2077,6 @@
     boolean mSystemThread = false;
     boolean mJitEnabled = false;
 
-    /**
-     * Activities that are enqueued to be relaunched.  This list is accessed
-     * by multiple threads, so you must synchronize on it when accessing it.
-     */
-    final ArrayList<ActivityRecord> mRelaunchingActivities
-            = new ArrayList<ActivityRecord>();
-    Configuration mPendingConfiguration = null;
-
     // These can be accessed by multiple threads; mPackages is the lock.
     // XXX For now we keep around information about all packages we have
     // seen, not removing entries from this map.
@@ -2092,6 +2088,9 @@
     DisplayMetrics mDisplayMetrics = null;
     HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources
         = new HashMap<ResourcesKey, WeakReference<Resources> >();
+    final ArrayList<ActivityRecord> mRelaunchingActivities
+            = new ArrayList<ActivityRecord>();
+        Configuration mPendingConfiguration = null;
 
     // The lock of mProviderMap protects the following variables.
     final HashMap<String, ProviderRecord> mProviderMap
@@ -3555,7 +3554,7 @@
         // First: make sure we have the most recent configuration and most
         // recent version of the activity, or skip it if some previous call
         // had taken a more recent version.
-        synchronized (mRelaunchingActivities) {
+        synchronized (mPackages) {
             int N = mRelaunchingActivities.size();
             IBinder token = tmp.token;
             tmp = null;
@@ -3585,8 +3584,12 @@
             // assume that is really what we want regardless of what we
             // may have pending.
             if (mConfiguration == null
-                    || mConfiguration.diff(tmp.createdConfig) != 0) {
-                changedConfig = tmp.createdConfig;
+                    || (tmp.createdConfig.isOtherSeqNewer(mConfiguration)
+                            && mConfiguration.diff(tmp.createdConfig) != 0)) {
+                if (changedConfig == null
+                        || tmp.createdConfig.isOtherSeqNewer(changedConfig)) {
+                    changedConfig = tmp.createdConfig;
+                }
             }
         }
         
@@ -3761,62 +3764,81 @@
         }
     }
 
-    final void handleConfigurationChanged(Configuration config) {
+    final void applyConfigurationToResourcesLocked(Configuration config) {
+        if (mResConfiguration == null) {
+            mResConfiguration = new Configuration();
+        }
+        if (!mResConfiguration.isOtherSeqNewer(config)) {
+            return;
+        }
+        mResConfiguration.updateFrom(config);
+        DisplayMetrics dm = getDisplayMetricsLocked(true);
 
-        synchronized (mRelaunchingActivities) {
-            if (mPendingConfiguration != null) {
-                config = mPendingConfiguration;
-                mPendingConfiguration = null;
-            }
+        // set it for java, this also affects newly created Resources
+        if (config.locale != null) {
+            Locale.setDefault(config.locale);
         }
 
-        ArrayList<ComponentCallbacks> callbacks
-                = new ArrayList<ComponentCallbacks>();
+        Resources.updateSystemConfiguration(config, dm);
 
-        if (DEBUG_CONFIGURATION) Log.v(TAG, "Handle configuration changed: "
-                + config);
+        ContextImpl.ApplicationPackageManager.configurationChanged();
+        //Log.i(TAG, "Configuration changed in " + currentPackageName());
         
-        synchronized(mPackages) {
+        Iterator<WeakReference<Resources>> it =
+            mActiveResources.values().iterator();
+        //Iterator<Map.Entry<String, WeakReference<Resources>>> it =
+        //    mActiveResources.entrySet().iterator();
+        while (it.hasNext()) {
+            WeakReference<Resources> v = it.next();
+            Resources r = v.get();
+            if (r != null) {
+                r.updateConfiguration(config, dm);
+                //Log.i(TAG, "Updated app resources " + v.getKey()
+                //        + " " + r + ": " + r.getConfiguration());
+            } else {
+                //Log.i(TAG, "Removing old resources " + v.getKey());
+                it.remove();
+            }
+        }
+    }
+    
+    final void handleConfigurationChanged(Configuration config) {
+
+        ArrayList<ComponentCallbacks> callbacks = null;
+
+        synchronized (mPackages) {
+            if (mPendingConfiguration != null) {
+                if (!mPendingConfiguration.isOtherSeqNewer(config)) {
+                    config = mPendingConfiguration;
+                }
+                mPendingConfiguration = null;
+            }
+
+            if (config == null) {
+                return;
+            }
+            
+            if (DEBUG_CONFIGURATION) Log.v(TAG, "Handle configuration changed: "
+                    + config);
+        
+            applyConfigurationToResourcesLocked(config);
+            
             if (mConfiguration == null) {
                 mConfiguration = new Configuration();
             }
+            if (!mConfiguration.isOtherSeqNewer(config)) {
+                return;
+            }
             mConfiguration.updateFrom(config);
-            DisplayMetrics dm = getDisplayMetricsLocked(true);
-
-            // set it for java, this also affects newly created Resources
-            if (config.locale != null) {
-                Locale.setDefault(config.locale);
-            }
-
-            Resources.updateSystemConfiguration(config, dm);
-
-            ContextImpl.ApplicationPackageManager.configurationChanged();
-            //Log.i(TAG, "Configuration changed in " + currentPackageName());
-            {
-                Iterator<WeakReference<Resources>> it =
-                    mActiveResources.values().iterator();
-                //Iterator<Map.Entry<String, WeakReference<Resources>>> it =
-                //    mActiveResources.entrySet().iterator();
-                while (it.hasNext()) {
-                    WeakReference<Resources> v = it.next();
-                    Resources r = v.get();
-                    if (r != null) {
-                        r.updateConfiguration(config, dm);
-                        //Log.i(TAG, "Updated app resources " + v.getKey()
-                        //        + " " + r + ": " + r.getConfiguration());
-                    } else {
-                        //Log.i(TAG, "Removing old resources " + v.getKey());
-                        it.remove();
-                    }
-                }
-            }
 
             callbacks = collectComponentCallbacksLocked(false, config);
         }
 
-        final int N = callbacks.size();
-        for (int i=0; i<N; i++) {
-            performConfigurationChanged(callbacks.get(i), config);
+        if (callbacks != null) {
+            final int N = callbacks.size();
+            for (int i=0; i<N; i++) {
+                performConfigurationChanged(callbacks.get(i), config);
+            }
         }
     }
 
@@ -3856,7 +3878,7 @@
         ArrayList<ComponentCallbacks> callbacks
                 = new ArrayList<ComponentCallbacks>();
 
-        synchronized(mPackages) {
+        synchronized (mPackages) {
             callbacks = collectComponentCallbacksLocked(true, null);
         }
 
@@ -4348,6 +4370,25 @@
                         "Unable to instantiate Application():" + e.toString(), e);
             }
         }
+        
+        ViewRoot.addConfigCallback(new ComponentCallbacks() {
+            public void onConfigurationChanged(Configuration newConfig) {
+                synchronized (mPackages) {
+                    if (mPendingConfiguration == null ||
+                            mPendingConfiguration.isOtherSeqNewer(newConfig)) {
+                        mPendingConfiguration = newConfig;
+                        
+                        // We need to apply this change to the resources
+                        // immediately, because upon returning the view
+                        // hierarchy will be informed about it.
+                        applyConfigurationToResourcesLocked(newConfig);
+                    }
+                }
+                queueOrSendMessage(H.CONFIGURATION_CHANGED, newConfig);
+            }
+            public void onLowMemory() {
+            }
+        });
     }
 
     private final void detach()
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index db6a4bf..1d004ee 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -42,6 +42,7 @@
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.IPackageInstallObserver;
+import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageManager;
 import android.content.pm.IPackageStatsObserver;
 import android.content.pm.InstrumentationInfo;
@@ -2489,6 +2490,15 @@
         }
 
         @Override
+        public void movePackage(String packageName, IPackageMoveObserver observer, int flags) {
+            try {
+                mPM.movePackage(packageName, observer, flags);
+            } catch (RemoteException e) {
+                // Should never happen!
+            }
+        }
+
+        @Override
         public String getInstallerPackageName(String packageName) {
             try {
                 return mPM.getInstallerPackageName(packageName);
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index ed38240..4598bb5 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -822,11 +822,6 @@
         final SearchManager searchManager = (SearchManager) mContext
                 .getSystemService(Context.SEARCH_SERVICE);
 
-        // can't start search without an associated activity (e.g a system dialog)
-        if (!searchManager.hasIdent()) {
-            return false;
-        }
-
         // associate search with owner activity if possible (otherwise it will default to
         // global search).
         final ComponentName appName = getAssociatedActivity();
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index e4c1ba6..581b436 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -16,6 +16,9 @@
 
 package android.app;
 
+import com.android.common.Patterns;
+import com.android.common.speech.Recognition;
+
 import static android.app.SuggestionsAdapter.getColumnString;
 
 import android.content.ActivityNotFoundException;
@@ -67,9 +70,6 @@
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AdapterView.OnItemSelectedListener;
 
-import com.android.common.Patterns;
-import com.android.common.speech.Recognition;
-
 import java.util.ArrayList;
 import java.util.WeakHashMap;
 import java.util.concurrent.atomic.AtomicLong;
@@ -89,10 +89,7 @@
 
     private static final String INSTANCE_KEY_COMPONENT = "comp";
     private static final String INSTANCE_KEY_APPDATA = "data";
-    private static final String INSTANCE_KEY_GLOBALSEARCH = "glob";
-    private static final String INSTANCE_KEY_STORED_COMPONENT = "sComp";
     private static final String INSTANCE_KEY_STORED_APPDATA = "sData";
-    private static final String INSTANCE_KEY_PREVIOUS_COMPONENTS = "sPrev";
     private static final String INSTANCE_KEY_USER_QUERY = "uQry";
     
     // The string used for privateImeOptions to identify to the IME that it should not show
@@ -115,19 +112,8 @@
     private SearchableInfo mSearchable;
     private ComponentName mLaunchComponent;
     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;
-    private Bundle mStoredAppSearchData;
-    
-    // stack of previous searchables, to support the BACK key after
-    // SearchManager.INTENT_ACTION_CHANGE_SEARCH_SOURCE.
-    // The top of the stack (= previous searchable) is the last element of the list,
-    // since adding and removing is efficient at the end of an ArrayList.
-    private ArrayList<ComponentName> mPreviousComponents;
 
     // For voice searching
     private final Intent mVoiceWebSearchIntent;
@@ -158,7 +144,7 @@
      * @param context Application Context we can use for system acess
      */
     public SearchDialog(Context context, SearchManager searchManager) {
-        super(context, com.android.internal.R.style.Theme_GlobalSearchBar);
+        super(context, com.android.internal.R.style.Theme_SearchBar);
 
         // Save voice intent for later queries/launching
         mVoiceWebSearchIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
@@ -241,14 +227,8 @@
      * @return true if search dialog launched, false if not
      */
     public boolean show(String initialQuery, boolean selectInitialQuery,
-            ComponentName componentName, Bundle appSearchData, boolean globalSearch) {
-
-        // Reset any stored values from last time dialog was shown.
-        mStoredComponentName = null;
-        mStoredAppSearchData = null;
-
-        boolean success = doShow(initialQuery, selectInitialQuery, componentName, appSearchData,
-                globalSearch);
+            ComponentName componentName, Bundle appSearchData) {
+        boolean success = doShow(initialQuery, selectInitialQuery, componentName, appSearchData);
         if (success) {
             // Display the drop down as soon as possible instead of waiting for the rest of the
             // pending UI stuff to get done, so that things appear faster to the user.
@@ -257,67 +237,16 @@
         return success;
     }
 
-    private boolean isInRealAppSearch() {
-        return !mGlobalSearchMode
-                && (mPreviousComponents == null || mPreviousComponents.isEmpty());
-    }
-
     /**
-     * Called in response to a press of the hard search button in
-     * {@link #onKeyDown(int, KeyEvent)}, this method toggles between in-app
-     * search and global search when relevant.
-     * 
-     * If pressed within an in-app search context, this switches the search dialog out to
-     * global search. If pressed within a global search context that was originally an in-app
-     * search context, this switches back to the in-app search context. If pressed within a
-     * global search context that has no original in-app search context (e.g., global search
-     * from Home), this does nothing.
-     * 
-     * @return false if we wanted to toggle context but could not do so successfully, true
-     * in all other cases
-     */
-    private boolean toggleGlobalSearch() {
-        String currentSearchText = mSearchAutoComplete.getText().toString();
-        if (!mGlobalSearchMode) {
-            mStoredComponentName = mLaunchComponent;
-            mStoredAppSearchData = mAppSearchData;
-            
-            // If this is the browser, we have a special case to not show the icon to the left
-            // of the text field, for extra space for url entry (this should be reconciled in
-            // Eclair). So special case a second tap of the search button to remove any
-            // already-entered text so that we can be sure to show the "Quick Search Box" hint
-            // text to still make it clear to the user that we've jumped out to global search.
-            //
-            // TODO: When the browser icon issue is reconciled in Eclair, remove this special case.
-            if (isBrowserSearch()) currentSearchText = "";
-
-            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
-                // global search.
-                return doShow(currentSearchText, false, mStoredComponentName,
-                        mStoredAppSearchData, false);
-            } else {
-                return true;
-            }
-        }
-    }
-    
-    /**
-     * Does the rest of the work required to show the search dialog. Called by both
-     * {@link #show(String, boolean, ComponentName, Bundle, boolean)} and
-     * {@link #toggleGlobalSearch()}.
-     * 
+     * Does the rest of the work required to show the search dialog. Called by
+     * {@link #show(String, boolean, ComponentName, Bundle)} and
+     *
      * @return true if search dialog showed, false if not
      */
     private boolean doShow(String initialQuery, boolean selectInitialQuery,
-            ComponentName componentName, Bundle appSearchData,
-            boolean globalSearch) {
+            ComponentName componentName, Bundle appSearchData) {
         // set up the searchable and show the dialog
-        if (!show(componentName, appSearchData, globalSearch)) {
+        if (!show(componentName, appSearchData)) {
             return false;
         }
 
@@ -335,38 +264,24 @@
      * 
      * @return <code>true</code> if search dialog launched
      */
-    private boolean show(ComponentName componentName, Bundle appSearchData, 
-            boolean globalSearch) {
+    private boolean show(ComponentName componentName, Bundle appSearchData) {
         
         if (DBG) { 
             Log.d(LOG_TAG, "show(" + componentName + ", " 
-                    + appSearchData + ", " + globalSearch + ")");
+                    + appSearchData + ")");
         }
         
         SearchManager searchManager = (SearchManager)
                 mContext.getSystemService(Context.SEARCH_SERVICE);
-        // Try to get the searchable info for the provided component (or for global search,
-        // if globalSearch == true).
-        mSearchable = searchManager.getSearchableInfo(componentName, globalSearch);
-        
-        // If we got back nothing, and it wasn't a request for global search, then try again
-        // for global search, as we'll try to launch that in lieu of any component-specific search.
-        if (!globalSearch && mSearchable == null) {
-            globalSearch = true;
-            mSearchable = searchManager.getSearchableInfo(componentName, globalSearch);
-        }
+        // Try to get the searchable info for the provided component.
+        mSearchable = searchManager.getSearchableInfo(componentName, false);
 
-        // If there's not even a searchable info available for global search, then really give up.
         if (mSearchable == null) {
-            Log.w(LOG_TAG, "No global search provider.");
             return false;
         }
 
         mLaunchComponent = componentName;
         mAppSearchData = appSearchData;
-        // Using globalSearch here is just an optimization, just calling
-        // isDefaultSearchable() should always give the same result.
-        mGlobalSearchMode = globalSearch || searchManager.isDefaultSearchable(mSearchable);
         mActivityContext = mSearchable.getActivityContext(getContext());
 
         // show the dialog. this will call onStart().
@@ -375,20 +290,6 @@
             // of any bad state in the AutoCompleteTextView etc
             createContentView();
 
-            // The Dialog uses a ContextThemeWrapper for the context; use this to change the
-            // theme out from underneath us, between the global search theme and the in-app
-            // search theme. They are identical except that the global search theme does not
-            // dim the background of the window (because global search is full screen so it's
-            // not needed and this should save a little bit of time on global search invocation).
-            Object context = getContext();
-            if (context instanceof ContextThemeWrapper) {
-                ContextThemeWrapper wrapper = (ContextThemeWrapper) context;
-                if (globalSearch) {
-                    wrapper.setTheme(com.android.internal.R.style.Theme_GlobalSearchBar);
-                } else {
-                    wrapper.setTheme(com.android.internal.R.style.Theme_SearchBar);
-                }
-            }
             show();
         }
         updateUI();
@@ -414,7 +315,6 @@
         mSearchable = null;
         mActivityContext = null;
         mUserQuery = null;
-        mPreviousComponents = null;
     }
 
     /**
@@ -428,7 +328,7 @@
         mWorkingSpinner.setVisible(working, false);
         mWorkingSpinner.invalidateSelf();
     }
-    
+
     /**
      * Closes and gets rid of the suggestions adapter.
      */
@@ -442,7 +342,7 @@
         }
         mSuggestionsAdapter = null;
     }
-    
+
     /**
      * Save the minimal set of data necessary to recreate the search
      * 
@@ -458,10 +358,6 @@
         // setup info so I can recreate this particular search       
         bundle.putParcelable(INSTANCE_KEY_COMPONENT, mLaunchComponent);
         bundle.putBundle(INSTANCE_KEY_APPDATA, mAppSearchData);
-        bundle.putBoolean(INSTANCE_KEY_GLOBALSEARCH, mGlobalSearchMode);
-        bundle.putParcelable(INSTANCE_KEY_STORED_COMPONENT, mStoredComponentName);
-        bundle.putBundle(INSTANCE_KEY_STORED_APPDATA, mStoredAppSearchData);
-        bundle.putParcelableArrayList(INSTANCE_KEY_PREVIOUS_COMPONENTS, mPreviousComponents);
         bundle.putString(INSTANCE_KEY_USER_QUERY, mUserQuery);
 
         return bundle;
@@ -481,22 +377,10 @@
 
         ComponentName launchComponent = savedInstanceState.getParcelable(INSTANCE_KEY_COMPONENT);
         Bundle appSearchData = savedInstanceState.getBundle(INSTANCE_KEY_APPDATA);
-        boolean globalSearch = savedInstanceState.getBoolean(INSTANCE_KEY_GLOBALSEARCH);
-        ComponentName storedComponentName =
-                savedInstanceState.getParcelable(INSTANCE_KEY_STORED_COMPONENT);
-        Bundle storedAppSearchData =
-                savedInstanceState.getBundle(INSTANCE_KEY_STORED_APPDATA);
-        ArrayList<ComponentName> previousComponents =
-                savedInstanceState.getParcelableArrayList(INSTANCE_KEY_PREVIOUS_COMPONENTS);
         String userQuery = savedInstanceState.getString(INSTANCE_KEY_USER_QUERY);
 
-        // Set stored state
-        mStoredComponentName = storedComponentName;
-        mStoredAppSearchData = storedAppSearchData;
-        mPreviousComponents = previousComponents;
-
         // show the dialog.
-        if (!doShow(userQuery, false, launchComponent, appSearchData, globalSearch)) {
+        if (!doShow(userQuery, false, launchComponent, appSearchData)) {
             // for some reason, we couldn't re-instantiate
             return;
         }
@@ -506,7 +390,7 @@
      * Called after resources have changed, e.g. after screen rotation or locale change.
      */
     public void onConfigurationChanged() {
-        if (isShowing()) {
+        if (mSearchable != null && isShowing()) {
             // Redraw (resources may have changed)
             updateSearchButton();
             updateSearchAppIcon();
@@ -571,19 +455,13 @@
         // we dismiss the entire dialog instead
         mSearchAutoComplete.setDropDownDismissedOnCompletion(false);
 
-        if (!isInRealAppSearch()) {
-            mSearchAutoComplete.setDropDownAlwaysVisible(true);  // fill space until results come in
-        } else {
-            mSearchAutoComplete.setDropDownAlwaysVisible(false);
-        }
-
         mSearchAutoComplete.setForceIgnoreOutsideTouch(true);
 
         // attach the suggestions adapter, if suggestions are available
         // The existence of a suggestions authority is the proxy for "suggestions available here"
         if (mSearchable.getSuggestAuthority() != null) {
             mSuggestionsAdapter = new SuggestionsAdapter(getContext(), this, mSearchable, 
-                    mOutsideDrawablesCache, mGlobalSearchMode);
+                    mOutsideDrawablesCache);
             mSearchAutoComplete.setAdapter(mSuggestionsAdapter);
         }
     }
@@ -611,7 +489,7 @@
         // global search, for extra space for url entry.
         //
         // TODO: Remove this special case once the issue has been reconciled in Eclair. 
-        if (mGlobalSearchMode || isBrowserSearch()) {
+        if (isBrowserSearch()) {
             mAppIcon.setImageResource(0);
             mAppIcon.setVisibility(View.GONE);
             mSearchPlate.setPadding(SEARCH_PLATE_LEFT_PADDING_GLOBAL,
@@ -705,15 +583,13 @@
     
     /**
      * Hack to determine whether this is the browser, so we can remove the browser icon
-     * to the left of the search field, as a special requirement for Donut.
-     * 
-     * TODO: For Eclair, reconcile this with the rest of the global search UI.
+     * to the left of the search field.
      */
     private boolean isBrowserSearch() {
         return mLaunchComponent.flattenToShortString().startsWith("com.android.browser/");
     }
 
-    /**
+    /*
      * Listeners of various types
      */
 
@@ -769,7 +645,7 @@
 
         return super.onKeyDown(keyCode, event);
     }
-    
+
     /**
      * Callback to watch the textedit field for empty/non-empty
      */
@@ -799,12 +675,8 @@
             if (mSearchable.autoUrlDetect() && !mSearchAutoComplete.isPerformingCompletion()) {
                 // The user changed the query, check if it is a URL and if so change the search
                 // button in the soft keyboard to the 'Go' button.
-                int options = (mSearchAutoComplete.getImeOptions() & (~EditorInfo.IME_MASK_ACTION));
-                if (Patterns.WEB_URL.matcher(mUserQuery).matches()) {
-                    options = options | EditorInfo.IME_ACTION_GO;
-                } else {
-                    options = options | EditorInfo.IME_ACTION_SEARCH;
-                }
+                int options = (mSearchAutoComplete.getImeOptions() & (~EditorInfo.IME_MASK_ACTION))
+                        | EditorInfo.IME_ACTION_GO;
                 if (options != mSearchAutoCompleteImeOptions) {
                     mSearchAutoCompleteImeOptions = options;
                     mSearchAutoComplete.setImeOptions(options);
@@ -881,7 +753,8 @@
                 if (searchable.getVoiceSearchLaunchWebSearch()) {
                     getContext().startActivity(mVoiceWebSearchIntent);
                 } else if (searchable.getVoiceSearchLaunchRecognizer()) {
-                    Intent appSearchIntent = createVoiceAppSearchIntent(mVoiceAppSearchIntent);                    
+                    Intent appSearchIntent = createVoiceAppSearchIntent(mVoiceAppSearchIntent,
+                            searchable);
                     getContext().startActivity(appSearchIntent);
                 }
             } catch (ActivityNotFoundException e) {
@@ -899,8 +772,8 @@
      * @param baseIntent The voice app search intent to start from
      * @return A completely-configured intent ready to send to the voice search activity
      */
-    private Intent createVoiceAppSearchIntent(Intent baseIntent) {
-        ComponentName searchActivity = mSearchable.getSearchActivity();
+    private Intent createVoiceAppSearchIntent(Intent baseIntent, SearchableInfo searchable) {
+        ComponentName searchActivity = searchable.getSearchActivity();
         
         // create the necessary intent to set up a search-and-forward operation
         // in the voice search system.   We have to keep the bundle separate,
@@ -930,17 +803,17 @@
         String language = null;
         int maxResults = 1;
         Resources resources = mActivityContext.getResources();
-        if (mSearchable.getVoiceLanguageModeId() != 0) {
-            languageModel = resources.getString(mSearchable.getVoiceLanguageModeId());
+        if (searchable.getVoiceLanguageModeId() != 0) {
+            languageModel = resources.getString(searchable.getVoiceLanguageModeId());
         }
-        if (mSearchable.getVoicePromptTextId() != 0) {
-            prompt = resources.getString(mSearchable.getVoicePromptTextId());
+        if (searchable.getVoicePromptTextId() != 0) {
+            prompt = resources.getString(searchable.getVoicePromptTextId());
         }
-        if (mSearchable.getVoiceLanguageId() != 0) {
-            language = resources.getString(mSearchable.getVoiceLanguageId());
+        if (searchable.getVoiceLanguageId() != 0) {
+            language = resources.getString(searchable.getVoiceLanguageId());
         }
-        if (mSearchable.getVoiceMaxResults() != 0) {
-            maxResults = mSearchable.getVoiceMaxResults();
+        if (searchable.getVoiceMaxResults() != 0) {
+            maxResults = searchable.getVoiceMaxResults();
         }
         voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, languageModel);
         voiceIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, prompt);
@@ -1140,14 +1013,9 @@
      */
     protected void launchQuerySearch(int actionKey, String actionMsg)  {
         String query = mSearchAutoComplete.getText().toString();
-        String action = mGlobalSearchMode ? Intent.ACTION_WEB_SEARCH : Intent.ACTION_SEARCH;
+        String action = Intent.ACTION_SEARCH;
         Intent intent = createIntent(action, null, null, query, null,
-                actionKey, actionMsg, null);
-        // Allow GlobalSearch to log and create shortcut for searches launched by
-        // the search button, enter key or an action key.
-        if (mGlobalSearchMode) {
-            mSuggestionsAdapter.reportSearch(query);
-        }
+                actionKey, actionMsg);
         launchIntent(intent);
     }
     
@@ -1160,7 +1028,7 @@
     protected boolean launchSuggestion(int position) {
         return launchSuggestion(position, KeyEvent.KEYCODE_UNKNOWN, null);
     }
-    
+
     /**
      * Launches an intent based on a suggestion.
      * 
@@ -1177,20 +1045,7 @@
 
             Intent intent = createIntentFromSuggestion(c, actionKey, actionMsg);
 
-            // report back about the click
-            if (mGlobalSearchMode) {
-                // in global search mode, do it via cursor
-                mSuggestionsAdapter.callCursorOnClick(c, position, actionKey, actionMsg);
-            } else if (intent != null
-                    && mPreviousComponents != null
-                    && !mPreviousComponents.isEmpty()) {
-                // in-app search (and we have pivoted in as told by mPreviousComponents,
-                // which is used for keeping track of what we pop back to when we are pivoting into
-                // in app search.)
-                reportInAppClickToGlobalSearch(c, intent);
-            }
-
-            // launch the intent
+           // launch the intent
             launchIntent(intent);
 
             return true;
@@ -1199,163 +1054,28 @@
     }
 
     /**
-     * Report a click from an in app search result back to global search for shortcutting porpoises.
-     *
-     * @param c The cursor that is pointing to the clicked position.
-     * @param intent The intent that will be launched for the click.
-     */
-    private void reportInAppClickToGlobalSearch(Cursor c, Intent intent) {
-        // for in app search, still tell global search via content provider
-        Uri uri = getClickReportingUri();
-        final ContentValues cv = new ContentValues();
-        cv.put(SearchManager.SEARCH_CLICK_REPORT_COLUMN_QUERY, mUserQuery);
-        final ComponentName source = mSearchable.getSearchActivity();
-        cv.put(SearchManager.SEARCH_CLICK_REPORT_COLUMN_COMPONENT, source.flattenToShortString());
-
-        // grab the intent columns from the intent we created since it has additional
-        // logic for falling back on the searchable default
-        cv.put(SearchManager.SUGGEST_COLUMN_INTENT_ACTION, intent.getAction());
-        cv.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA, intent.getDataString());
-        cv.put(SearchManager.SUGGEST_COLUMN_INTENT_COMPONENT_NAME,
-                intent.getComponent().flattenToShortString());
-
-        // ensure the icons will work for global search
-        cv.put(SearchManager.SUGGEST_COLUMN_ICON_1,
-                        wrapIconForPackage(
-                                mSearchable.getSuggestPackage(),
-                                getColumnString(c, SearchManager.SUGGEST_COLUMN_ICON_1)));
-        cv.put(SearchManager.SUGGEST_COLUMN_ICON_2,
-                        wrapIconForPackage(
-                                mSearchable.getSuggestPackage(),
-                                getColumnString(c, SearchManager.SUGGEST_COLUMN_ICON_2)));
-
-        // the rest can be passed through directly
-        cv.put(SearchManager.SUGGEST_COLUMN_FORMAT,
-                getColumnString(c, SearchManager.SUGGEST_COLUMN_FORMAT));
-        cv.put(SearchManager.SUGGEST_COLUMN_TEXT_1,
-                getColumnString(c, SearchManager.SUGGEST_COLUMN_TEXT_1));
-        cv.put(SearchManager.SUGGEST_COLUMN_TEXT_2,
-                getColumnString(c, SearchManager.SUGGEST_COLUMN_TEXT_2));
-        cv.put(SearchManager.SUGGEST_COLUMN_QUERY,
-                getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY));
-        cv.put(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID,
-                getColumnString(c, SearchManager.SUGGEST_COLUMN_SHORTCUT_ID));
-        // note: deliberately omitting background color since it is only for global search
-        // "more results" entries
-        mContext.getContentResolver().insert(uri, cv);
-    }
-
-    /**
-     * @return A URI appropriate for reporting a click.
-     */
-    private Uri getClickReportingUri() {
-        Uri.Builder uriBuilder = new Uri.Builder()
-                .scheme(ContentResolver.SCHEME_CONTENT)
-                .authority(SearchManager.SEARCH_CLICK_REPORT_AUTHORITY);
-
-        uriBuilder.appendPath(SearchManager.SEARCH_CLICK_REPORT_URI_PATH);
-
-        return uriBuilder
-                .query("")     // TODO: Remove, workaround for a bug in Uri.writeToParcel()
-                .fragment("")  // TODO: Remove, workaround for a bug in Uri.writeToParcel()
-                .build();
-    }
-
-    /**
-     * Wraps an icon for a particular package.  If the icon is a resource id, it is converted into
-     * an android.resource:// URI.
-     *
-     * @param packageName The source of the icon
-     * @param icon The icon retrieved from a suggestion column
-     * @return An icon string appropriate for the package.
-     */
-    private String wrapIconForPackage(String packageName, String icon) {
-        if (icon == null || icon.length() == 0 || "0".equals(icon)) {
-            // SearchManager specifies that null or zero can be returned to indicate
-            // no icon. We also allow empty string.
-            return null;
-        } else if (!Character.isDigit(icon.charAt(0))){
-            return icon;
-        } else {
-            return new Uri.Builder()
-                    .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
-                    .authority(packageName)
-                    .encodedPath(icon)
-                    .toString();
-        }
-    }
-
-    /**
      * Launches an intent, including any special intent handling.
      */
     private void launchIntent(Intent intent) {
         if (intent == null) {
             return;
         }
-        if (handleSpecialIntent(intent)){
-            return;
-        }
         Log.d(LOG_TAG, "launching " + intent);
         try {
-            // in global search mode, we send the activity straight to the original suggestion
-            // source. this is because GlobalSearch may not have permission to launch the
-            // intent, and to avoid the extra step of going through GlobalSearch.
-            if (mGlobalSearchMode) {
-                launchGlobalSearchIntent(intent);
-                if (mStoredComponentName != null) {
-                    // If we're embedded in an application, dismiss the dialog.
-                    // This ensures that if the intent is handled by the current
-                    // activity, it's not obscured by the dialog.
-                    dismiss();
-                }
-            } else {
-                // If the intent was created from a suggestion, it will always have an explicit
-                // component here.
-                Log.i(LOG_TAG, "Starting (as ourselves) " + intent.toURI());
-                getContext().startActivity(intent);
-                // If the search switches to a different activity,
-                // SearchDialogWrapper#performActivityResuming
-                // will handle hiding the dialog when the next activity starts, but for
-                // real in-app search, we still need to dismiss the dialog.
-                if (isInRealAppSearch()) {
-                    dismiss();
-                }
-            }
+            // If the intent was created from a suggestion, it will always have an explicit
+            // component here.
+            Log.i(LOG_TAG, "Starting (as ourselves) " + intent.toURI());
+            getContext().startActivity(intent);
+            // If the search switches to a different activity,
+            // SearchDialogWrapper#performActivityResuming
+            // will handle hiding the dialog when the next activity starts, but for
+            // real in-app search, we still need to dismiss the dialog.
+            dismiss();
         } catch (RuntimeException ex) {
             Log.e(LOG_TAG, "Failed launch activity: " + intent, ex);
         }
     }
 
-    private void launchGlobalSearchIntent(Intent intent) {
-        final String packageName;
-        // GlobalSearch puts the original source of the suggestion in the
-        // 'component name' column. If set, we send the intent to that activity.
-        // We trust GlobalSearch to always set this to the suggestion source.
-        String intentComponent = intent.getStringExtra(SearchManager.COMPONENT_NAME_KEY);
-        if (intentComponent != null) {
-            ComponentName componentName = ComponentName.unflattenFromString(intentComponent);
-            intent.setComponent(componentName);
-            intent.removeExtra(SearchManager.COMPONENT_NAME_KEY);
-            // Launch the intent as the suggestion source.
-            // This prevents sources from using the search dialog to launch
-            // intents that they don't have permission for themselves.
-            packageName = componentName.getPackageName();
-        } else {
-            // If there is no component in the suggestion, it must be a built-in suggestion
-            // from GlobalSearch (e.g. "Search the web for") or the intent
-            // launched when pressing the search/go button in the search dialog.
-            // Launch the intent with the permissions of GlobalSearch.
-            packageName = mSearchable.getSearchActivity().getPackageName();
-        }
-
-        // Launch all global search suggestions as new tasks, since they don't relate
-        // to the current task.
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        setBrowserApplicationId(intent);
-
-        startActivityInPackage(intent, packageName);
-    }
-
     /**
      * If the intent is to open an HTTP or HTTPS URL, we set
      * {@link Browser#EXTRA_APPLICATION_ID} so that any existing browser window that
@@ -1372,106 +1092,6 @@
     }
 
     /**
-     * Starts an activity as if it had been started by the given package.
-     *
-     * @param intent The description of the activity to start.
-     * @param packageName
-     * @throws ActivityNotFoundException If the intent could not be resolved to
-     *         and existing activity.
-     * @throws SecurityException If the package does not have permission to start
-     *         start the activity.
-     * @throws AndroidRuntimeException If some other error occurs.
-     */
-    private void startActivityInPackage(Intent intent, String packageName) {
-        try {
-            int uid = ActivityThread.getPackageManager().getPackageUid(packageName);
-            if (uid < 0) {
-                throw new AndroidRuntimeException("Package UID not found " + packageName);
-            }
-            String resolvedType = intent.resolveTypeIfNeeded(getContext().getContentResolver());
-            IBinder resultTo = null;
-            String resultWho = null;
-            int requestCode = -1;
-            boolean onlyIfNeeded = false;
-            Log.i(LOG_TAG, "Starting (uid " + uid + ", " + packageName + ") " + intent.toURI());
-            int result = ActivityManagerNative.getDefault().startActivityInPackage(
-                    uid, intent, resolvedType, resultTo, resultWho, requestCode, onlyIfNeeded);
-            checkStartActivityResult(result, intent);
-        } catch (RemoteException ex) {
-            throw new AndroidRuntimeException(ex);
-        }
-    }
-
-    // Stolen from Instrumentation.checkStartActivityResult()
-    private static void checkStartActivityResult(int res, Intent intent) {
-        if (res >= IActivityManager.START_SUCCESS) {
-            return;
-        }
-        switch (res) {
-            case IActivityManager.START_INTENT_NOT_RESOLVED:
-            case IActivityManager.START_CLASS_NOT_FOUND:
-                if (intent.getComponent() != null)
-                    throw new ActivityNotFoundException(
-                            "Unable to find explicit activity class "
-                            + intent.getComponent().toShortString()
-                            + "; have you declared this activity in your AndroidManifest.xml?");
-                throw new ActivityNotFoundException(
-                        "No Activity found to handle " + intent);
-            case IActivityManager.START_PERMISSION_DENIED:
-                throw new SecurityException("Not allowed to start activity "
-                        + intent);
-            case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
-                throw new AndroidRuntimeException(
-                        "FORWARD_RESULT_FLAG used while also requesting a result");
-            default:
-                throw new AndroidRuntimeException("Unknown error code "
-                        + res + " when starting " + intent);
-        }
-    }
-
-    /**
-     * Handles the special intent actions declared in {@link SearchManager}.
-     * 
-     * @return <code>true</code> if the intent was handled.
-     */
-    private boolean handleSpecialIntent(Intent intent) {
-        String action = intent.getAction();
-        if (SearchManager.INTENT_ACTION_CHANGE_SEARCH_SOURCE.equals(action)) {
-            handleChangeSourceIntent(intent);
-            return true;
-        }
-        return false;
-    }
-    
-    /**
-     * Handles {@link SearchManager#INTENT_ACTION_CHANGE_SEARCH_SOURCE}.
-     */
-    private void handleChangeSourceIntent(Intent intent) {
-        Uri dataUri = intent.getData();
-        if (dataUri == null) {
-            Log.w(LOG_TAG, "SearchManager.INTENT_ACTION_CHANGE_SOURCE without intent data.");
-            return;
-        }
-        ComponentName componentName = ComponentName.unflattenFromString(dataUri.toString());
-        if (componentName == null) {
-            Log.w(LOG_TAG, "Invalid ComponentName: " + dataUri);
-            return;
-        }
-        if (DBG) Log.d(LOG_TAG, "Switching to " + componentName);
-
-        pushPreviousComponent(mLaunchComponent);
-        if (!show(componentName, mAppSearchData, false)) {
-            Log.w(LOG_TAG, "Failed to switch to source " + componentName);
-            popPreviousComponent();
-            return;
-        }
-
-        String query = intent.getStringExtra(SearchManager.QUERY);
-        setUserQuery(query);
-        mSearchAutoComplete.showDropDown();
-    }
-
-    /**
      * Sets the list item selection in the AutoCompleteTextView's ListView.
      */
     public void setListSelection(int index) {
@@ -1479,61 +1099,6 @@
     }
 
     /**
-     * Checks if there are any previous searchable components in the history stack.
-     */
-    private boolean hasPreviousComponent() {
-        return mPreviousComponents != null && !mPreviousComponents.isEmpty();
-    }
-
-    /**
-     * Saves the previous component that was searched, so that we can go
-     * back to it.
-     */
-    private void pushPreviousComponent(ComponentName componentName) {
-        if (mPreviousComponents == null) {
-            mPreviousComponents = new ArrayList<ComponentName>();
-        }
-        mPreviousComponents.add(componentName);
-    }
-    
-    /**
-     * Pops the previous component off the stack and returns it.
-     * 
-     * @return The component name, or <code>null</code> if there was
-     *         no previous component.
-     */
-    private ComponentName popPreviousComponent() {
-        if (!hasPreviousComponent()) {
-            return null;
-        }
-        return mPreviousComponents.remove(mPreviousComponents.size() - 1);
-    }
-    
-    /**
-     * Goes back to the previous component that was searched, if any.
-     * 
-     * @return <code>true</code> if there was a previous component that we could go back to.
-     */
-    private boolean backToPreviousComponent() {
-        ComponentName previous = popPreviousComponent();
-        if (previous == null) {
-            return false;
-        }
-
-        if (!show(previous, mAppSearchData, false)) {
-            Log.w(LOG_TAG, "Failed to switch to source " + previous);
-            return false;
-        }
-
-        // must touch text to trigger suggestions
-        // TODO: should this be the text as it was when the user left
-        // the source that we are now going back to?
-        String query = mSearchAutoComplete.getText().toString();
-        setUserQuery(query);
-        return true;
-    }
-    
-    /**
      * When a particular suggestion has been selected, perform the various lookups required
      * to use the suggestion.  This includes checking the cursor for suggestion-specific data,
      * and/or falling back to the XML for defaults;  It also creates REST style Uri data when
@@ -1582,10 +1147,9 @@
 
             String query = getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY);
             String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
-            String mode = mGlobalSearchMode ? SearchManager.MODE_GLOBAL_SEARCH_SUGGESTION : null;
 
             return createIntent(action, dataUri, extraData, query, componentName, actionKey,
-                    actionMsg, mode);
+                    actionMsg);
         } catch (RuntimeException e ) {
             int rowNum;
             try {                       // be really paranoid now
@@ -1616,16 +1180,13 @@
      * @return The intent.
      */
     private Intent createIntent(String action, Uri data, String extraData, String query,
-            String componentName, int actionKey, String actionMsg, String mode) {
+            String componentName, int actionKey, String actionMsg) {
         // Now build the Intent
         Intent intent = new Intent(action);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         // We need CLEAR_TOP to avoid reusing an old task that has other activities
         // on top of the one we want. We don't want to do this in in-app search though,
         // as it can be destructive to the activity stack.
-        if (mGlobalSearchMode) {
-            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        }
         if (data != null) {
             intent.setData(data);
         }
@@ -1636,9 +1197,6 @@
         if (extraData != null) {
             intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData);
         }
-        if (componentName != null) {
-            intent.putExtra(SearchManager.COMPONENT_NAME_KEY, componentName);
-        }
         if (mAppSearchData != null) {
             intent.putExtra(SearchManager.APP_DATA, mAppSearchData);
         }
@@ -1646,16 +1204,10 @@
             intent.putExtra(SearchManager.ACTION_KEY, actionKey);
             intent.putExtra(SearchManager.ACTION_MSG, actionMsg);
         }
-        if (mode != null) {
-            intent.putExtra(SearchManager.SEARCH_MODE, mode);
-        }
-        // Only allow 3rd-party intents from GlobalSearch
-        if (!mGlobalSearchMode) {
-            intent.setComponent(mSearchable.getSearchActivity());
-        }
+        intent.setComponent(mSearchable.getSearchActivity());
         return intent;
     }
-    
+
     /**
      * For a given suggestion and a given cursor row, get the action message.  If not provided
      * by the specific row/column, also check for a single definition (for the action key).
@@ -1812,12 +1364,8 @@
                 imm.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0)) {
             return;
         }
-        // Otherwise, go back to any previous source (e.g. back to QSB when
-        // pivoted into a source.
-        if (!backToPreviousComponent()) {
-            // If no previous source, close search dialog
-            cancel();
-        }
+        // Close search dialog
+        cancel();
     }
 
     /**
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 5a9a675..ce5f1bf 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -350,7 +350,7 @@
  * <p><b>Configuring your Content Provider to Receive Suggestion Queries.</b>  The basic job of
  * a search suggestions {@link android.content.ContentProvider Content Provider} is to provide
  * "live" (while-you-type) conversion of the user's query text into a set of zero or more 
- * suggestions.  Each application is free to define the conversion, and as described above there are
+ * suggestions. Each application is free to define the conversion, and as described above there are
  * many possible solutions.  This section simply defines how to communicate with the suggestion
  * provider.  
  * 
@@ -360,7 +360,8 @@
  * 
  * <p>Every query includes a Uri, and the Search Manager will format the Uri as shown:
  * <p><pre class="prettyprint">
- * content:// your.suggest.authority / your.suggest.path / SearchManager.SUGGEST_URI_PATH_QUERY</pre>
+ * content:// your.suggest.authority / your.suggest.path / SearchManager.SUGGEST_URI_PATH_QUERY
+ *    </pre>
  * 
  * <p>Your Content Provider can receive the query text in one of two ways.
  * <ul>
@@ -379,7 +380,7 @@
  * <p><b>Providing access to Content Providers that require permissions.</b>  If your content
  * provider declares an android:readPermission in your application's manifest, you must provide
  * access to the search infrastructure to the search suggestion path by including a path-permission
- * that grants android:readPermission access to "android.permission.GLOBAL_SEARCH".  Granting access
+ * that grants android:readPermission access to "android.permission.GLOBAL_SEARCH". Granting access
  * explicitly to the search infrastructure ensures it will be able to access the search suggestions
  * without needing to know ahead of time any other details of the permissions protecting your
  * provider.  Content providers that require no permissions are already available to the search
@@ -546,7 +547,8 @@
  * taken directly to a specific result.
  *   <ul>
  *   <li><b>Action:</b> {@link android.content.Intent#ACTION_VIEW ACTION_VIEW}</li>
- *   <li><b>Data:</b> a complete Uri, supplied by the cursor, that identifies the desired data.</li>
+ *   <li><b>Data:</b> a complete Uri, supplied by the cursor, that identifies the desired data.
+ *   </li>
  *   <li><b>Query:</b> query text supplied with the suggestion (probably ignored)</li>
  *   </ul>
  * </li>
@@ -570,7 +572,7 @@
  * 
  * <p><b>Suggestion Rewriting.</b>  If the user navigates through the suggestions list, the UI
  * may temporarily rewrite the user's query with a query that matches the currently selected 
- * suggestion.  This enables the user to see what query is being suggested, and also allows the user
+ * suggestion. This enables the user to see what query is being suggested, and also allows the user
  * to click or touch in the entry EditText element and make further edits to the query before
  * dispatching it.  In order to perform this correctly, the Search UI needs to know exactly what
  * text to rewrite the query with.
@@ -1289,15 +1291,6 @@
     public final static String SEARCH_MODE = "search_mode";
 
     /**
-     * Value for the {@link #SEARCH_MODE} key.
-     * This is used if the intent was launched by clicking a suggestion in global search
-     * mode (Quick Search Box).
-     *
-     * @hide
-     */
-    public static final String MODE_GLOBAL_SEARCH_SUGGESTION = "global_search_suggestion";
-
-    /**
      * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
      * {@link android.content.Intent#getIntExtra content.Intent.getIntExtra()}
      * to obtain the keycode that the user used to trigger this query.  It will be zero if the
@@ -1308,14 +1301,6 @@
     public final static String ACTION_KEY = "action_key";
     
     /**
-     * Intent component name key: This key will be used for the extra populated by the
-     * {@link #SUGGEST_COLUMN_INTENT_COMPONENT_NAME} column.
-     *
-     * {@hide}
-     */
-    public final static String COMPONENT_NAME_KEY = "intent_component_name_key";
-
-    /**
      * Intent extra data key: This key will be used for the extra populated by the
      * {@link #SUGGEST_COLUMN_INTENT_EXTRA_DATA} column.
      */
@@ -1329,58 +1314,6 @@
     public final static String EXTRA_SELECT_QUERY = "select_query";
 
     /**
-     * Defines the constants used in the communication between {@link android.app.SearchDialog} and
-     * the global search provider via {@link Cursor#respond(android.os.Bundle)}.
-     *
-     * @hide
-     */
-    public static class DialogCursorProtocol {
-
-        /**
-         * The sent bundle will contain this integer key, with a value set to one of the events
-         * below.
-         */
-        public final static String METHOD = "DialogCursorProtocol.method";
-
-        /**
-         * After data has been refreshed.
-         */
-        public final static int POST_REFRESH = 0;
-        public final static String POST_REFRESH_RECEIVE_ISPENDING
-                = "DialogCursorProtocol.POST_REFRESH.isPending";
-        public final static String POST_REFRESH_RECEIVE_DISPLAY_NOTIFY
-                = "DialogCursorProtocol.POST_REFRESH.displayNotify";
-
-        /**
-         * When a position has been clicked.
-         */
-        public final static int CLICK = 2;
-        public final static String CLICK_SEND_POSITION
-                = "DialogCursorProtocol.CLICK.sendPosition";
-        public final static String CLICK_SEND_MAX_DISPLAY_POS
-                = "DialogCursorProtocol.CLICK.sendDisplayPosition";
-        public final static String CLICK_SEND_ACTION_KEY
-                = "DialogCursorProtocol.CLICK.sendActionKey";
-        public final static String CLICK_SEND_ACTION_MSG
-                = "DialogCursorProtocol.CLICK.sendActionMsg";
-        public final static String CLICK_RECEIVE_SELECTED_POS
-                = "DialogCursorProtocol.CLICK.receiveSelectedPosition";
-
-        /**
-         * When the threshold received in {@link #POST_REFRESH_RECEIVE_DISPLAY_NOTIFY} is displayed.
-         */
-        public final static int THRESH_HIT = 3;
-
-        /**
-         * When a search is started without using a suggestion.
-         */
-        public final static int SEARCH = 4;
-        public final static String SEARCH_SEND_MAX_DISPLAY_POS
-                = "DialogCursorProtocol.SEARCH.sendDisplayPosition";
-        public final static String SEARCH_SEND_QUERY = "DialogCursorProtocol.SEARCH.query";
-    }
-
-    /**
      * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
      * {@link android.content.Intent#getStringExtra content.Intent.getStringExtra()}
      * to obtain the action message that was defined for a particular search action key and/or
@@ -1421,40 +1354,6 @@
     public final static String SHORTCUT_MIME_TYPE = 
             "vnd.android.cursor.item/vnd.android.search.suggest";
 
-
-    /**
-     * The authority of the provider to report clicks to when a click is detected after pivoting
-     * into a specific app's search from global search.
-     *
-     * In addition to the columns below, the suggestion columns are used to pass along the full
-     * suggestion so it can be shortcutted.
-     *
-     * @hide
-     */
-    public final static String SEARCH_CLICK_REPORT_AUTHORITY =
-            "com.android.globalsearch.stats";
-
-    /**
-     * The path the write goes to.
-     *
-     * @hide
-     */
-    public final static String SEARCH_CLICK_REPORT_URI_PATH = "click";
-
-    /**
-     * The column storing the query for the click.
-     *
-     * @hide
-     */
-    public final static String SEARCH_CLICK_REPORT_COLUMN_QUERY = "query";
-
-    /**
-     * The column storing the component name of the application that was pivoted into.
-     *
-     * @hide
-     */
-    public final static String SEARCH_CLICK_REPORT_COLUMN_COMPONENT = "component";
-
     /**
      * Column name for suggestions cursor.  <i>Unused - can be null or column can be omitted.</i>
      */
@@ -1531,10 +1430,7 @@
      */
     public final static String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data";
     /**
-     * Column name for suggestions cursor.  <i>Optional.</i>  This column allows suggestions
-     *  to provide additional arbitrary data which will be included as an extra under the key
-     *  {@link #COMPONENT_NAME_KEY}. For use by the global search system only - if other providers
-     *  attempt to use this column, the value will be overwritten by global search.
+     * TODO: Remove
      *
      * @hide
      */
@@ -1594,27 +1490,6 @@
     public final static String SUGGEST_PARAMETER_LIMIT = "limit";
 
     /**
-     * If a suggestion has this value in {@link #SUGGEST_COLUMN_INTENT_ACTION},
-     * the search dialog will switch to a different suggestion source when the
-     * suggestion is clicked. 
-     * 
-     * {@link #SUGGEST_COLUMN_INTENT_DATA} must contain
-     * the flattened {@link ComponentName} of the activity which is to be searched.
-     * 
-     * TODO: Should {@link #SUGGEST_COLUMN_INTENT_DATA} instead contain a URI in the format
-     * used by {@link android.provider.Applications}?
-     * 
-     * TODO: This intent should be protected by the same permission that we use
-     * for replacing the global search provider.
-     * 
-     * The query text field will be set to the value of {@link #SUGGEST_COLUMN_QUERY}.
-     * 
-     * @hide Pending API council approval.
-     */
-    public final static String INTENT_ACTION_CHANGE_SEARCH_SOURCE 
-            = "android.search.action.CHANGE_SEARCH_SOURCE";
-
-    /**
      * Intent action for starting the global search activity.
      * The global search provider should handle this intent.
      *
@@ -1663,7 +1538,7 @@
      * @hide
      */
     public final static String INTENT_ACTION_NONE = "android.search.action.ZILCH";
-    
+
     /**
      * Reference to the shared system search service.
      */
@@ -1672,13 +1547,6 @@
     private final Context mContext;
 
     /**
-     * compact representation of the activity associated with this search manager so
-     * we can say who we are when starting search.  the search managerservice, in turn,
-     * uses this to properly handle the back stack.
-     */
-    private int mIdent;
-
-    /**
      * The package associated with this seach manager.
      */
     private String mAssociatedPackage;
@@ -1696,21 +1564,6 @@
         mService = ISearchManager.Stub.asInterface(
                 ServiceManager.getService(Context.SEARCH_SERVICE));
     }
-
-    /*package*/ boolean hasIdent() {
-        return mIdent != 0;
-    }
-    
-    /*package*/ void setIdent(int ident, ComponentName component) {
-        if (mIdent != 0) {
-            throw new IllegalStateException("mIdent already set");
-        }
-        if (component == null) {
-            throw new IllegalArgumentException("component must be non-null");
-        }
-        mIdent = ident;
-        mAssociatedPackage = component.getPackageName();
-    }
     
     /**
      * Launch search UI.
@@ -1757,15 +1610,14 @@
                             ComponentName launchActivity,
                             Bundle appSearchData,
                             boolean globalSearch) {
-        ensureSearchDialog();
-
         if (globalSearch) {
             startGlobalSearch(initialQuery, selectInitialQuery, appSearchData);
             return;
         }
 
-        mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData,
-                globalSearch);
+        ensureSearchDialog();
+
+        mSearchDialog.show(initialQuery, selectInitialQuery, launchActivity, appSearchData);
     }
 
     private void ensureSearchDialog() {
@@ -1838,6 +1690,25 @@
     }
 
     /**
+     * Gets the name of the web search activity.
+     *
+     * @return The name of the default activity for web searches. This activity
+     *         can be used to get web search suggestions. Returns {@code null} if
+     *         there is no default web search activity.
+     *
+     * @hide
+     */
+    public ComponentName getWebSearchActivity() {
+        ComponentName globalSearch = getGlobalSearchActivity();
+        if (globalSearch == null) {
+            return null;
+        }
+        Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
+        intent.setPackage(globalSearch.getPackageName());
+        return intent.resolveActivity(mContext.getPackageManager());
+    }
+
+    /**
      * Similar to {@link #startSearch} but actually fires off the search query after invoking
      * the search dialog.  Made available for testing purposes.
      *
@@ -1994,17 +1865,6 @@
             return null;
         }
     }
-    
-    /**
-     * Checks whether the given searchable is the default searchable.
-     * 
-     * @hide because SearchableInfo is not part of the API.
-     */
-    public boolean isDefaultSearchable(SearchableInfo searchable) {
-        SearchableInfo defaultSearchable = getSearchableInfo(null, true);
-        return defaultSearchable != null 
-                && defaultSearchable.getSearchActivity().equals(searchable.getSearchActivity());
-    }
 
     /**
      * Gets a cursor with search suggestions.
@@ -2091,56 +1951,4 @@
         }
     }
 
-    /**
-     * Returns a list of the searchable activities that handle web searches.
-     *
-     * @return a list of all searchable activities that handle
-     *         {@link android.content.Intent#ACTION_WEB_SEARCH}.
-     *
-     * @hide because SearchableInfo is not part of the API.
-     */
-    public List<SearchableInfo> getSearchablesForWebSearch() {
-        try {
-            return mService.getSearchablesForWebSearch();
-        } catch (RemoteException e) {
-            Log.e(TAG, "getSearchablesForWebSearch() failed: " + e);
-            return null;
-        }
-    }
-
-    /**
-     * Returns the default searchable activity for web searches.
-     *
-     * @return searchable information for the activity handling web searches by default.
-     *
-     * @hide because SearchableInfo is not part of the API.
-     */
-    public SearchableInfo getDefaultSearchableForWebSearch() {
-        try {
-            return mService.getDefaultSearchableForWebSearch();
-        } catch (RemoteException e) {
-            Log.e(TAG, "getDefaultSearchableForWebSearch() failed: " + e);
-            return null;
-        }
-    }
-
-    /**
-     * Sets the default searchable activity for web searches.
-     *
-     * @param component Name of the component to set as default activity for web searches.
-     *
-     * @hide
-     */
-    public void setDefaultWebSearch(ComponentName component) {
-        try {
-            mService.setDefaultWebSearch(component);
-        } catch (RemoteException e) {
-            Log.e(TAG, "setDefaultWebSearch() failed: " + e);
-        }
-    }
-
-    private static void debug(String msg) {
-        Thread thread = Thread.currentThread();
-        Log.d(TAG, msg + " (" + thread.getName() + "-" + thread.getId() + ")");
-    }
 }
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 8ec5bd4..6767332 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -56,6 +56,8 @@
  * <li><a href="#ServiceLifecycle">Service Lifecycle</a>
  * <li><a href="#Permissions">Permissions</a>
  * <li><a href="#ProcessLifecycle">Process Lifecycle</a>
+ * <li><a href="#LocalServiceSample">Local Service Sample</a>
+ * <li><a href="#RemoteMessengerServiceSample">Remote Messenger Service Sample</a>
  * </ol>
  * 
  * <a name="ServiceLifecycle"></a>
@@ -166,6 +168,64 @@
  * (such as an {@link android.app.Activity}) can, of course, increase the
  * importance of the overall
  * process beyond just the importance of the service itself.
+ * 
+ * <a name="LocalServiceSample"></a>
+ * <h3>Local Service Sample</h3>
+ * 
+ * <p>One of the most common uses of a Service is as a secondary component
+ * running alongside other parts of an application, in the same process as
+ * the rest of the components.  All components of an .apk run in the same
+ * process unless explicitly stated otherwise, so this is a typical situation.
+ * 
+ * <p>When used in this way, by assuming the
+ * components are in the same process, you can greatly simplify the interaction
+ * between them: clients of the service can simply cast the IBinder they
+ * receive from it to a concrete class published by the service.
+ * 
+ * <p>An example of this use of a Service is shown here.  First is the Service
+ * itself, publishing a custom class when bound:
+ * 
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/LocalService.java
+ *      service}
+ * 
+ * <p>With that done, one can now write client code that directly accesses the
+ * running service, such as:
+ * 
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceActivities.java
+ *      bind}
+ * 
+ * <a name="RemoteMessengerServiceSample"></a>
+ * <h3>Remote Messenger Service Sample</h3>
+ * 
+ * <p>If you need to be able to write a Service that can perform complicated
+ * communication with clients in remote processes (beyond simply the use of
+ * {@link Context#startService(Intent) Context.startService} to send
+ * commands to it), then you can use the {@link android.os.Messenger} class
+ * instead of writing full AIDL files.
+ * 
+ * <p>An example of a Service that uses Messenger as its client interface
+ * is shown here.  First is the Service itself, publishing a Messenger to
+ * an internal Handler when bound:
+ * 
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/MessengerService.java
+ *      service}
+ * 
+ * <p>If we want to make this service run in a remote process (instead of the
+ * standard one for its .apk), we can use <code>android:process</code> in its
+ * manifest tag to specify one:
+ * 
+ * {@sample development/samples/ApiDemos/AndroidManifest.xml remote_service_declaration}
+ * 
+ * <p>Note that the name "remote" chosen here is arbitrary, and you can use
+ * other names if you want additional processes.  The ':' prefix appends the
+ * name to your package's standard process name.
+ * 
+ * <p>With that done, clients can now bind to the service and send messages
+ * to it.  Note that this allows clients to register with it to receive
+ * messages back as well:
+ * 
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/MessengerServiceActivities.java
+ *      bind}
  */
 public abstract class Service extends ContextWrapper implements ComponentCallbacks {
     private static final String TAG = "Service";
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 173c3e1..57795d1 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -16,7 +16,6 @@
 
 package android.app;
 
-import android.app.SearchManager.DialogCursorProtocol;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -30,12 +29,10 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.StateListDrawable;
 import android.net.Uri;
-import android.os.Bundle;
 import android.text.Html;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
-import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Filter;
@@ -65,7 +62,6 @@
     private Context mProviderContext;
     private WeakHashMap<String, Drawable.ConstantState> mOutsideDrawablesCache;
     private SparseArray<Drawable.ConstantState> mBackgroundsCache;
-    private boolean mGlobalSearchMode;
     private boolean mClosed = false;
 
     // Cached column indexes, updated when the cursor changes.
@@ -76,29 +72,8 @@
     private int mIconName2Col;
     private int mBackgroundColorCol;
     
-    // The extra used to tell a cursor to close itself. This is a hack, see the description by
-    // its use later in this file.
-    private static final String EXTRA_CURSOR_RESPOND_CLOSE_CURSOR = "cursor_respond_close_cursor";
-
-    // The bundle which contains {EXTRA_CURSOR_RESPOND_CLOSE_CURSOR=true}, just cached once
-    // so we don't bother recreating it a bunch.
-    private final Bundle mCursorRespondCloseCursorBundle;
-
-    // This value is stored in SuggestionsAdapter by the SearchDialog to indicate whether
-    // a particular list item should be selected upon the next call to notifyDataSetChanged.
-    // This is used to indicate the index of the "More results..." list item so that when
-    // the data set changes after a click of "More results...", we can correctly tell the
-    // ListView to scroll to the right line item. It gets reset to NONE every time it
-    // is consumed.
-    private int mListItemToSelect = NONE;
     static final int NONE = -1;
 
-    // holds the maximum position that has been displayed to the user
-    int mMaxDisplayed = NONE;
-
-    // holds the position that, when displayed, should result in notifying the cursor
-    int mDisplayNotifyPos = NONE;
-
     private final Runnable mStartSpinnerRunnable;
     private final Runnable mStopSpinnerRunnable;
 
@@ -110,8 +85,7 @@
 
     public SuggestionsAdapter(Context context, SearchDialog searchDialog,
             SearchableInfo searchable,
-            WeakHashMap<String, Drawable.ConstantState> outsideDrawablesCache,
-            boolean globalSearchMode) {
+            WeakHashMap<String, Drawable.ConstantState> outsideDrawablesCache) {
         super(context,
                 com.android.internal.R.layout.search_dropdown_item_icons_2line,
                 null,   // no initial cursor
@@ -126,7 +100,6 @@
 
         mOutsideDrawablesCache = outsideDrawablesCache;
         mBackgroundsCache = new SparseArray<Drawable.ConstantState>();
-        mGlobalSearchMode = globalSearchMode;
 
         mStartSpinnerRunnable = new Runnable() {
                 public void run() {
@@ -140,10 +113,6 @@
             }
         };
         
-        // Create this once because we'll reuse it a bunch.
-        mCursorRespondCloseCursorBundle = new Bundle();
-        mCursorRespondCloseCursorBundle.putBoolean(EXTRA_CURSOR_RESPOND_CLOSE_CURSOR, true);
-
         // delay 500ms when deleting
         getFilter().setDelayer(new Filter.Delayer() {
 
@@ -177,27 +146,22 @@
     public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
         if (DBG) Log.d(LOG_TAG, "runQueryOnBackgroundThread(" + constraint + ")");
         String query = (constraint == null) ? "" : constraint.toString();
-        if (!mGlobalSearchMode) {
-            /**
-             * for in app search we show the progress spinner until the cursor is returned with
-             * the results.  for global search we manage the progress bar using
-             * {@link DialogCursorProtocol#POST_REFRESH_RECEIVE_ISPENDING}.
-             */
-            mSearchDialog.getWindow().getDecorView().post(mStartSpinnerRunnable);
-        }
+        /**
+         * for in app search we show the progress spinner until the cursor is returned with
+         * the results.
+         */
+        mSearchDialog.getWindow().getDecorView().post(mStartSpinnerRunnable);
         try {
             final Cursor cursor = mSearchManager.getSuggestions(mSearchable, query, QUERY_LIMIT);
             // trigger fill window so the spinner stays up until the results are copied over and
             // closer to being ready
-            if (!mGlobalSearchMode && cursor != null) cursor.getCount();
+            if (cursor != null) cursor.getCount();
             return cursor;
         } catch (RuntimeException e) {
             Log.w(LOG_TAG, "Search suggestions query threw an exception.", e);
             return null;
         } finally {
-            if (!mGlobalSearchMode) {
-                mSearchDialog.getWindow().getDecorView().post(mStopSpinnerRunnable);
-            }
+            mSearchDialog.getWindow().getDecorView().post(mStopSpinnerRunnable);
         }
     }
 
@@ -221,21 +185,8 @@
         }
 
         try {
-            Cursor oldCursor = getCursor();
             super.changeCursor(c);
-            
-            // We send a special respond to the cursor to tell it to close itself directly because
-            // it may not happen correctly for some cursors currently. This was originally
-            // included as a fix to http://b/2036290, in which the search dialog was holding
-            // on to references to the web search provider unnecessarily. This is being caused by
-            // the fact that the cursor is not being correctly closed in
-            // BulkCursorToCursorAdapter#close, which remains unfixed (see http://b/2015069).
-            //
-            // TODO: Remove this hack once http://b/2015069 is fixed.
-            if (oldCursor != null && oldCursor != c) {
-                oldCursor.respond(mCursorRespondCloseCursorBundle);
-            }
-            
+
             if (c != null) {
                 mFormatCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_FORMAT);
                 mText1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1);
@@ -249,79 +200,6 @@
         }
     }
 
-    @Override
-    public void notifyDataSetChanged() {
-        if (DBG) Log.d(LOG_TAG, "notifyDataSetChanged");
-        super.notifyDataSetChanged();
-
-        callCursorPostRefresh(mCursor);
-
-        // look out for the pending item we are supposed to scroll to
-        if (mListItemToSelect != NONE) {
-            mSearchDialog.setListSelection(mListItemToSelect);
-            mListItemToSelect = NONE;
-        }
-    }
-
-    /**
-     * Handle sending and receiving information associated with
-     * {@link DialogCursorProtocol#POST_REFRESH}.
-     *
-     * @param cursor The cursor to call.
-     */
-    private void callCursorPostRefresh(Cursor cursor) {
-        if (!mGlobalSearchMode) return;
-        final Bundle request = new Bundle();
-        request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.POST_REFRESH);
-        final Bundle response = cursor.respond(request);
-
-        mSearchDialog.setWorking(
-                response.getBoolean(DialogCursorProtocol.POST_REFRESH_RECEIVE_ISPENDING, false));
-
-        mDisplayNotifyPos =
-                response.getInt(DialogCursorProtocol.POST_REFRESH_RECEIVE_DISPLAY_NOTIFY, -1);
-    }
-
-    /**
-     * Tell the cursor which position was clicked, handling sending and receiving information
-     * associated with {@link DialogCursorProtocol#CLICK}.
-     *
-     * @param cursor The cursor
-     * @param position The position that was clicked.
-     */
-    void callCursorOnClick(Cursor cursor, int position, int actionKey, String actionMsg) {
-        if (!mGlobalSearchMode) return;
-        final Bundle request = new Bundle(5);
-        request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.CLICK);
-        request.putInt(DialogCursorProtocol.CLICK_SEND_POSITION, position);
-        request.putInt(DialogCursorProtocol.CLICK_SEND_MAX_DISPLAY_POS, mMaxDisplayed);
-        if (actionKey != KeyEvent.KEYCODE_UNKNOWN) {
-            request.putInt(DialogCursorProtocol.CLICK_SEND_ACTION_KEY, actionKey);
-            request.putString(DialogCursorProtocol.CLICK_SEND_ACTION_MSG, actionMsg);
-        }
-        final Bundle response = cursor.respond(request);
-        mMaxDisplayed = -1;
-        mListItemToSelect = response.getInt(
-                DialogCursorProtocol.CLICK_RECEIVE_SELECTED_POS, SuggestionsAdapter.NONE);
-    }
-
-    /**
-     * Tell the cursor that a search was started without using a suggestion.
-     *
-     * @param query The search query.
-     */
-    void reportSearch(String query) {
-        if (!mGlobalSearchMode) return;
-        Cursor cursor = getCursor();
-        if (cursor == null) return;
-        final Bundle request = new Bundle(3);
-        request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.SEARCH);
-        request.putString(DialogCursorProtocol.SEARCH_SEND_QUERY, query);
-        request.putInt(DialogCursorProtocol.SEARCH_SEND_MAX_DISPLAY_POS, mMaxDisplayed);
-        // the response is always empty
-        cursor.respond(request);
-    }
-
     /**
      * Tags the view with cached child view look-ups.
      */
@@ -353,20 +231,6 @@
     @Override
     public void bindView(View view, Context context, Cursor cursor) {
         ChildViewCache views = (ChildViewCache) view.getTag();
-        final int pos = cursor.getPosition();
-
-        // update the maximum position displayed since last refresh
-        if (pos > mMaxDisplayed) {
-            mMaxDisplayed = pos;
-        }
-
-        // if the cursor wishes to be notified about this position, send it
-        if (mGlobalSearchMode && mDisplayNotifyPos != NONE && pos == mDisplayNotifyPos) {
-            final Bundle request = new Bundle();
-            request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.THRESH_HIT);
-            mCursor.respond(request);
-            mDisplayNotifyPos = NONE;  // only notify the first time
-        }
 
         int backgroundColor = 0;
         if (mBackgroundColorCol != -1) {
diff --git a/core/java/android/backup/BackupDataInput.java b/core/java/android/backup/BackupDataInput.java
index 67d51ea..295dc66 100644
--- a/core/java/android/backup/BackupDataInput.java
+++ b/core/java/android/backup/BackupDataInput.java
@@ -133,7 +133,7 @@
 
     /**
      * Consume the current record's data without actually reading it into a buffer
-     * for further processing.  This allows a {@link android.backup.BackupAgent} to
+     * for further processing.  This allows a {@link android.app.BackupAgent} to
      * efficiently discard obsolete or otherwise uninteresting records during the
      * restore operation.
      * 
diff --git a/core/java/android/backup/IBackupManager.aidl b/core/java/android/backup/IBackupManager.aidl
index bf6c79f..d94b066 100644
--- a/core/java/android/backup/IBackupManager.aidl
+++ b/core/java/android/backup/IBackupManager.aidl
@@ -62,6 +62,12 @@
     void agentDisconnected(String packageName);
 
     /**
+     * Notify the Backup Manager Service that an application being installed will
+     * need a data-restore pass.  This method is only invoked by the Package Manager.
+     */
+    void restoreAtInstall(String packageName, int token);
+
+    /**
      * Enable/disable the backup service entirely.  When disabled, no backup
      * or restore operations will take place.  Data-changed notifications will
      * still be observed and collected, however, so that changes made while the
diff --git a/core/java/android/backup/RestoreSession.java b/core/java/android/backup/RestoreSession.java
index fc53854..bc410c4 100644
--- a/core/java/android/backup/RestoreSession.java
+++ b/core/java/android/backup/RestoreSession.java
@@ -63,7 +63,7 @@
      *
      * @return Zero on success; nonzero on error.  The observer will only receive
      *   progress callbacks if this method returned zero.
-     * @param token The token from {@link getAvailableRestoreSets()} corresponding to
+     * @param token The token from {@link #getAvailableRestoreSets()} corresponding to
      *   the restore set that should be used.
      * @param observer If non-null, this binder points to an object that will receive
      *   progress callbacks during the restore operation.
@@ -120,8 +120,7 @@
      * object is no longer valid.
      *
      * <p><b>Note:</b> The caller <i>must</i> invoke this method to end the restore session,
-     *   even if {@link #getAvailableRestoreSets()} or
-     *   {@link #restorePackage(long, String, RestoreObserver)} failed.
+     *   even if {@link #restorePackage(String, RestoreObserver)} failed.
      */
     public void endRestoreSession() {
         try {
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index b792965..251813e 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -112,11 +112,9 @@
     /** Default priority when not set or when the device is unpaired */
     public static final int PRIORITY_UNDEFINED = -1;
 
-    /** The voice dialer 'works' but the user experience is poor. The voice
-     *  recognizer has trouble dealing with the 8kHz SCO signal, and it still
-     *  requires visual confirmation. Disable for cupcake.
-     */
-    public static final boolean DISABLE_BT_VOICE_DIALING = true;
+    /** Set this to true to prevent the bluetooth headset from
+     * activating the VoiceDialer. */
+    public static final boolean DISABLE_BT_VOICE_DIALING = false;
 
     /**
      * An interface for notifying BluetoothHeadset IPC clients when they have
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index ca36df2..7945f3f 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -21,6 +21,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -46,6 +47,8 @@
     private final Map<Integer, Integer> mSelectionArgsBackReferences;
     private final boolean mYieldAllowed;
 
+    private final static String TAG = "ContentProviderOperation";
+
     /**
      * Creates a {@link ContentProviderOperation} by copying the contents of a
      * {@link Builder}.
@@ -241,6 +244,7 @@
                             final String expectedValue = values.getAsString(projection[i]);
                             if (!TextUtils.equals(cursorValue, expectedValue)) {
                                 // Throw exception when expected values don't match
+                                Log.e(TAG, this.toString());
                                 throw new OperationApplicationException("Found value " + cursorValue
                                         + " when expected " + expectedValue + " for column "
                                         + projection[i]);
@@ -252,10 +256,12 @@
                 cursor.close();
             }
         } else {
+            Log.e(TAG, this.toString());
             throw new IllegalStateException("bad type, " + mType);
         }
 
         if (mExpectedCount != null && mExpectedCount != numRows) {
+            Log.e(TAG, this.toString());
             throw new OperationApplicationException("wrong number of rows: " + numRows);
         }
 
@@ -289,6 +295,7 @@
             String key = entry.getKey();
             Integer backRefIndex = mValuesBackReferences.getAsInteger(key);
             if (backRefIndex == null) {
+                Log.e(TAG, this.toString());
                 throw new IllegalArgumentException("values backref " + key + " is not an integer");
             }
             values.put(key, backRefToValue(backRefs, numBackRefs, backRefIndex));
@@ -326,6 +333,17 @@
         return newArgs;
     }
 
+    @Override
+    public String toString() {
+        return "mType: " + mType + ", mUri: " + mUri +
+                ", mSelection: " + mSelection +
+                ", mExpectedCount: " + mExpectedCount +
+                ", mYieldAllowed: " + mYieldAllowed +
+                ", mValues: " + mValues +
+                ", mValuesBackReferences: " + mValuesBackReferences +
+                ", mSelectionArgsBackReferences: " + mSelectionArgsBackReferences;
+    }
+
     /**
      * Return the string representation of the requested back reference.
      * @param backRefs an array of results
@@ -335,9 +353,10 @@
      * the numBackRefs
      * @return the string representation of the requested back reference.
      */
-    private static long backRefToValue(ContentProviderResult[] backRefs, int numBackRefs,
+    private long backRefToValue(ContentProviderResult[] backRefs, int numBackRefs,
             Integer backRefIndex) {
         if (backRefIndex >= numBackRefs) {
+            Log.e(TAG, this.toString());
             throw new ArrayIndexOutOfBoundsException("asked for back ref " + backRefIndex
                     + " but there are only " + numBackRefs + " back refs");
         }
diff --git a/core/java/android/content/ContentValues.java b/core/java/android/content/ContentValues.java
index 532cc03..c04625d 100644
--- a/core/java/android/content/ContentValues.java
+++ b/core/java/android/content/ContentValues.java
@@ -39,14 +39,14 @@
      * Creates an empty set of values using the default initial size
      */
     public ContentValues() {
-        // Choosing a default size of 8 based on analysis of typical 
+        // Choosing a default size of 8 based on analysis of typical
         // consumption by applications.
         mValues = new HashMap<String, Object>(8);
     }
 
     /**
      * Creates an empty set of values using the given initial size
-     * 
+     *
      * @param size the initial size of the set of values
      */
     public ContentValues(int size) {
@@ -55,7 +55,7 @@
 
     /**
      * Creates a set of values copied from the given set
-     * 
+     *
      * @param from the values to copy
      */
     public ContentValues(ContentValues from) {
@@ -65,7 +65,7 @@
     /**
      * Creates a set of values copied from the given HashMap. This is used
      * by the Parcel unmarshalling code.
-     * 
+     *
      * @param from the values to start with
      * {@hide}
      */
@@ -174,7 +174,7 @@
     public void put(String key, Boolean value) {
         mValues.put(key, value);
     }
-    
+
     /**
      * Adds a value to the set.
      *
@@ -187,7 +187,7 @@
 
     /**
      * Adds a null value to the set.
-     * 
+     *
      * @param key the name of the value to make null
      */
     public void putNull(String key) {
@@ -196,7 +196,7 @@
 
     /**
      * Returns the number of values.
-     * 
+     *
      * @return the number of values
      */
     public int size() {
@@ -223,7 +223,7 @@
      * Returns true if this object has the named value.
      *
      * @param key the value to check for
-     * @return {@code true} if the value is present, {@code false} otherwise 
+     * @return {@code true} if the value is present, {@code false} otherwise
      */
     public boolean containsKey(String key) {
         return mValues.containsKey(key);
@@ -242,7 +242,7 @@
 
     /**
      * Gets a value and converts it to a String.
-     * 
+     *
      * @param key the value to get
      * @return the String for the value
      */
@@ -253,7 +253,7 @@
 
     /**
      * Gets a value and converts it to a Long.
-     * 
+     *
      * @param key the value to get
      * @return the Long value, or null if the value is missing or cannot be converted
      */
@@ -270,7 +270,7 @@
                     return null;
                 }
             } else {
-                Log.e(TAG, "Cannot cast value for " + key + " to a Long");
+                Log.e(TAG, "Cannot cast value for " + key + " to a Long: " + value, e);
                 return null;
             }
         }
@@ -278,7 +278,7 @@
 
     /**
      * Gets a value and converts it to an Integer.
-     * 
+     *
      * @param key the value to get
      * @return the Integer value, or null if the value is missing or cannot be converted
      */
@@ -295,7 +295,7 @@
                     return null;
                 }
             } else {
-                Log.e(TAG, "Cannot cast value for " + key + " to a Integer");
+                Log.e(TAG, "Cannot cast value for " + key + " to a Integer: " + value, e);
                 return null;
             }
         }
@@ -303,7 +303,7 @@
 
     /**
      * Gets a value and converts it to a Short.
-     * 
+     *
      * @param key the value to get
      * @return the Short value, or null if the value is missing or cannot be converted
      */
@@ -320,7 +320,7 @@
                     return null;
                 }
             } else {
-                Log.e(TAG, "Cannot cast value for " + key + " to a Short");
+                Log.e(TAG, "Cannot cast value for " + key + " to a Short: " + value, e);
                 return null;
             }
         }
@@ -328,7 +328,7 @@
 
     /**
      * Gets a value and converts it to a Byte.
-     * 
+     *
      * @param key the value to get
      * @return the Byte value, or null if the value is missing or cannot be converted
      */
@@ -345,7 +345,7 @@
                     return null;
                 }
             } else {
-                Log.e(TAG, "Cannot cast value for " + key + " to a Byte");
+                Log.e(TAG, "Cannot cast value for " + key + " to a Byte: " + value, e);
                 return null;
             }
         }
@@ -353,7 +353,7 @@
 
     /**
      * Gets a value and converts it to a Double.
-     * 
+     *
      * @param key the value to get
      * @return the Double value, or null if the value is missing or cannot be converted
      */
@@ -370,7 +370,7 @@
                     return null;
                 }
             } else {
-                Log.e(TAG, "Cannot cast value for " + key + " to a Double");
+                Log.e(TAG, "Cannot cast value for " + key + " to a Double: " + value, e);
                 return null;
             }
         }
@@ -378,7 +378,7 @@
 
     /**
      * Gets a value and converts it to a Float.
-     * 
+     *
      * @param key the value to get
      * @return the Float value, or null if the value is missing or cannot be converted
      */
@@ -395,7 +395,7 @@
                     return null;
                 }
             } else {
-                Log.e(TAG, "Cannot cast value for " + key + " to a Float");
+                Log.e(TAG, "Cannot cast value for " + key + " to a Float: " + value, e);
                 return null;
             }
         }
@@ -403,7 +403,7 @@
 
     /**
      * Gets a value and converts it to a Boolean.
-     * 
+     *
      * @param key the value to get
      * @return the Boolean value, or null if the value is missing or cannot be converted
      */
@@ -415,7 +415,7 @@
             if (value instanceof CharSequence) {
                 return Boolean.valueOf(value.toString());
             } else {
-                Log.e(TAG, "Cannot cast value for " + key + " to a Boolean");
+                Log.e(TAG, "Cannot cast value for " + key + " to a Boolean: " + value, e);
                 return null;
             }
         }
@@ -424,7 +424,7 @@
     /**
      * Gets a value that is a byte array. Note that this method will not convert
      * any other types to byte arrays.
-     * 
+     *
      * @param key the value to get
      * @return the byte[] value, or null is the value is missing or not a byte[]
      */
@@ -439,13 +439,13 @@
 
     /**
      * Returns a set of all of the keys and values
-     * 
+     *
      * @return a set of all of the keys and values
      */
     public Set<Map.Entry<String, Object>> valueSet() {
         return mValues.entrySet();
     }
-    
+
     public static final Parcelable.Creator<ContentValues> CREATOR =
             new Parcelable.Creator<ContentValues>() {
         @SuppressWarnings({"deprecation", "unchecked"})
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d31b25b..1b0437c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1815,11 +1815,18 @@
 
     /**
      * Broadcast Action:  A sticky broadcast indicating the phone was docked
-     * or undocked.  Includes the extra
-     * field {@link #EXTRA_DOCK_STATE}, containing the current dock state. It also
-     * includes the boolean extra field {@link #EXTRA_CAR_MODE_ENABLED}, indicating
-     * the state of the car mode.
-     * This is intended for monitoring the current dock state.
+     * or undocked.
+     *
+     * <p>The intent will have the following extra values:
+     * <ul>
+     *   <li><em>{@link #EXTRA_DOCK_STATE}</em> - the current dock
+     *       state, which depends on the state of the car mode.</li>
+     *   <li><em>{@link #EXTRA_PHYSICAL_DOCK_STATE}</em> - the physical dock
+     *       state.</li>
+     *   <li><em>{@link #EXTRA_CAR_MODE_ENABLED}</em> - a boolean indicating the
+     *       state of the car mode.</li>
+     * </ul>
+     * <p>This is intended for monitoring the current dock state.
      * To launch an activity from a dock state change, use {@link #CATEGORY_CAR_DOCK}
      * or {@link #CATEGORY_DESK_DOCK} instead.
      */
@@ -2154,6 +2161,16 @@
     public static final int EXTRA_DOCK_STATE_CAR = 2;
 
     /**
+     * Used as an int extra field in {@link android.content.Intent#ACTION_DOCK_EVENT}
+     * intents to request the physical dock state. Possible values are
+     * {@link android.content.Intent#EXTRA_DOCK_STATE_UNDOCKED},
+     * {@link android.content.Intent#EXTRA_DOCK_STATE_DESK}, or
+     * {@link android.content.Intent#EXTRA_DOCK_STATE_CAR}.
+     */
+    public static final String EXTRA_PHYSICAL_DOCK_STATE =
+            "android.intent.extra.PHYSICAL_DOCK_STATE";
+
+    /**
      * Used as an boolean extra field in {@link android.content.Intent#ACTION_DOCK_EVENT}
      * intents to indicate that the car mode is enabled or not.
      */
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 9ff2e25..317e5a9 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -115,6 +115,11 @@
     private static final long DEFAULT_MAX_SYNC_RETRY_TIME_IN_SECONDS = 60 * 60; // one hour
 
     /**
+     * How long to wait before retrying a sync that failed due to one already being in progress.
+     */
+    private static final int DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS = 10;
+
+    /**
      * An error notification is sent if sync of any of the providers has been failing for this long.
      */
     private static final long ERROR_NOTIFICATION_DELAY_MS = 1000 * 60 * 10; // 10 minutes
@@ -447,17 +452,6 @@
     }
 
     /**
-     * Returns whether or not sync is enabled.  Sync can be enabled by
-     * setting the system property "ro.config.sync" to the value "yes".
-     * This is normally done at boot time on builds that support sync.
-     * @return true if sync is enabled
-     */
-    private boolean isSyncEnabled() {
-        // Require the precise value "yes" to discourage accidental activation.
-        return "yes".equals(SystemProperties.get("ro.config.sync"));
-    }
-
-    /**
      * Initiate a sync. This can start a sync for all providers
      * (pass null to url, set onlyTicklable to false), only those
      * providers that are marked as ticklable (pass null to url,
@@ -488,13 +482,6 @@
             Bundle extras, long delay, boolean onlyThoseWithUnkownSyncableState) {
         boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
 
-        if (!isSyncEnabled()) {
-            if (isLoggable) {
-                Log.v(TAG, "not syncing because sync is disabled");
-            }
-            return;
-        }
-
         final boolean backgroundDataUsageAllowed = !mBootCompleted ||
                 getConnectivityManager().getBackgroundDataSetting();
 
@@ -825,6 +812,14 @@
                         + "it achieved some success");
             }
             scheduleSyncOperation(operation);
+        } else if (syncResult.syncAlreadyInProgress) {
+            if (isLoggable) {
+                Log.d(TAG, "retrying sync operation that failed because there was already a "
+                        + "sync in progress: " + operation);
+            }
+            scheduleSyncOperation(new SyncOperation(operation.account, operation.syncSource,
+                    operation.authority, operation.extras,
+                    DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS));
         } else if (syncResult.hasSoftError()) {
             if (isLoggable) {
                 Log.d(TAG, "retrying sync operation because it encountered a soft error: "
@@ -922,9 +917,7 @@
     protected void dump(FileDescriptor fd, PrintWriter pw) {
         StringBuilder sb = new StringBuilder();
         dumpSyncState(pw, sb);
-        if (isSyncEnabled()) {
-            dumpSyncHistory(pw, sb);
-        }
+        dumpSyncHistory(pw, sb);
 
         pw.println();
         pw.println("SyncAdapters:");
@@ -940,7 +933,6 @@
     }
 
     protected void dumpSyncState(PrintWriter pw, StringBuilder sb) {
-        pw.print("sync enabled: "); pw.println(isSyncEnabled());
         pw.print("data connected: "); pw.println(mDataConnectionIsConnected);
         pw.print("memory low: "); pw.println(mStorageIsLow);
 
@@ -1456,11 +1448,6 @@
                 boolean backgroundDataUsageAllowed) {
             Account[] accounts = mAccounts;
 
-            // Sync is disabled, drop this operation.
-            if (!isSyncEnabled()) {
-                return false;
-            }
-
             // skip the sync if the account of this operation no longer exists
             if (!ArrayUtils.contains(accounts, account)) {
                 return false;
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 123d9b7..2e405c1 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -68,8 +68,6 @@
      * will be null if the application does not specify it in its manifest.
      * 
      * <p>If android:allowBackup is set to false, this attribute is ignored.
-     * 
-     * {@hide}
      */
     public String backupAgentName;
     
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 47789a5..f793a00 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -26,6 +26,7 @@
 import android.content.pm.IPackageInstallObserver;
 import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.IPackageDataObserver;
+import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
@@ -153,6 +154,8 @@
     void installPackage(in Uri packageURI, IPackageInstallObserver observer, int flags,
             in String installerPackageName);
 
+    void finishPackageInstall(int token);
+
     /**
      * Delete a package.
      *
@@ -309,4 +312,6 @@
     void updateExternalMediaStatus(boolean mounted);
 
     String nextPackageToClean(String lastPackage);
+
+    void movePackage(String packageName, IPackageMoveObserver observer, int flags);
 }
diff --git a/core/java/android/content/pm/IPackageMoveObserver.aidl b/core/java/android/content/pm/IPackageMoveObserver.aidl
new file mode 100644
index 0000000..baa1595
--- /dev/null
+++ b/core/java/android/content/pm/IPackageMoveObserver.aidl
@@ -0,0 +1,27 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.content.pm;
+
+/**
+ * Callback for moving package resources from the Package Manager.
+ * @hide
+ */
+oneway interface IPackageMoveObserver {
+    void packageMoved(in String packageName, int returnCode);
+}
+
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index ff2ed3d..2edb430 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -551,6 +551,69 @@
     public static final int DONT_DELETE_DATA = 0x00000001;
 
     /**
+     * Return code that is passed to the {@link IPackageMoveObserver} by
+     * {@link #movePackage(android.net.Uri, IPackageMoveObserver)}
+     * when the package has been successfully moved by the system.
+     * @hide
+     */
+    public static final int MOVE_SUCCEEDED = 1;
+    /**
+     * Error code that is passed to the {@link IPackageMoveObserver} by
+     * {@link #movePackage(android.net.Uri, IPackageMoveObserver)}
+     * when the package hasn't been successfully moved by the system
+     * because of insufficient memory on specified media.
+     * @hide
+     */
+    public static final int MOVE_FAILED_INSUFFICIENT_STORAGE = -1;
+
+    /**
+     * Error code that is passed to the {@link IPackageMoveObserver} by
+     * {@link #movePackage(android.net.Uri, IPackageMoveObserver)}
+     * if the specified package doesn't exist.
+     * @hide
+     */
+    public static final int MOVE_FAILED_DOESNT_EXIST = -2;
+
+    /**
+     * Error code that is passed to the {@link IPackageMoveObserver} by
+     * {@link #movePackage(android.net.Uri, IPackageMoveObserver)}
+     * if the specified package cannot be moved since its a system package.
+     * @hide
+     */
+    public static final int MOVE_FAILED_SYSTEM_PACKAGE = -3;
+
+    /**
+     * Error code that is passed to the {@link IPackageMoveObserver} by
+     * {@link #movePackage(android.net.Uri, IPackageMoveObserver)}
+     * if the specified package cannot be moved since its forward locked.
+     * @hide
+     */
+    public static final int MOVE_FAILED_FORWARD_LOCKED = -4;
+
+    /**
+     * Error code that is passed to the {@link IPackageMoveObserver} by
+     * {@link #movePackage(android.net.Uri, IPackageMoveObserver)}
+     * if the specified package cannot be moved to the specified location.
+     * @hide
+     */
+    public static final int MOVE_FAILED_INVALID_LOCATION = -5;
+
+    /**
+     * Flag parameter for {@link #movePackage} to indicate that
+     * the package should be moved to internal storage if its
+     * been installed on external media.
+     * @hide
+     */
+    public static final int MOVE_INTERNAL = 0x00000001;
+
+    /**
+     * Flag parameter for {@link #movePackage} to indicate that
+     * the package should be moved to external media.
+     * @hide
+     */
+    public static final int MOVE_EXTERNAL_MEDIA = 0x00000002;
+
+    /**
      * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device has a camera facing away
      * from the screen.
@@ -1153,7 +1216,9 @@
      *
      * @return Returns a ResolveInfo containing the final activity intent that
      *         was determined to be the best action.  Returns null if no
-     *         matching activity was found.
+     *         matching activity was found. If multiple matching activities are
+     *         found and there is no default set, returns a ResolveInfo
+     *         containing something else, such as the activity resolver.
      *
      * @see #MATCH_DEFAULT_ONLY
      * @see #GET_INTENT_FILTERS
@@ -1920,4 +1985,23 @@
      * Return whether the device has been booted into safe mode.
      */
     public abstract boolean isSafeMode();
+
+    /**
+     * Attempts to move package resources from internal to external media or vice versa.
+     * Since this may take a little while, the result will
+     * be posted back to the given observer.   This call may fail if the calling context
+     * lacks the {@link android.Manifest.permission#MOVE_PACKAGE} permission, if the
+     * named package cannot be found, or if the named package is a "system package".
+     *
+     * @param packageName The name of the package to delete
+     * @param observer An observer callback to get notified when the package move is
+     * complete. {@link android.content.pm.IPackageMoveObserver#packageMoved(boolean)} will be
+     * called when that happens.  observer may be null to indicate that no callback is desired.
+     * @param flags To indicate install location {@link #MOVE_INTERNAL} or
+     * {@link #MOVE_EXTERNAL_MEDIA}
+     *
+     * @hide
+     */
+    public abstract void movePackage(
+            String packageName, IPackageMoveObserver observer, int flags);
 }
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index aa5f128..6490b65 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -193,6 +193,11 @@
     public int uiMode;
 
     /**
+     * @hide Internal book-keeping.
+     */
+    public int seq;
+    
+    /**
      * Construct an invalid Configuration.  You must call {@link #setToDefaults}
      * for this object to be valid.  {@more}
      */
@@ -220,6 +225,7 @@
         orientation = o.orientation;
         screenLayout = o.screenLayout;
         uiMode = o.uiMode;
+        seq = o.seq;
     }
 
     public String toString() {
@@ -250,6 +256,10 @@
         sb.append(screenLayout);
         sb.append(" uiMode=");
         sb.append(uiMode);
+        if (seq != 0) {
+            sb.append(" seq=");
+            sb.append(seq);
+        }
         sb.append('}');
         return sb.toString();
     }
@@ -260,7 +270,7 @@
     public void setToDefaults() {
         fontScale = 1;
         mcc = mnc = 0;
-        locale = Locale.getDefault();
+        locale = null;
         userSetLocale = false;
         touchscreen = TOUCHSCREEN_UNDEFINED;
         keyboard = KEYBOARD_UNDEFINED;
@@ -271,6 +281,7 @@
         orientation = ORIENTATION_UNDEFINED;
         screenLayout = SCREENLAYOUT_SIZE_UNDEFINED;
         uiMode = UI_MODE_TYPE_NORMAL;
+        seq = 0;
     }
 
     /** {@hide} */
@@ -357,6 +368,10 @@
             uiMode = delta.uiMode;
         }
         
+        if (delta.seq != 0) {
+            seq = delta.seq;
+        }
+        
         return changed;
     }
 
@@ -456,6 +471,35 @@
     }
     
     /**
+     * @hide Return true if the sequence of 'other' is better than this.  Assumes
+     * that 'this' is your current sequence and 'other' is a new one you have
+     * received some how and want to compare with what you have.
+     */
+    public boolean isOtherSeqNewer(Configuration other) {
+        if (other == null) {
+            // Sanity check.
+            return false;
+        }
+        if (other.seq == 0) {
+            // If the other sequence is not specified, then we must assume
+            // it is newer since we don't know any better.
+            return true;
+        }
+        if (seq == 0) {
+            // If this sequence is not specified, then we also consider the
+            // other is better.  Yes we have a preference for other.  Sue us.
+            return true;
+        }
+        int diff = other.seq - seq;
+        if (diff > 0x10000) {
+            // If there has been a sufficiently large jump, assume the
+            // sequence has wrapped around.
+            return false;
+        }
+        return diff > 0;
+    }
+    
+    /**
      * Parcelable methods
      */
     public int describeContents() {
@@ -488,6 +532,7 @@
         dest.writeInt(orientation);
         dest.writeInt(screenLayout);
         dest.writeInt(uiMode);
+        dest.writeInt(seq);
     }
 
     public static final Parcelable.Creator<Configuration> CREATOR
@@ -522,6 +567,7 @@
         orientation = source.readInt();
         screenLayout = source.readInt();
         uiMode = source.readInt();
+        seq = source.readInt();
     }
 
     public int compareTo(Configuration that) {
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index ae8e297..a5e39d4 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -39,6 +39,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.ref.WeakReference;
+import java.util.Locale;
 
 /**
  * Class for accessing an application's resources.  This sits on top of the
@@ -1259,6 +1260,9 @@
             if (config != null) {
                 configChanges = mConfiguration.updateFrom(config);
             }
+            if (mConfiguration.locale == null) {
+                mConfiguration.locale = Locale.getDefault();
+            }
             if (metrics != null) {
                 mMetrics.setTo(metrics);
                 mMetrics.updateMetrics(mCompatibilityInfo,
diff --git a/core/java/android/database/sqlite/SQLiteClosable.java b/core/java/android/database/sqlite/SQLiteClosable.java
index 7776520..e589f34 100644
--- a/core/java/android/database/sqlite/SQLiteClosable.java
+++ b/core/java/android/database/sqlite/SQLiteClosable.java
@@ -16,6 +16,8 @@
 
 package android.database.sqlite;
 
+import android.database.CursorWindow;
+
 /**
  * An object create from a SQLiteDatabase that can be closed.
  */
@@ -29,9 +31,9 @@
         synchronized(mLock) {
             if (mReferenceCount <= 0) {
                 throw new IllegalStateException(
-                        "attempt to acquire a reference on an already-closed SQLiteClosable obj.");
+                        "attempt to acquire a reference on an already-closed " + getObjInfo());
             }
-            mReferenceCount++;     
+            mReferenceCount++;
         }
     }
     
@@ -52,4 +54,24 @@
             }
         }        
     }
+
+    private String getObjInfo() {
+        StringBuilder buff = new StringBuilder();
+        buff.append(this.getClass().getName());
+        buff.append(" Obj");
+        buff.append(" (");
+        if (this instanceof SQLiteDatabase) {
+            buff.append("database = ");
+            buff.append(((SQLiteDatabase)this).getPath());
+        } else if (this instanceof SQLiteProgram || this instanceof SQLiteStatement ||
+                this instanceof SQLiteQuery) {
+            buff.append("mSql = ");
+            buff.append(((SQLiteProgram)this).mSql);
+        } else if (this instanceof CursorWindow) {
+            buff.append("mStartPos = ");
+            buff.append(((CursorWindow)this).getStartPosition());
+        }
+        buff.append(") ");
+        return buff.toString();
+    }
 }
diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java
index 79527b4..eb85822 100644
--- a/core/java/android/database/sqlite/SQLiteCompiledSql.java
+++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java
@@ -44,6 +44,9 @@
      */
     /* package */ int nStatement = 0;
 
+    /** when in cache and is in use, this member is set */
+    private boolean mInUse = false;
+
     /* package */ SQLiteCompiledSql(SQLiteDatabase db, String sql) {
         mDatabase = db;
         this.nHandle = db.mNativeHandle;
@@ -92,6 +95,18 @@
         }
     }
 
+    /* package */ synchronized boolean isInUse() {
+        return mInUse;
+    }
+
+    /* package */ synchronized void acquire() {
+        mInUse = true;
+    }
+
+    /* package */ synchronized void release() {
+        mInUse = false;
+    }
+
     /**
      * Make sure that the native resource is cleaned up.
      */
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index 2d0aa39..2bb2f5d 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -58,32 +58,51 @@
 
             // add it to the cache of compiled-sqls
             db.addToCompiledQueries(sql, mCompiledSql);
+            mCompiledSql.acquire();
+        } else {
+            // it is already in compiled-sql cache.
+            if (mCompiledSql.isInUse()) {
+                // but the CompiledSql in cache is in use by some other SQLiteProgram object.
+                // we can't have two different SQLiteProgam objects can't share the same
+                // CompiledSql object. create a new one.
+                // finalize it when I am done with it in "this" object.
+                mCompiledSql = new SQLiteCompiledSql(db, sql);
+            } else {
+                // the CompiledSql in cache is NOT in use by any other SQLiteProgram object.
+                // it is safe to give it to this SQLIteProgram Object.
+                mCompiledSql.acquire();
+            }
         }
         nStatement = mCompiledSql.nStatement;
     }
 
     @Override
     protected void onAllReferencesReleased() {
-        releaseCompiledSqlIfInCache();
+        releaseCompiledSqlIfNotInCache();
         mDatabase.releaseReference();
         mDatabase.removeSQLiteClosable(this);
     }
 
     @Override
     protected void onAllReferencesReleasedFromContainer() {
-        releaseCompiledSqlIfInCache();
+        releaseCompiledSqlIfNotInCache();
         mDatabase.releaseReference();
     }
 
-    private void releaseCompiledSqlIfInCache() {
+    private void releaseCompiledSqlIfNotInCache() {
         if (mCompiledSql == null) {
             return;
         }
         synchronized(mDatabase.mCompiledQueries) {
             if (!mDatabase.mCompiledQueries.containsValue(mCompiledSql)) {
+                // it is NOT in compiled-sql cache. i.e., responsibility of
+                // release this statement is on me.
                 mCompiledSql.releaseSqlStatement();
                 mCompiledSql = null; // so that GC doesn't call finalize() on it
                 nStatement = 0;
+            } else {
+                // it is in compiled-sql cache. reset its CompiledSql#mInUse flag
+                mCompiledSql.release();
             }
         }
     }
diff --git a/core/java/android/gesture/Learner.java b/core/java/android/gesture/Learner.java
index 60997e0..a105652 100755
--- a/core/java/android/gesture/Learner.java
+++ b/core/java/android/gesture/Learner.java
@@ -72,7 +72,8 @@
         for (int i = 0; i < count; i++) {
             final Instance instance = instances.get(i);
             // the label can be null, as specified in Instance
-            if ((instance.label == null && name == null) || instance.label.equals(name)) {
+            if ((instance.label == null && name == null)
+                    || (instance.label != null && instance.label.equals(name))) {
                 toDelete.add(instance);
             }
         }
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index c0bff66..6dba94d 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -26,7 +26,7 @@
 import android.util.Log;
 import android.view.Surface;
 import android.view.SurfaceHolder;
-import android.graphics.PixelFormat;
+import android.graphics.ImageFormat;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -192,7 +192,7 @@
          * The callback that delivers the preview frames.
          *
          * @param data The contents of the preview frame in the format defined
-         *  by {@link android.graphics.PixelFormat}, which can be queried
+         *  by {@link android.graphics.ImageFormat}, which can be queried
          *  with {@link android.hardware.Camera.Parameters#getPreviewFormat()}.
          *  If {@link android.hardware.Camera.Parameters#setPreviewFormat(int)}
          *             is never called, the default will be the YCbCr_420_SP
@@ -276,7 +276,7 @@
      * Adds a pre-allocated buffer to the callback buffer queue.
      * Preview width and height can be determined from getPreviewSize, and bitsPerPixel can be
      * found from from  {@link android.hardware.Camera.Parameters#getPreviewFormat()} and
-     * {@link android.graphics.PixelFormat#getPixelFormatInfo(int, PixelFormat)}
+     * {@link android.graphics.ImageFormat#getBitsPerPixel(int)}
      *
      * Alternatively, a buffer from a previous callback may be passed in or used
      * to determine the size of new preview frame buffers.
@@ -1086,15 +1086,15 @@
         /**
          * Sets the image format for preview pictures.
          * <p>If this is never called, the default format will be
-         * {@link android.graphics.PixelFormat#YCbCr_420_SP}, which
+         * {@link android.graphics.ImageFormat#NV21}, which
          * uses the NV21 encoding format.</p>
          *
          * @param pixel_format the desired preview picture format, defined
-         *   by one of the {@link android.graphics.PixelFormat} constants.
-         *   (E.g., <var>PixelFormat.YCbCr_420_SP</var> (default),
-         *                      <var>PixelFormat.RGB_565</var>, or
-         *                      <var>PixelFormat.JPEG</var>)
-         * @see android.graphics.PixelFormat
+         *   by one of the {@link android.graphics.ImageFormat} constants.
+         *   (E.g., <var>ImageFormat.NV21</var> (default),
+         *                      <var>ImageFormat.RGB_565</var>, or
+         *                      <var>ImageFormat.JPEG</var>)
+         * @see android.graphics.ImageFormat
          */
         public void setPreviewFormat(int pixel_format) {
             String s = cameraFormatForPixelFormat(pixel_format);
@@ -1110,7 +1110,7 @@
          * Returns the image format for preview pictures got from
          * {@link PreviewCallback}.
          *
-         * @return the {@link android.graphics.PixelFormat} int representing
+         * @return the {@link android.graphics.ImageFormat} int representing
          *         the preview picture format.
          */
         public int getPreviewFormat() {
@@ -1128,7 +1128,7 @@
             ArrayList<Integer> formats = new ArrayList<Integer>();
             for (String s : split(str)) {
                 int f = pixelFormatForCameraFormat(s);
-                if (f == PixelFormat.UNKNOWN) continue;
+                if (f == ImageFormat.UNKNOWN) continue;
                 formats.add(f);
             }
             return formats;
@@ -1171,10 +1171,10 @@
          * Sets the image format for pictures.
          *
          * @param pixel_format the desired picture format
-         *                     (<var>PixelFormat.YCbCr_420_SP (NV21)</var>,
-         *                      <var>PixelFormat.RGB_565</var>, or
-         *                      <var>PixelFormat.JPEG</var>)
-         * @see android.graphics.PixelFormat
+         *                     (<var>ImageFormat.NV21</var>,
+         *                      <var>ImageFormat.RGB_565</var>, or
+         *                      <var>ImageFormat.JPEG</var>)
+         * @see android.graphics.ImageFormat
          */
         public void setPictureFormat(int pixel_format) {
             String s = cameraFormatForPixelFormat(pixel_format);
@@ -1189,7 +1189,7 @@
         /**
          * Returns the image format for pictures.
          *
-         * @return the PixelFormat int representing the picture format
+         * @return the ImageFormat int representing the picture format
          */
         public int getPictureFormat() {
             return pixelFormatForCameraFormat(get(KEY_PICTURE_FORMAT));
@@ -1198,7 +1198,7 @@
         /**
          * Gets the supported picture formats.
          *
-         * @return a List of Integer objects (values are PixelFormat.XXX). This
+         * @return a List of Integer objects (values are ImageFormat.XXX). This
          *         method will always return a list with at least one element.
          */
         public List<Integer> getSupportedPictureFormats() {
@@ -1206,7 +1206,7 @@
             ArrayList<Integer> formats = new ArrayList<Integer>();
             for (String s : split(str)) {
                 int f = pixelFormatForCameraFormat(s);
-                if (f == PixelFormat.UNKNOWN) continue;
+                if (f == ImageFormat.UNKNOWN) continue;
                 formats.add(f);
             }
             return formats;
@@ -1214,35 +1214,35 @@
 
         private String cameraFormatForPixelFormat(int pixel_format) {
             switch(pixel_format) {
-            case PixelFormat.YCbCr_422_SP: return PIXEL_FORMAT_YUV422SP;
-            case PixelFormat.YCbCr_420_SP: return PIXEL_FORMAT_YUV420SP;
-            case PixelFormat.YCbCr_422_I:  return PIXEL_FORMAT_YUV422I;
-            case PixelFormat.RGB_565:      return PIXEL_FORMAT_RGB565;
-            case PixelFormat.JPEG:         return PIXEL_FORMAT_JPEG;
-            default:                       return null;
+            case ImageFormat.NV16:      return PIXEL_FORMAT_YUV422SP;
+            case ImageFormat.NV21:      return PIXEL_FORMAT_YUV420SP;
+            case ImageFormat.YUY2:      return PIXEL_FORMAT_YUV422I;
+            case ImageFormat.RGB_565:   return PIXEL_FORMAT_RGB565;
+            case ImageFormat.JPEG:      return PIXEL_FORMAT_JPEG;
+            default:                    return null;
             }
         }
 
         private int pixelFormatForCameraFormat(String format) {
             if (format == null)
-                return PixelFormat.UNKNOWN;
+                return ImageFormat.UNKNOWN;
 
             if (format.equals(PIXEL_FORMAT_YUV422SP))
-                return PixelFormat.YCbCr_422_SP;
+                return ImageFormat.NV16;
 
             if (format.equals(PIXEL_FORMAT_YUV420SP))
-                return PixelFormat.YCbCr_420_SP;
+                return ImageFormat.NV21;
 
             if (format.equals(PIXEL_FORMAT_YUV422I))
-                return PixelFormat.YCbCr_422_I;
+                return ImageFormat.YUY2;
 
             if (format.equals(PIXEL_FORMAT_RGB565))
-                return PixelFormat.RGB_565;
+                return ImageFormat.RGB_565;
 
             if (format.equals(PIXEL_FORMAT_JPEG))
-                return PixelFormat.JPEG;
+                return ImageFormat.JPEG;
 
-            return PixelFormat.UNKNOWN;
+            return ImageFormat.UNKNOWN;
         }
 
         /**
diff --git a/core/java/android/os/HandlerThread.java b/core/java/android/os/HandlerThread.java
index 65301e4..911439a 100644
--- a/core/java/android/os/HandlerThread.java
+++ b/core/java/android/os/HandlerThread.java
@@ -53,9 +53,9 @@
         Looper.prepare();
         synchronized (this) {
             mLooper = Looper.myLooper();
-            Process.setThreadPriority(mPriority);
             notifyAll();
         }
+        Process.setThreadPriority(mPriority);
         onLooperPrepared();
         Looper.loop();
         mTid = -1;
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index f48f45f..92041d8 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -148,4 +148,18 @@
      */
     void detachPppd(String tty);
 
+    /**
+     * Turn on USB RNDIS support - this will turn off thinks like adb/mass-storage
+     */
+    void startUsbRNDIS();
+
+    /**
+     * Turn off USB RNDIS support
+     */
+    void stopUsbRNDIS();
+
+    /**
+     * Check the status of USB RNDIS support
+     */
+    boolean isUsbRNDISStarted();
 }
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 4130109..476da1d 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -40,20 +40,36 @@
      */
     public int what;
 
-    // Use these fields instead of using the class's Bundle if you can. 
-    /** arg1 and arg2 are lower-cost alternatives to using {@link #setData(Bundle) setData()}
-    if you only need to store a few integer values. */
+    /**
+     * arg1 and arg2 are lower-cost alternatives to using
+     * {@link #setData(Bundle) setData()} if you only need to store a
+     * few integer values.
+     */
     public int arg1; 
 
-    /** arg1 and arg2 are lower-cost alternatives to using {@link #setData(Bundle) setData()}
-    if you only need to store a few integer values.*/ 
+    /**
+     * arg1 and arg2 are lower-cost alternatives to using
+     * {@link #setData(Bundle) setData()} if you only need to store a
+     * few integer values.
+     */
     public int arg2;
 
-    /** An arbitrary object to send to the recipient.  This must be null when
-     * sending messages across processes. */
+    /**
+     * An arbitrary object to send to the recipient.  When using
+     * {@link Messenger} to send the message across processes this can only
+     * be non-null if it contains a Parcelable of a framework class (not one
+     * implemented by the application).   For other data transfer use
+     * {@link #setData}.
+     * 
+     * <p>Note that Parcelable objects here are not supported prior to
+     * the {@link android.os.Build.VERSION_CODES#FROYO} release.
+     */
     public Object obj;
 
-    /** Optional Messenger where replies to this message can be sent.
+    /**
+     * Optional Messenger where replies to this message can be sent.  The
+     * semantics of exactly how this is used are up to the sender and
+     * receiver.
      */
     public Messenger replyTo;
     
@@ -278,14 +294,22 @@
      * the <em>target</em> {@link Handler} that is receiving this Message to
      * dispatch it.  If
      * not set, the message will be dispatched to the receiving Handler's
-     * {@link Handler#handleMessage(Message Handler.handleMessage())}. */
+     * {@link Handler#handleMessage(Message Handler.handleMessage())}.
+     */
     public Runnable getCallback() {
         return callback;
     }
     
     /** 
      * Obtains a Bundle of arbitrary data associated with this
-     * event, lazily creating it if necessary. Set this value by calling {@link #setData(Bundle)}.
+     * event, lazily creating it if necessary. Set this value by calling
+     * {@link #setData(Bundle)}.  Note that when transferring data across
+     * processes via {@link Messenger}, you will need to set your ClassLoader
+     * on the Bundle via {@link Bundle#setClassLoader(ClassLoader)
+     * Bundle.setClassLoader()} so that it can instantiate your objects when
+     * you retrieve them.
+     * @see #peekData()
+     * @see #setData(Bundle)
      */
     public Bundle getData() {
         if (data == null) {
@@ -297,14 +321,21 @@
 
     /** 
      * Like getData(), but does not lazily create the Bundle.  A null
-     * is returned if the Bundle does not already exist.
+     * is returned if the Bundle does not already exist.  See
+     * {@link #getData} for further information on this.
+     * @see #getData()
+     * @see #setData(Bundle)
      */
     public Bundle peekData() {
         return data;
     }
 
-    /** Sets a Bundle of arbitrary data values. Use arg1 and arg1 members 
-     * as a lower cost way to send a few simple integer values, if you can. */
+    /**
+     * Sets a Bundle of arbitrary data values. Use arg1 and arg1 members 
+     * as a lower cost way to send a few simple integer values, if you can.
+     * @see #getData() 
+     * @see #peekData()
+     */
     public void setData(Bundle data) {
         this.data = data;
     }
@@ -381,13 +412,25 @@
     }
 
     public void writeToParcel(Parcel dest, int flags) {
-        if (obj != null || callback != null) {
+        if (callback != null) {
             throw new RuntimeException(
-                "Can't marshal objects across processes.");
+                "Can't marshal callbacks across processes.");
         }
         dest.writeInt(what);
         dest.writeInt(arg1);
         dest.writeInt(arg2);
+        if (obj != null) {
+            try {
+                Parcelable p = (Parcelable)obj;
+                dest.writeInt(1);
+                dest.writeParcelable(p, flags);
+            } catch (ClassCastException e) {
+                throw new RuntimeException(
+                    "Can't marshal non-Parcelable objects across processes.");
+            }
+        } else {
+            dest.writeInt(0);
+        }
         dest.writeLong(when);
         dest.writeBundle(data);
         Messenger.writeMessengerOrNullToParcel(replyTo, dest);
@@ -397,6 +440,9 @@
         what = source.readInt();
         arg1 = source.readInt();
         arg2 = source.readInt();
+        if (source.readInt() != 0) {
+            obj = source.readParcelable(getClass().getClassLoader());
+        }
         when = source.readLong();
         data = source.readBundle();
         replyTo = Messenger.readMessengerOrNullFromParcel(source);
diff --git a/core/java/android/os/storage/IMountService.aidl b/core/java/android/os/storage/IMountService.aidl
index 816baf3..79a6cfe 100644
--- a/core/java/android/os/storage/IMountService.aidl
+++ b/core/java/android/os/storage/IMountService.aidl
@@ -63,7 +63,7 @@
      * Safely unmount external storage at given mount point.
      * Returns an int consistent with MountServiceResultCode
      */
-    int unmountVolume(String mountPoint);
+    int unmountVolume(String mountPoint, boolean force);
 
     /**
      * Format external storage given a mount point.
@@ -100,7 +100,7 @@
      * NOTE: Ensure all references are released prior to deleting.
      * Returns an int consistent with MountServiceResultCode
      */
-    int destroySecureContainer(String id);
+    int destroySecureContainer(String id, boolean force);
 
     /*
      * Mount a secure container with the specified key and owner UID.
@@ -112,7 +112,7 @@
      * Unount a secure container.
      * Returns an int consistent with MountServiceResultCode
      */
-    int unmountSecureContainer(String id);
+    int unmountSecureContainer(String id, boolean force);
 
     /*
      * Returns true if the specified container is mounted
diff --git a/core/java/android/os/storage/StorageResultCode.java b/core/java/android/os/storage/StorageResultCode.java
index 249bacf..07d95df 100644
--- a/core/java/android/os/storage/StorageResultCode.java
+++ b/core/java/android/os/storage/StorageResultCode.java
@@ -64,4 +64,10 @@
      */
     public static final int OperationFailedStorageMounted     = -6;
 
+    /**
+     * Operation failed: Storage is busy.
+     * @see android.os.storage.StorageManager
+     */
+    public static final int OperationFailedStorageBusy        = -7;
+
 }
diff --git a/core/java/android/pim/RecurrenceSet.java b/core/java/android/pim/RecurrenceSet.java
index bd7924a..5d09fb5 100644
--- a/core/java/android/pim/RecurrenceSet.java
+++ b/core/java/android/pim/RecurrenceSet.java
@@ -48,7 +48,8 @@
      * events table in the CalendarProvider.
      * @param values The values retrieved from the Events table.
      */
-    public RecurrenceSet(ContentValues values) {
+    public RecurrenceSet(ContentValues values)
+            throws EventRecurrence.InvalidFormatException {
         String rruleStr = values.getAsString(Calendar.Events.RRULE);
         String rdateStr = values.getAsString(Calendar.Events.RDATE);
         String exruleStr = values.getAsString(Calendar.Events.EXRULE);
@@ -65,7 +66,8 @@
      * @param cursor The cursor containing the RRULE, RDATE, EXRULE, and EXDATE
      * columns.
      */
-    public RecurrenceSet(Cursor cursor) {
+    public RecurrenceSet(Cursor cursor)
+            throws EventRecurrence.InvalidFormatException {
         int rruleColumn = cursor.getColumnIndex(Calendar.Events.RRULE);
         int rdateColumn = cursor.getColumnIndex(Calendar.Events.RDATE);
         int exruleColumn = cursor.getColumnIndex(Calendar.Events.EXRULE);
@@ -78,12 +80,14 @@
     }
 
     public RecurrenceSet(String rruleStr, String rdateStr,
-                  String exruleStr, String exdateStr) {
+                  String exruleStr, String exdateStr)
+            throws EventRecurrence.InvalidFormatException {
         init(rruleStr, rdateStr, exruleStr, exdateStr);
     }
 
     private void init(String rruleStr, String rdateStr,
-                      String exruleStr, String exdateStr) {
+                      String exruleStr, String exdateStr)
+            throws EventRecurrence.InvalidFormatException {
         if (!TextUtils.isEmpty(rruleStr) || !TextUtils.isEmpty(rdateStr)) {
 
             if (!TextUtils.isEmpty(rruleStr)) {
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 74a03da..dda9018 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -54,6 +54,13 @@
     private static final String CONTENT_AUTHORITY_SLASH = "content://" + AUTHORITY + "/";
 
     /**
+     * Activity Action: Launch a music player.
+     * The activity should be able to play, browse, or manipulate music files stored on the device.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String INTENT_ACTION_MUSIC_PLAYER = "android.intent.action.MUSIC_PLAYER";
+
+    /**
      * Activity Action: Perform a search for media.
      * Contains at least the {@link android.app.SearchManager#QUERY} extra.
      * May also contain any combination of the following extras:
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index eb48a0c..52de64c 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -28,6 +28,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -226,7 +227,7 @@
             
             @Override
             public void resized(int w, int h, Rect coveredInsets,
-                    Rect visibleInsets, boolean reportDraw) {
+                    Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
                 Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED,
                         reportDraw ? 1 : 0);
                 mCaller.sendMessage(msg);
diff --git a/core/java/android/speech/RecognitionManager.java b/core/java/android/speech/RecognitionManager.java
index 7f55ad6..16b1f89 100644
--- a/core/java/android/speech/RecognitionManager.java
+++ b/core/java/android/speech/RecognitionManager.java
@@ -98,6 +98,9 @@
 
     /** Context with which the manager was created */
     private final Context mContext;
+    
+    /** Component to direct service intent to */
+    private final ComponentName mServiceComponent;
 
     /** Handler that will execute the main tasks */
     private Handler mHandler = new Handler() {
@@ -133,8 +136,9 @@
      * The right way to create a {@code RecognitionManager} is by using
      * {@link #createRecognitionManager} static factory method
      */
-    private RecognitionManager(final Context context) {
+    private RecognitionManager(final Context context, final ComponentName serviceComponent) {
         mContext = context;
+        mServiceComponent = serviceComponent;
     }
 
     /**
@@ -184,11 +188,31 @@
      * @return a new {@code RecognitionManager}
      */
     public static RecognitionManager createRecognitionManager(final Context context) {
+        return createRecognitionManager(context, null);
+    }
+
+    /**
+     * Factory method to create a new {@code RecognitionManager}, please note that
+     * {@link #setRecognitionListener(RecognitionListener)} must be called before dispatching any
+     * command to the created {@code RecognitionManager}.
+     * 
+     * Use this version of the method to specify a specific service to direct this
+     * {@link RecognitionManager} to. Normally you would not use this; use
+     * {@link #createRecognitionManager(Context)} instead to use the system default
+     * recognition service.
+     * 
+     * @param context in which to create {@code RecognitionManager}
+     * @param serviceComponent the {@link ComponentName} of a specific service to direct this
+     *        {@code RecognitionManager} to
+     * @return a new {@code RecognitionManager}
+     */
+    public static RecognitionManager createRecognitionManager(final Context context,
+            final ComponentName serviceComponent) {
         if (context == null) {
             throw new IllegalArgumentException("Context cannot be null)");
         }
         checkIsCalledFromMainThread();
-        return new RecognitionManager(context);
+        return new RecognitionManager(context, serviceComponent);
     }
 
     /**
@@ -222,17 +246,22 @@
             mConnection = new Connection();
             
             Intent serviceIntent = new Intent(RecognitionService.SERVICE_INTERFACE);
-            String serviceComponent = Settings.Secure.getString(mContext.getContentResolver(),
-                    Settings.Secure.VOICE_RECOGNITION_SERVICE);
             
-            if (TextUtils.isEmpty(serviceComponent)) {
-                Log.e(TAG, "no selected voice recognition service");
-                mListener.onError(ERROR_CLIENT);
-                return;
+            if (mServiceComponent == null) {
+                String serviceComponent = Settings.Secure.getString(mContext.getContentResolver(),
+                        Settings.Secure.VOICE_RECOGNITION_SERVICE);
+                
+                if (TextUtils.isEmpty(serviceComponent)) {
+                    Log.e(TAG, "no selected voice recognition service");
+                    mListener.onError(ERROR_CLIENT);
+                    return;
+                }
+                
+                serviceIntent.setComponent(ComponentName.unflattenFromString(serviceComponent));                
+            } else {
+                serviceIntent.setComponent(mServiceComponent);
             }
             
-            serviceIntent.setComponent(ComponentName.unflattenFromString(serviceComponent));
-            
             if (!mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE)) {
                 Log.e(TAG, "bind to recognition service failed");
                 mConnection = null;
diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java
index 5f651e1..7c15cec 100644
--- a/core/java/android/speech/RecognizerIntent.java
+++ b/core/java/android/speech/RecognizerIntent.java
@@ -16,9 +16,17 @@
 
 package android.speech;
 
+import java.util.ArrayList;
+
 import android.app.Activity;
 import android.content.ActivityNotFoundException;
+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.Bundle;
 
 /**
  * Constants for supporting speech recognition through starting an {@link Intent}
@@ -208,4 +216,92 @@
      * an activity result. In a PendingIntent, the lack of this extra indicates failure.
      */
     public static final String EXTRA_RESULTS = "android.speech.extra.RESULTS";
+    
+    /**
+     * Returns the broadcast intent to fire with
+     * {@link Context#sendOrderedBroadcast(Intent, String, BroadcastReceiver, android.os.Handler, int, String, Bundle)}
+     * to receive details from the package that implements voice search.
+     * <p>
+     * This is based on the value specified by the voice search {@link Activity} in
+     * {@link #DETAILS_META_DATA}, and if this is not specified, will return null. Also if there
+     * is no chosen default to resolve for {@link #ACTION_WEB_SEARCH}, this will return null.
+     * <p>
+     * If an intent is returned and is fired, a {@link Bundle} of extras will be returned to the
+     * provided result receiver, and should ideally contain values for
+     * {@link #EXTRA_LANGUAGE_PREFERENCE} and {@link #EXTRA_SUPPORTED_LANGUAGES}.
+     * <p>
+     * (Whether these are actually provided is up to the particular implementation. It is
+     * recommended that {@link Activity}s implementing {@link #ACTION_WEB_SEARCH} provide this
+     * information, but it is not required.)
+     * 
+     * @param context a context object
+     * @return the broadcast intent to fire or null if not available
+     */
+    public static final Intent getVoiceDetailsIntent(Context context) {
+        Intent voiceSearchIntent = new Intent(ACTION_WEB_SEARCH);
+        ResolveInfo ri = context.getPackageManager().resolveActivity(
+                voiceSearchIntent, PackageManager.GET_META_DATA);
+        if (ri == null || ri.activityInfo == null || ri.activityInfo.metaData == null) return null;
+        
+        String className = ri.activityInfo.metaData.getString(DETAILS_META_DATA);
+        if (className == null) return null;
+        
+        Intent detailsIntent = new Intent(ACTION_GET_LANGUAGE_DETAILS);
+        detailsIntent.setComponent(new ComponentName(ri.activityInfo.packageName, className));
+        return detailsIntent;
+    }
+    
+    /**
+     * Meta-data name under which an {@link Activity} implementing {@link #ACTION_WEB_SEARCH} can
+     * use to expose the class name of a {@link BroadcastReceiver} which can respond to request for
+     * more information, from any of the broadcast intents specified in this class.
+     * <p>
+     * Broadcast intents can be directed to the class name specified in the meta-data by creating
+     * an {@link Intent}, setting the component with
+     * {@link Intent#setComponent(android.content.ComponentName)}, and using
+     * {@link Context#sendOrderedBroadcast(Intent, String, BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle)}
+     * with another {@link BroadcastReceiver} which can receive the results.
+     * <p>
+     * The {@link #getVoiceDetailsIntent(Context)} method is provided as a convenience to create
+     * a broadcast intent based on the value of this meta-data, if available.
+     * <p>
+     * This is optional and not all {@link Activity}s which implement {@link #ACTION_WEB_SEARCH}
+     * are required to implement this. Thus retrieving this meta-data may be null.
+     */
+    public static final String DETAILS_META_DATA = "android.speech.DETAILS";
+    
+    /**
+     * A broadcast intent which can be fired to the {@link BroadcastReceiver} component specified
+     * in the meta-data defined in the {@link #DETAILS_META_DATA} meta-data of an
+     * {@link Activity} satisfying {@link #ACTION_WEB_SEARCH}.
+     * <p>
+     * When fired with
+     * {@link Context#sendOrderedBroadcast(Intent, String, BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle)},
+     * a {@link Bundle} of extras will be returned to the provided result receiver, and should
+     * ideally contain values for {@link #EXTRA_LANGUAGE_PREFERENCE} and
+     * {@link #EXTRA_SUPPORTED_LANGUAGES}.
+     * <p>
+     * (Whether these are actually provided is up to the particular implementation. It is
+     * recommended that {@link Activity}s implementing {@link #ACTION_WEB_SEARCH} provide this
+     * information, but it is not required.)
+     */
+    public static final String ACTION_GET_LANGUAGE_DETAILS =
+            "android.speech.action.GET_LANGUAGE_DETAILS";
+    
+    /**
+     * The key to the extra in the {@link Bundle} returned by {@link #ACTION_GET_LANGUAGE_DETAILS}
+     * which is a {@link String} that represents the current language preference this user has
+     * specified - a locale string like "en-US".
+     */
+    public static final String EXTRA_LANGUAGE_PREFERENCE =
+            "android.speech.extra.LANGUAGE_PREFERENCE";
+    
+    /**
+     * The key to the extra in the {@link Bundle} returned by {@link #ACTION_GET_LANGUAGE_DETAILS}
+     * which is an {@link ArrayList} of {@link String}s that represents the languages supported by
+     * this implementation of voice recognition - a list of strings like "en-US", "cmn-Hans-CN",
+     * etc.
+     */
+    public static final String EXTRA_SUPPORTED_LANGUAGES =
+            "android.speech.extra.SUPPORTED_LANGUAGES";
 }
diff --git a/core/java/android/text/AndroidCharacter.java b/core/java/android/text/AndroidCharacter.java
index af93b5d..05887c5 100644
--- a/core/java/android/text/AndroidCharacter.java
+++ b/core/java/android/text/AndroidCharacter.java
@@ -73,6 +73,11 @@
      * Replace the specified slice of <code>text</code> with the chars'
      * right-to-left mirrors (if any), returning true if any
      * replacements were made.
+     *
+     * @param text array of characters to apply mirror operation
+     * @param start first character in array to mirror
+     * @param count maximum number of characters to mirror
+     * @return true if replacements were made
      */
     public native static boolean mirror(char[] text, int start, int count);
 
diff --git a/core/java/android/text/style/LeadingMarginSpan.java b/core/java/android/text/style/LeadingMarginSpan.java
index 6635ddb8..f320701 100644
--- a/core/java/android/text/style/LeadingMarginSpan.java
+++ b/core/java/android/text/style/LeadingMarginSpan.java
@@ -45,7 +45,7 @@
 
     /**
      * Renders the leading margin.  This is called before the margin has been
-     * adjusted by the value returned by {@link getLeadingMargin(boolean)}.
+     * adjusted by the value returned by {@link #getLeadingMargin(boolean)}.
      * 
      * @param c the canvas
      * @param p the paint. The this should be left unchanged on exit.
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 58f998e..c1e1049 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -494,6 +494,9 @@
 
             mLastMotionX = x;
             mLastMotionY = y;
+            if (mCurrentDownEvent != null) {
+                mCurrentDownEvent.recycle();
+            }
             mCurrentDownEvent = MotionEvent.obtain(ev);
             mAlwaysInTapRegion = true;
             mAlwaysInBiggerTapRegion = true;
@@ -562,10 +565,14 @@
 
                 if ((Math.abs(velocityY) > mMinimumFlingVelocity)
                         || (Math.abs(velocityX) > mMinimumFlingVelocity)){
-                    handled = mListener.onFling(mCurrentDownEvent, currentUpEvent, velocityX, velocityY);
+                    handled = mListener.onFling(mCurrentDownEvent, ev, velocityX, velocityY);
                 }
             }
-            mPreviousUpEvent = MotionEvent.obtain(ev);
+            if (mPreviousUpEvent != null) {
+                mPreviousUpEvent.recycle();
+            }
+            // Hold the event we obtained above - listeners may have changed the original.
+            mPreviousUpEvent = currentUpEvent;
             mVelocityTracker.recycle();
             mVelocityTracker = null;
             mIsDoubleTapping = false;
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 71302cb..3b09808 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -17,6 +17,7 @@
 
 package android.view;
 
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
@@ -44,7 +45,7 @@
     void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor);
 
     void resized(int w, int h, in Rect coveredInsets, in Rect visibleInsets,
-            boolean reportDraw);
+            boolean reportDraw, in Configuration newConfig);
     void dispatchKey(in KeyEvent event);
     void dispatchPointer(in MotionEvent event, long eventTime, boolean callWhenDone);
     void dispatchTrackball(in MotionEvent event, long eventTime, boolean callWhenDone);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 0ebe360..9b7b2f40 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -64,8 +64,6 @@
     void addAppToken(int addPos, IApplicationToken token,
             int groupId, int requestedOrientation, boolean fullscreen);
     void setAppGroupId(IBinder token, int groupId);
-    Configuration updateOrientationFromAppTokens(in Configuration currentConfig,
-            IBinder freezeThisOneIfNeeded);
     void setAppOrientation(IApplicationToken token, int requestedOrientation);
     int getAppOrientation(IApplicationToken token);
     void setFocusedApp(IBinder token, boolean moveFocusNow);
@@ -85,6 +83,13 @@
     void moveAppTokensToTop(in List<IBinder> tokens);
     void moveAppTokensToBottom(in List<IBinder> tokens);
 
+    // Re-evaluate the current orientation from the caller's state.
+    // If there is a change, the new Configuration is returned and the
+    // caller must call setNewConfiguration() sometime later.
+    Configuration updateOrientationFromAppTokens(in Configuration currentConfig,
+            IBinder freezeThisOneIfNeeded);
+    void setNewConfiguration(in Configuration config);
+    
     // these require DISABLE_KEYGUARD permission
     void disableKeyguard(IBinder token, String tag);
     void reenableKeyguard(IBinder token);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index ca5e1de..d7f2539 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -19,6 +19,7 @@
 import com.android.internal.view.BaseIWindow;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.CompatibilityInfo.Translator;
 import android.graphics.Canvas;
@@ -504,7 +505,7 @@
         }
 
         public void resized(int w, int h, Rect coveredInsets,
-                Rect visibleInsets, boolean reportDraw) {
+                Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
             SurfaceView surfaceView = mSurfaceView.get();
             if (surfaceView != null) {
                 if (localLOGV) Log.v(
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e5db120..2eb633f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -20,6 +20,7 @@
 import com.android.internal.view.menu.MenuBuilder;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
@@ -3050,6 +3051,7 @@
      *
      * @param enabled True if this view is enabled, false otherwise.
      */
+    @RemotableViewMethod
     public void setEnabled(boolean enabled) {
         if (enabled == isEnabled()) return;
 
@@ -3932,6 +3934,32 @@
     }
 
     /**
+     * Dispatch a notification about a resource configuration change down
+     * the view hierarchy.
+     * ViewGroups should override to route to their children.
+     *
+     * @param newConfig The new resource configuration.
+     *
+     * @see #onConfigurationChanged
+     */
+    public void dispatchConfigurationChanged(Configuration newConfig) {
+        onConfigurationChanged(newConfig);
+    }
+
+    /**
+     * Called when the current configuration of the resources being used
+     * by the application have changed.  You can use this to decide when
+     * to reload resources that can changed based on orientation and other
+     * configuration characterstics.  You only need to use this if you are
+     * not relying on the normal {@link android.app.Activity} mechanism of
+     * recreating the activity instance upon a configuration change.
+     *
+     * @param newConfig The new resource configuration.
+     */
+    protected void onConfigurationChanged(Configuration newConfig) {
+    }
+
+    /**
      * Private function to aggregate all per-view attributes in to the view
      * root.
      */
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 2ed623d..0663215 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -19,6 +19,7 @@
 import com.android.internal.R;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -722,6 +723,19 @@
     /**
      * {@inheritDoc}
      */
+    @Override
+    public void dispatchConfigurationChanged(Configuration newConfig) {
+        super.dispatchConfigurationChanged(newConfig);
+        final int count = mChildrenCount;
+        final View[] children = mChildren;
+        for (int i = 0; i < count; i++) {
+            children[i].dispatchConfigurationChanged(newConfig);
+        }
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
     public void recomputeViewAttributes(View child) {
         ViewParent parent = mParent;
         if (parent != null) parent.recomputeViewAttributes(this);
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 07b2d1c..264b8c9 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -41,7 +41,9 @@
 import android.widget.Scroller;
 import android.content.pm.PackageManager;
 import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.ComponentCallbacks;
 import android.content.Context;
 import android.app.ActivityManagerNative;
 import android.Manifest;
@@ -101,6 +103,9 @@
     static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
     static boolean sFirstDrawComplete = false;
     
+    static final ArrayList<ComponentCallbacks> sConfigCallbacks
+            = new ArrayList<ComponentCallbacks>();
+    
     private static int sDrawTime;
 
     long mLastTrackballTime = 0;
@@ -171,6 +176,12 @@
     final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
             = new ViewTreeObserver.InternalInsetsInfo();
 
+    class ResizedInfo {
+        Rect coveredInsets;
+        Rect visibleInsets;
+        Configuration newConfig;
+    }
+    
     boolean mScrollMayChange;
     int mSoftInputMode;
     View mLastScrolledFocus;
@@ -265,6 +276,12 @@
         }
     }
     
+    public static void addConfigCallback(ComponentCallbacks callback) {
+        synchronized (sConfigCallbacks) {
+            sConfigCallbacks.add(callback);
+        }
+    }
+    
     // FIXME for perf testing only
     private boolean mProfile = false;
 
@@ -1782,23 +1799,33 @@
             handleGetNewSurface();
             break;
         case RESIZED:
-            Rect coveredInsets = ((Rect[])msg.obj)[0];
-            Rect visibleInsets = ((Rect[])msg.obj)[1];
+            ResizedInfo ri = (ResizedInfo)msg.obj;
 
             if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2
-                    && mPendingContentInsets.equals(coveredInsets)
-                    && mPendingVisibleInsets.equals(visibleInsets)) {
+                    && mPendingContentInsets.equals(ri.coveredInsets)
+                    && mPendingVisibleInsets.equals(ri.visibleInsets)) {
                 break;
             }
             // fall through...
         case RESIZED_REPORT:
             if (mAdded) {
+                Configuration config = ((ResizedInfo)msg.obj).newConfig;
+                if (config != null) {
+                    synchronized (sConfigCallbacks) {
+                        for (int i=sConfigCallbacks.size()-1; i>=0; i--) {
+                            sConfigCallbacks.get(i).onConfigurationChanged(config);
+                        }
+                    }
+                    if (mView != null) {
+                        mView.dispatchConfigurationChanged(config);
+                    }
+                }
                 mWinFrame.left = 0;
                 mWinFrame.right = msg.arg1;
                 mWinFrame.top = 0;
                 mWinFrame.bottom = msg.arg2;
-                mPendingContentInsets.set(((Rect[])msg.obj)[0]);
-                mPendingVisibleInsets.set(((Rect[])msg.obj)[1]);
+                mPendingContentInsets.set(((ResizedInfo)msg.obj).coveredInsets);
+                mPendingVisibleInsets.set(((ResizedInfo)msg.obj).visibleInsets);
                 if (msg.what == RESIZED_REPORT) {
                     mReportNextDraw = true;
                 }
@@ -2587,7 +2614,7 @@
     }
 
     public void dispatchResized(int w, int h, Rect coveredInsets,
-            Rect visibleInsets, boolean reportDraw) {
+            Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
         if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": w=" + w
                 + " h=" + h + " coveredInsets=" + coveredInsets.toShortString()
                 + " visibleInsets=" + visibleInsets.toShortString()
@@ -2601,7 +2628,11 @@
         }
         msg.arg1 = w;
         msg.arg2 = h;
-        msg.obj = new Rect[] { new Rect(coveredInsets), new Rect(visibleInsets) };
+        ResizedInfo ri = new ResizedInfo();
+        ri.coveredInsets = new Rect(coveredInsets);
+        ri.visibleInsets = new Rect(visibleInsets);
+        ri.newConfig = newConfig;
+        msg.obj = ri;
         sendMessage(msg);
     }
 
@@ -2802,11 +2833,11 @@
         }
 
         public void resized(int w, int h, Rect coveredInsets,
-                Rect visibleInsets, boolean reportDraw) {
+                Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
             final ViewRoot viewRoot = mViewRoot.get();
             if (viewRoot != null) {
                 viewRoot.dispatchResized(w, h, coveredInsets,
-                        visibleInsets, reportDraw);
+                        visibleInsets, reportDraw, newConfig);
             }
         }
 
diff --git a/core/java/android/webkit/DateSorter.java b/core/java/android/webkit/DateSorter.java
index 16feaa9..0e8ad7e 100644
--- a/core/java/android/webkit/DateSorter.java
+++ b/core/java/android/webkit/DateSorter.java
@@ -26,7 +26,7 @@
  * Sorts dates into the following groups:
  *   Today
  *   Yesterday
- *   five days ago
+ *   seven days ago
  *   one month ago
  *   older than a month ago
  */
@@ -41,7 +41,7 @@
     private long [] mBins = new long[DAY_COUNT-1];
     private String [] mLabels = new String[DAY_COUNT];
     
-    private static final int NUM_DAYS_AGO = 5;
+    private static final int NUM_DAYS_AGO = 7;
 
     /**
      * @param context Application context
@@ -66,13 +66,12 @@
         mLabels[0] = context.getText(com.android.internal.R.string.today).toString();
         mLabels[1] = context.getText(com.android.internal.R.string.yesterday).toString();
 
-        int resId = com.android.internal.R.plurals.num_days_ago;
+        int resId = com.android.internal.R.plurals.last_num_days;
         String format = resources.getQuantityString(resId, NUM_DAYS_AGO);
         mLabels[2] = String.format(format, NUM_DAYS_AGO);
 
-        mLabels[3] = context.getText(com.android.internal.R.string.oneMonthDurationPast).toString();
-        mLabels[4] = context.getText(com.android.internal.R.string.beforeOneMonthDurationPast)
-                .toString();
+        mLabels[3] = context.getString(com.android.internal.R.string.last_month);
+        mLabels[4] = context.getString(com.android.internal.R.string.older);
     }
 
     /**
diff --git a/core/java/android/webkit/GeolocationPermissions.java b/core/java/android/webkit/GeolocationPermissions.java
index d12d828..4565b756 100755
--- a/core/java/android/webkit/GeolocationPermissions.java
+++ b/core/java/android/webkit/GeolocationPermissions.java
@@ -23,6 +23,7 @@
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.Vector;
 
 
 /**
@@ -61,11 +62,8 @@
     private Handler mHandler;
     private Handler mUIHandler;
 
-    // Members used to transfer the origins and permissions between threads.
-    private Set<String> mOrigins;
-    private boolean mAllowed;
-    private Set<String> mOriginsToClear;
-    private Set<String> mOriginsToAllow;
+    // A queue to store messages until the handler is ready.
+    private Vector<Message> mQueuedMessages;
 
     // Message ids
     static final int GET_ORIGINS = 0;
@@ -126,7 +124,7 @@
      * Creates the message handler. Must be called on the WebKit thread.
      * @hide
      */
-    public void createHandler() {
+    public synchronized void createHandler() {
         if (mHandler == null) {
             mHandler = new Handler() {
                 @Override
@@ -134,21 +132,21 @@
                     // Runs on the WebKit thread.
                     switch (msg.what) {
                         case GET_ORIGINS: {
-                            getOriginsImpl();
+                            Set origins = nativeGetOrigins();
                             ValueCallback callback = (ValueCallback) msg.obj;
                             Map values = new HashMap<String, Object>();
                             values.put(CALLBACK, callback);
-                            values.put(ORIGINS, mOrigins);
+                            values.put(ORIGINS, origins);
                             postUIMessage(Message.obtain(null, RETURN_ORIGINS, values));
                             } break;
                         case GET_ALLOWED: {
                             Map values = (Map) msg.obj;
                             String origin = (String) values.get(ORIGIN);
                             ValueCallback callback = (ValueCallback) values.get(CALLBACK);
-                            getAllowedImpl(origin);
+                            boolean allowed = nativeGetAllowed(origin);
                             Map retValues = new HashMap<String, Object>();
                             retValues.put(CALLBACK, callback);
-                            retValues.put(ALLOWED, new Boolean(mAllowed));
+                            retValues.put(ALLOWED, new Boolean(allowed));
                             postUIMessage(Message.obtain(null, RETURN_ALLOWED, retValues));
                             } break;
                         case CLEAR:
@@ -164,15 +162,12 @@
                 }
             };
 
-            if (mOriginsToClear != null) {
-                for (String origin : mOriginsToClear) {
-                    nativeClear(origin);
+            // Handle the queued messages
+            if (mQueuedMessages != null) {
+                while (!mQueuedMessages.isEmpty()) {
+                    mHandler.sendMessage(mQueuedMessages.remove(0));
                 }
-            }
-            if (mOriginsToAllow != null) {
-                for (String origin : mOriginsToAllow) {
-                    nativeAllow(origin);
-                }
+                mQueuedMessages = null;
             }
         }
     }
@@ -180,9 +175,15 @@
     /**
      * Utility function to send a message to our handler.
      */
-    private void postMessage(Message msg) {
-        assert(mHandler != null);
-        mHandler.sendMessage(msg);
+    private synchronized void postMessage(Message msg) {
+        if (mHandler == null) {
+            if (mQueuedMessages == null) {
+                mQueuedMessages = new Vector<Message>();
+            }
+            mQueuedMessages.add(msg);
+        } else {
+            mHandler.sendMessage(msg);
+        }
     }
 
     /**
@@ -207,8 +208,8 @@
     public void getOrigins(ValueCallback<Set<String> > callback) {
         if (callback != null) {
             if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
-                getOriginsImpl();
-                callback.onReceiveValue(mOrigins);
+                Set origins = nativeGetOrigins();
+                callback.onReceiveValue(origins);
             } else {
                 postMessage(Message.obtain(null, GET_ORIGINS, callback));
             }
@@ -216,14 +217,6 @@
     }
 
     /**
-     * Helper method to get the set of origins.
-     */
-    private void getOriginsImpl() {
-        // Called on the WebKit thread.
-        mOrigins = nativeGetOrigins();
-    }
-
-    /**
      * Gets the permission state for the specified origin.
      *
      * Callback is a ValueCallback object whose onReceiveValue method will be
@@ -238,8 +231,8 @@
             return;
         }
         if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
-            getAllowedImpl(origin);
-            callback.onReceiveValue(new Boolean(mAllowed));
+            boolean allowed = nativeGetAllowed(origin);
+            callback.onReceiveValue(new Boolean(allowed));
         } else {
             Map values = new HashMap<String, Object>();
             values.put(ORIGIN, origin);
@@ -249,31 +242,13 @@
     }
 
     /**
-     * Helper method to get the permission state for the specified origin.
-     */
-    private void getAllowedImpl(String origin) {
-        // Called on the WebKit thread.
-        mAllowed = nativeGetAllowed(origin);
-    }
-
-    /**
      * Clears the permission state for the specified origin. This method may be
      * called before the WebKit thread has intialized the message handler.
      * Messages will be queued until this time.
      */
     public void clear(String origin) {
         // Called on the UI thread.
-        if (mHandler == null) {
-            if (mOriginsToClear == null) {
-                mOriginsToClear = new HashSet<String>();
-            }
-            mOriginsToClear.add(origin);
-            if (mOriginsToAllow != null) {
-                mOriginsToAllow.remove(origin);
-            }
-        } else {
-            postMessage(Message.obtain(null, CLEAR, origin));
-        }
+        postMessage(Message.obtain(null, CLEAR, origin));
     }
 
     /**
@@ -283,17 +258,7 @@
      */
     public void allow(String origin) {
         // Called on the UI thread.
-        if (mHandler == null) {
-            if (mOriginsToAllow == null) {
-                mOriginsToAllow = new HashSet<String>();
-            }
-            mOriginsToAllow.add(origin);
-            if (mOriginsToClear != null) {
-                mOriginsToClear.remove(origin);
-            }
-        } else {
-            postMessage(Message.obtain(null, ALLOW, origin));
-        }
+        postMessage(Message.obtain(null, ALLOW, origin));
     }
 
     /**
diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java
index a9d6ff6..3ed9851 100644
--- a/core/java/android/webkit/MimeTypeMap.java
+++ b/core/java/android/webkit/MimeTypeMap.java
@@ -368,6 +368,7 @@
             sMimeTypeMap.loadEntry("application/x-xcf", "xcf");
             sMimeTypeMap.loadEntry("application/x-xfig", "fig");
             sMimeTypeMap.loadEntry("application/xhtml+xml", "xhtml");
+            sMimeTypeMap.loadEntry("audio/3gpp", "3gpp");
             sMimeTypeMap.loadEntry("audio/basic", "snd");
             sMimeTypeMap.loadEntry("audio/midi", "mid");
             sMimeTypeMap.loadEntry("audio/midi", "midi");
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 39e5275..662be95 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -916,9 +916,12 @@
     }
 
     /**
-     * Tell the WebView to block network image. This is only checked when
-     * getLoadsImagesAutomatically() is true.
-     * @param flag True if the WebView should block network image
+     * Tell the WebView to block network images. This is only checked when
+     * {@link #getLoadsImagesAutomatically} is true. If you set the value to
+     * false, images will automatically be loaded. Use this api to reduce
+     * bandwidth only. Use {@link #setBlockNetworkLoads} if possible.
+     * @param flag True if the WebView should block network images.
+     * @see #setBlockNetworkLoads
      */
     public synchronized void setBlockNetworkImage(boolean flag) {
         if (mBlockNetworkImage != flag) {
@@ -928,17 +931,21 @@
     }
 
     /**
-     * Return true if the WebView will block network image. The default is false.
-     * @return True if the WebView blocks network image.
+     * Return true if the WebView will block network images. The default is
+     * false.
+     * @return True if the WebView blocks network images.
      */
     public synchronized boolean getBlockNetworkImage() {
         return mBlockNetworkImage;
     }
 
     /**
-     * @hide
-     * Tell the WebView to block all network load requests.
-     * @param flag True if the WebView should block all network loads
+     * Tell the WebView to block all network load requests. If you set the
+     * value to false, you must call {@link android.webkit.WebView#reload} to
+     * fetch remote resources. This flag supercedes the value passed to
+     * {@link #setBlockNetworkImage}.
+     * @param flag True if the WebView should block all network loads.
+     * @see android.webkit.WebView#reload
      */
     public synchronized void setBlockNetworkLoads(boolean flag) {
         if (mBlockNetworkLoads != flag) {
@@ -948,9 +955,8 @@
     }
 
     /**
-     * @hide
-     * Return true if the WebView will block all network loads.
-     * The default is false.
+     * Return true if the WebView will block all network loads. The default is
+     * false.
      * @return True if the WebView blocks all network loads.
      */
     public synchronized boolean getBlockNetworkLoads() {
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index cf71a84..9314d7b 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -146,7 +146,7 @@
      * @hide
      * Message handler, webcore side
      */
-    public void createHandler() {
+    public synchronized void createHandler() {
         if (mHandler == null) {
             mHandler = new Handler() {
                 @Override
@@ -342,7 +342,7 @@
     /**
      * Utility function to send a message to our handler
      */
-    private void postMessage(Message msg) {
+    private synchronized void postMessage(Message msg) {
         if (mHandler != null) {
             mHandler.sendMessage(msg);
         }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 9672892..adae0cb 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3088,14 +3088,11 @@
         Rect vBox = contentToViewRect(contentBounds);
         Rect visibleRect = new Rect();
         calcOurVisibleRect(visibleRect);
-        // The IME may have shown, resulting in the textfield being offscreen.
-        // If so, the textfield will be scrolled on screen, so treat it as
-        // though it is on screen.  If it is on screen, place the WebTextView in
-        // its new place, accounting for our new scroll/zoom values.
-        InputMethodManager imm = InputMethodManager.peekInstance();
-        if ((imm != null && imm.isActive(mWebTextView))
-                || (allowIntersect ? Rect.intersects(visibleRect, vBox)
-                : visibleRect.contains(vBox))) {
+        // If the textfield is on screen, place the WebTextView in
+        // its new place, accounting for our new scroll/zoom values,
+        // and adjust its textsize.
+        if (allowIntersect ? Rect.intersects(visibleRect, vBox)
+                : visibleRect.contains(vBox)) {
             mWebTextView.setRect(vBox.left, vBox.top, vBox.width(),
                     vBox.height());
             mWebTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
@@ -4439,6 +4436,7 @@
             ted.mX = viewToContentX((int) x + mScrollX);
             ted.mY = viewToContentY((int) y + mScrollY);
             ted.mEventTime = eventTime;
+            ted.mMetaState = ev.getMetaState();
             mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
             mLastSentTouchTime = eventTime;
         }
@@ -4702,6 +4700,7 @@
                             ted.mX = viewToContentX((int) x + mScrollX);
                             ted.mY = viewToContentY((int) y + mScrollY);
                             ted.mEventTime = eventTime;
+                            ted.mMetaState = ev.getMetaState();
                             mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                         } else if (mFullScreenHolder == null) {
                             doDoubleTap();
@@ -5738,6 +5737,11 @@
                         ted.mX = viewToContentX((int) mLastTouchX + mScrollX);
                         ted.mY = viewToContentY((int) mLastTouchY + mScrollY);
                         ted.mEventTime = SystemClock.uptimeMillis();
+                        // metaState for long press is tricky. Should it be the state
+                        // when the press started or when the press was released? Or
+                        // some intermediary key state? For simplicity for now, we
+                        // don't set it.
+                        ted.mMetaState = 0;
                         mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                     } else if (mPreventDrag == PREVENT_DRAG_NO) {
                         mTouchMode = TOUCH_DONE_MODE;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 3a3e445..361ec56 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -515,7 +515,7 @@
     private native void nativeTouchUp(int touchGeneration,
             int framePtr, int nodePtr, int x, int y);
 
-    private native int nativeHandleTouchEvent(int action, int x, int y, long time);
+    private native int nativeHandleTouchEvent(int action, int x, int y, long time, int metaState);
 
     private native void nativeUpdateFrameCache();
 
@@ -735,6 +735,7 @@
         int mX;
         int mY;
         long mEventTime;
+        int mMetaState;
     }
 
     static class GeolocationPermissionsData {
@@ -1198,7 +1199,7 @@
                                     mWebView.mPrivateHandler,
                                     WebView.PREVENT_TOUCH_ID, ted.mAction,
                                     nativeHandleTouchEvent(ted.mAction, ted.mX,
-                                    ted.mY, ted.mEventTime)).sendToTarget();
+                                    ted.mY, ted.mEventTime, ted.mMetaState)).sendToTarget();
                             break;
                         }
 
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 254efe7..a79bbee 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2364,7 +2364,16 @@
     public void draw(Canvas canvas) {
         super.draw(canvas);
         if (mFastScroller != null) {
-            mFastScroller.draw(canvas);
+            final int scrollY = mScrollY;
+            if (scrollY != 0) {
+                // Pin the fast scroll thumb to the top/bottom during overscroll.
+                int restoreCount = canvas.save();
+                canvas.translate(0, (float) scrollY);
+                mFastScroller.draw(canvas);
+                canvas.restoreToCount(restoreCount);
+            } else {
+                mFastScroller.draw(canvas);
+            }
         }
     }
 
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 3853359..233ce30 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -32,6 +32,7 @@
 import android.net.Uri;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.RemotableViewMethod;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -69,6 +70,7 @@
     private ColorFilter mColorFilter;
     private int mAlpha = 255;
     private int mViewAlphaScale = 256;
+    private boolean mColorMod = false;
 
     private Drawable mDrawable = null;
     private int[] mState = null;
@@ -138,7 +140,7 @@
 
         int tint = a.getInt(com.android.internal.R.styleable.ImageView_tint, 0);
         if (tint != 0) {
-            setColorFilter(tint, PorterDuff.Mode.SRC_ATOP);
+            setColorFilter(tint);
         }
         
         mCropToPadding = a.getBoolean(
@@ -877,6 +879,18 @@
         setColorFilter(new PorterDuffColorFilter(color, mode));
     }
 
+    /**
+     * Set a tinting option for the image. Assumes
+     * {@link PorterDuff.Mode#SRC_ATOP} blending mode.
+     *
+     * @param color Color tint to apply.
+     * @attr ref android.R.styleable#ImageView_tint
+     */
+    @RemotableViewMethod
+    public final void setColorFilter(int color) {
+        setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
+    }
+
     public final void clearColorFilter() {
         setColorFilter(null);
     }
@@ -889,22 +903,29 @@
     public void setColorFilter(ColorFilter cf) {
         if (mColorFilter != cf) {
             mColorFilter = cf;
+            mColorMod = true;
             applyColorMod();
             invalidate();
         }
     }
 
+    @RemotableViewMethod
     public void setAlpha(int alpha) {
         alpha &= 0xFF;          // keep it legal
         if (mAlpha != alpha) {
             mAlpha = alpha;
+            mColorMod = true;
             applyColorMod();
             invalidate();
         }
     }
 
     private void applyColorMod() {
-        if (mDrawable != null) {
+        // Only mutate and apply when modifications have occurred. This should
+        // not reset the mColorMod flag, since these filters need to be
+        // re-applied if the Drawable is changed.
+        if (mDrawable != null && mColorMod) {
+            mDrawable = mDrawable.mutate();
             mDrawable.setColorFilter(mColorFilter);
             mDrawable.setAlpha(mAlpha * mViewAlphaScale >> 8);
         }
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index c428dc0..2feed03 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -16,14 +16,17 @@
 
 package android.widget;
 
+import com.android.internal.R;
+import com.google.android.collect.Lists;
+
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.PixelFormat;
 import android.graphics.Paint;
-import android.graphics.drawable.Drawable;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
@@ -31,16 +34,13 @@
 import android.view.FocusFinder;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
+import android.view.SoundEffectConstants;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.view.ViewParent;
-import android.view.SoundEffectConstants;
 import android.view.accessibility.AccessibilityEvent;
 
-import com.google.android.collect.Lists;
-import com.android.internal.R;
-
 import java.util.ArrayList;
 
 /*
@@ -2722,7 +2722,8 @@
 
     /**
      * Determine the distance to the nearest edge of a view in a particular
-     * direciton.
+     * direction.
+     * 
      * @param descendant A descendant of this list.
      * @return The distance, or 0 if the nearest edge is already on screen.
      */
@@ -3091,9 +3092,9 @@
             previouslyFocusedRect.offset(mScrollX, mScrollY);
 
             final ListAdapter adapter = mAdapter;
-            final int firstPosition = mFirstPosition;
-            // Don't cache the result of getChildCount here, it could change in layoutChildren.
-            if (adapter.getCount() < getChildCount() + firstPosition) {
+            // Don't cache the result of getChildCount or mFirstPosition here,
+            // it could change in layoutChildren.
+            if (adapter.getCount() < getChildCount() + mFirstPosition) {
                 mLayoutMode = LAYOUT_NORMAL;
                 layoutChildren();
             }
@@ -3103,6 +3104,7 @@
             Rect otherRect = mTempRect;
             int minDistance = Integer.MAX_VALUE;
             final int childCount = getChildCount();
+            final int firstPosition = mFirstPosition;
 
             for (int i = 0; i < childCount; i++) {
                 // only consider selectable views
@@ -3307,9 +3309,9 @@
      * Sets the checked state of the specified position. The is only valid if
      * the choice mode has been set to {@link #CHOICE_MODE_SINGLE} or
      * {@link #CHOICE_MODE_MULTIPLE}.
-     *
+     * 
      * @param position The item whose checked state is to be checked
-     * @param value The new checked sate for the item
+     * @param value The new checked state for the item
      */
     public void setItemChecked(int position, boolean value) {
         if (mChoiceMode == CHOICE_MODE_NONE) {
@@ -3392,10 +3394,11 @@
     }
 
     /**
-     * Returns the set of checked items ids. The result is only valid if
-     * the choice mode has not been set to {@link #CHOICE_MODE_SINGLE}.
-     *
-     * @return A new array which contains the id of each checked item in the list.
+     * Returns the set of checked items ids. The result is only valid if the
+     * choice mode has not been set to {@link #CHOICE_MODE_SINGLE}.
+     * 
+     * @return A new array which contains the id of each checked item in the
+     *         list.
      */
     public long[] getCheckItemIds() {
         if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null && mAdapter != null) {
@@ -3404,11 +3407,23 @@
             final long[] ids = new long[count];
             final ListAdapter adapter = mAdapter;
 
+            int checkedCount = 0;
             for (int i = 0; i < count; i++) {
-                ids[i]= adapter.getItemId(states.keyAt(i));
+                if (states.valueAt(i)) {
+                    ids[checkedCount++] = adapter.getItemId(states.keyAt(i));
+                }
             }
 
-            return ids;
+            // Trim array if needed. mCheckStates may contain false values
+            // resulting in checkedCount being smaller than count.
+            if (checkedCount == count) {
+                return ids;
+            } else {
+                final long[] result = new long[checkedCount];
+                System.arraycopy(ids, 0, result, 0, checkedCount);
+
+                return result;
+            }
         }
 
         return new long[0];
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index bcddca1..2f6dd1e 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -295,14 +295,18 @@
      */
     private static class DropDownAdapter implements ListAdapter, SpinnerAdapter {
         private SpinnerAdapter mAdapter;
+        private ListAdapter mListAdapter;
 
         /**
-         * <p>Creates a new ListAddapter wrapper for the specified adapter.</p>
+         * <p>Creates a new ListAdapter wrapper for the specified adapter.</p>
          *
          * @param adapter the Adapter to transform into a ListAdapter
          */
         public DropDownAdapter(SpinnerAdapter adapter) {
             this.mAdapter = adapter;
+            if (adapter instanceof ListAdapter) {
+                this.mListAdapter = (ListAdapter) adapter;
+            }
         }
 
         public int getCount() {
@@ -343,21 +347,29 @@
         }
 
         /**
-         * <p>Always returns false.</p>
-         *
-         * @return false
+         * If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call.
+         * Otherwise, return true. 
          */
         public boolean areAllItemsEnabled() {
-            return true;
+            final ListAdapter adapter = mListAdapter;
+            if (adapter != null) {
+                return adapter.areAllItemsEnabled();
+            } else {
+                return true;
+            }
         }
 
         /**
-         * <p>Always returns false.</p>
-         *
-         * @return false
+         * If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call.
+         * Otherwise, return true.
          */
         public boolean isEnabled(int position) {
-            return true;
+            final ListAdapter adapter = mListAdapter;
+            if (adapter != null) {
+                return adapter.isEnabled(position);
+            } else {
+                return true;
+            }
         }
 
         public int getItemViewType(int position) {
diff --git a/core/java/android/widget/ViewFlipper.java b/core/java/android/widget/ViewFlipper.java
index aee25b0..8034961 100644
--- a/core/java/android/widget/ViewFlipper.java
+++ b/core/java/android/widget/ViewFlipper.java
@@ -38,7 +38,7 @@
 @RemoteView
 public class ViewFlipper extends ViewAnimator {
     private static final String TAG = "ViewFlipper";
-    private static final boolean LOGD = true;
+    private static final boolean LOGD = false;
 
     private static final int DEFAULT_INTERVAL = 3000;
 
diff --git a/core/java/com/android/internal/app/DisableCarModeActivity.java b/core/java/com/android/internal/app/DisableCarModeActivity.java
new file mode 100644
index 0000000..95dc1f9
--- /dev/null
+++ b/core/java/com/android/internal/app/DisableCarModeActivity.java
@@ -0,0 +1,42 @@
+/*
+ * 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.internal.app;
+
+import android.app.Activity;
+import android.app.IUiModeManager;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+public class DisableCarModeActivity extends Activity {
+    private static final String TAG = "DisableCarModeActivity";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        try {
+            IUiModeManager uiModeManager = IUiModeManager.Stub.asInterface(
+                    ServiceManager.getService("uimode"));
+            uiModeManager.disableCarMode();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to disable car mode", e);
+        }
+        finish();
+    }
+
+}
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index c5b869b..bc7dbf4 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -93,7 +93,7 @@
 
    public static boolean unMountSdDir(String cid) {
     try {
-        int rc = getMountService().unmountSecureContainer(cid);
+        int rc = getMountService().unmountSecureContainer(cid, false);
         if (rc != StorageResultCode.OperationSucceeded) {
             Log.e(TAG, "Failed to unmount " + cid + " with rc " + rc);
             return false;
@@ -148,7 +148,7 @@
 
     public static boolean destroySdDir(String cid) {
         try {
-            int rc = getMountService().destroySecureContainer(cid);
+            int rc = getMountService().destroySecureContainer(cid, false);
             if (rc != StorageResultCode.OperationSucceeded) {
                 Log.i(TAG, "Failed to destroy container " + cid);
                 return false;
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 15dcbd6..22c6e79 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -1,5 +1,6 @@
 package com.android.internal.view;
 
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
@@ -17,7 +18,7 @@
     }
     
     public void resized(int w, int h, Rect coveredInsets,
-            Rect visibleInsets, boolean reportDraw) {
+            Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
         if (reportDraw) {
             try {
                 mSession.finishDrawing(this);
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
index c2862b0..28bf6bb 100644
--- a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
@@ -17,12 +17,15 @@
 package com.android.internal.widget;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.inputmethodservice.Keyboard;
 import android.inputmethodservice.KeyboardView;
 import android.inputmethodservice.KeyboardView.OnKeyboardActionListener;
 import android.os.Handler;
 import android.os.SystemClock;
+import android.os.Vibrator;
 import android.provider.Settings;
+import android.util.Log;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.View;
@@ -36,6 +39,7 @@
     private static final int KEYBOARD_STATE_NORMAL = 0;
     private static final int KEYBOARD_STATE_SHIFTED = 1;
     private static final int KEYBOARD_STATE_CAPSLOCK = 2;
+    private static final String TAG = "PasswordEntryKeyboardHelper";
     private int mKeyboardMode = KEYBOARD_MODE_ALPHA;
     private int mKeyboardState = KEYBOARD_STATE_NORMAL;
     private PasswordEntryKeyboard mQwertyKeyboard;
@@ -46,6 +50,8 @@
     private Context mContext;
     private View mTargetView;
     private KeyboardView mKeyboardView;
+    private long[] mVibratePattern;
+    private Vibrator mVibrator;
 
     public PasswordEntryKeyboardHelper(Context context, KeyboardView keyboardView, View targetView) {
         mContext = context;
@@ -53,6 +59,7 @@
         mKeyboardView = keyboardView;
         createKeyboards();
         mKeyboardView.setOnKeyboardActionListener(this);
+        mVibrator = new Vibrator();
     }
 
     public boolean isAlpha() {
@@ -142,6 +149,29 @@
         }
     }
 
+    /**
+     * Sets and enables vibrate pattern.  If id is 0 (or can't be loaded), vibrate is disabled.
+     * @param id resource id for array containing vibrate pattern.
+     */
+    public void setVibratePattern(int id) {
+        int[] tmpArray = null;
+        try {
+            tmpArray = mContext.getResources().getIntArray(id);
+        } catch (Resources.NotFoundException e) {
+            if (id != 0) {
+                Log.e(TAG, "Vibrate pattern missing", e);
+            }
+        }
+        if (tmpArray == null) {
+            mVibratePattern = null;
+            return;
+        }
+        mVibratePattern = new long[tmpArray.length];
+        for (int i = 0; i < tmpArray.length; i++) {
+            mVibratePattern[i] = tmpArray[i];
+        }
+    }
+
     private void handleModeChange() {
         final Keyboard current = mKeyboardView.getKeyboard();
         Keyboard next = null;
@@ -200,7 +230,9 @@
     }
 
     public void onPress(int primaryCode) {
-        // TODO: vibration support.
+        if (mVibratePattern != null) {
+            mVibrator.vibrate(mVibratePattern, -1);
+        }
     }
 
     public void onRelease(int primaryCode) {
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.cpp b/core/jni/android/graphics/YuvToJpegEncoder.cpp
index e6a1872..819cce8 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.cpp
+++ b/core/jni/android/graphics/YuvToJpegEncoder.cpp
@@ -7,9 +7,9 @@
 #include <jni.h>
 
 YuvToJpegEncoder* YuvToJpegEncoder::create(int format, int* strides) {
-    // Only PIXEL_FORMAT_YCbCr_420_SP and PIXEl_FOMAT_YCbCr_422_I are supported
+    // Only ImageFormat.NV21 and ImageFormat.YUY2 are supported
     // for now.
-    if (format == HAL_PIXEL_FORMAT_YCbCr_420_SP) {
+    if (format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
         return new Yuv420SpToJpegEncoder(strides);
     } else if (format == HAL_PIXEL_FORMAT_YCbCr_422_I) {
         return new Yuv422IToJpegEncoder(strides);
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp
index c197010..26d0e86 100644
--- a/core/jni/android_database_SQLiteDatabase.cpp
+++ b/core/jni/android_database_SQLiteDatabase.cpp
@@ -470,7 +470,7 @@
     if (errcode == SQLITE_DONE) {
         throw_sqlite3_exception(env, errcode, NULL, message);
     } else {
-        char temp[20];
+        char temp[21];
         sprintf(temp, "error code %d", errcode);
         throw_sqlite3_exception(env, errcode, temp, message);
     }
diff --git a/core/jni/android_database_SQLiteProgram.cpp b/core/jni/android_database_SQLiteProgram.cpp
index 32018eb..c247bbd 100644
--- a/core/jni/android_database_SQLiteProgram.cpp
+++ b/core/jni/android_database_SQLiteProgram.cpp
@@ -45,8 +45,8 @@
 
 static void native_compile(JNIEnv* env, jobject object, jstring sqlString)
 {
-    char buf[32];
-    sprintf(buf, "android_database_SQLiteProgram->native_compile() not implemented");
+    char buf[65];
+    strcpy(buf, "android_database_SQLiteProgram->native_compile() not implemented");
     throw_sqlite3_exception(env, GET_HANDLE(env, object), buf);
     return;
 }
@@ -152,8 +152,8 @@
 
 static void native_finalize(JNIEnv* env, jobject object)
 {
-    char buf[32];
-    sprintf(buf, "android_database_SQLiteProgram->native_finalize() not implemented");
+    char buf[66];
+    strcpy(buf, "android_database_SQLiteProgram->native_finalize() not implemented");
     throw_sqlite3_exception(env, GET_HANDLE(env, object), buf);
     return;
 }
diff --git a/core/jni/android_graphics_PixelFormat.cpp b/core/jni/android_graphics_PixelFormat.cpp
index 0643622..5b8363c 100644
--- a/core/jni/android_graphics_PixelFormat.cpp
+++ b/core/jni/android_graphics_PixelFormat.cpp
@@ -48,11 +48,35 @@
         JNIEnv* env, jobject clazz, jint format, jobject pixelFormatObject)
 {
     PixelFormatInfo info;
-    status_t err = getPixelFormatInfo(format, &info);
+    status_t err;
+
+    // we need this for backward compatibility with PixelFormat's
+    // deprecated constants
+    switch (format) {
+    case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+        // defined as the bytes per pixel of the Y plane
+        info.bytesPerPixel = 1;
+        info.bitsPerPixel = 16;
+        goto done;
+    case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+        // defined as the bytes per pixel of the Y plane
+        info.bytesPerPixel = 1;
+        info.bitsPerPixel = 12;
+        goto done;
+    case HAL_PIXEL_FORMAT_YCbCr_422_I:
+        // defined as the bytes per pixel of the Y plane
+        info.bytesPerPixel = 1;
+        info.bitsPerPixel = 16;
+        goto done;
+    }
+
+    err = getPixelFormatInfo(format, &info);
     if (err < 0) {
         doThrow(env, "java/lang/IllegalArgumentException");
         return;
     }
+
+done:
     env->SetIntField(pixelFormatObject, offsets.bytesPerPixel, info.bytesPerPixel);
     env->SetIntField(pixelFormatObject, offsets.bitsPerPixel,  info.bitsPerPixel);
 }
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 4e1ae62..5432efb 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -1122,9 +1122,10 @@
     if (dbus_set_error_from_message(&err, msg)) {
         if (dbus_error_has_name(&err, "org.bluez.Error.AlreadyExists")) {
             result = CREATE_DEVICE_ALREADY_EXISTS;
+        } else {
+            result = CREATE_DEVICE_FAILED;
         }
         LOG_AND_FREE_DBUS_ERROR(&err);
-        result = CREATE_DEVICE_FAILED;
     }
     env->CallVoidMethod(nat->me,
                         method_onCreateDeviceResult,
diff --git a/core/jni/android_text_AndroidCharacter.cpp b/core/jni/android_text_AndroidCharacter.cpp
index 1353478..5d8d419 100644
--- a/core/jni/android_text_AndroidCharacter.cpp
+++ b/core/jni/android_text_AndroidCharacter.cpp
@@ -165,7 +165,8 @@
         goto MIRROR_END;
     }
 
-    if (start > start + count || env->GetArrayLength(charArray) < count) {
+    if (start < 0 || start > start + count
+            || env->GetArrayLength(charArray) < start + count) {
         jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
         goto MIRROR_END;
     }
diff --git a/core/jni/android_util_FileObserver.cpp b/core/jni/android_util_FileObserver.cpp
index 13a1645..65e7130 100644
--- a/core/jni/android_util_FileObserver.cpp
+++ b/core/jni/android_util_FileObserver.cpp
@@ -71,28 +71,32 @@
             return;
         }
         
-    	while (num_bytes >= (int)sizeof(*event))
-    	{
-			int event_size;
-			event = (struct inotify_event *)(event_buf + event_pos);
-			
+        while (num_bytes >= (int)sizeof(*event))
+        {
+            int event_size;
+            event = (struct inotify_event *)(event_buf + event_pos);
+
             jstring path = NULL;
             
             if (event->len > 0)
             {
                 path = env->NewStringUTF(event->name);
             }
-            
-		    env->CallVoidMethod(object, method_onEvent, event->wd, event->mask, path);
+
+            env->CallVoidMethod(object, method_onEvent, event->wd, event->mask, path);
+            if (env->ExceptionCheck()) {
+                env->ExceptionDescribe();
+                env->ExceptionClear();
+            }
             if (path != NULL)
             {
                 env->DeleteLocalRef(path);
             }
-		    
-		    event_size = sizeof(*event) + event->len;
-			num_bytes -= event_size;
-			event_pos += event_size;
-		}
+
+            event_size = sizeof(*event) + event->len;
+            num_bytes -= event_size;
+            event_pos += event_size;
+        }
     }
     
 #endif // HAVE_INOTIFY
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a27d28f..63584ed 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1041,6 +1041,12 @@
         android:description="@string/permdesc_deletePackages"
         android:protectionLevel="signatureOrSystem" />
 
+    <!-- Allows an application to move location of installed package. -->
+    <permission android:name="android.permission.MOVE_PACKAGE"
+        android:label="@string/permlab_movePackage"
+        android:description="@string/permdesc_movePackage"
+        android:protectionLevel="signatureOrSystem" />
+
     <!-- Allows an application to change whether an application component (other than its own) is
          enabled or not. -->
     <permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"
@@ -1252,6 +1258,10 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
+        <activity android:name="com.android.internal.app.DisableCarModeActivity"
+                android:theme="@style/Theme.NoDisplay"
+                android:excludeFromRecents="true">
+        </activity>
         <activity android:name="com.android.internal.app.RingtonePickerActivity"
                 android:theme="@style/Theme.Dialog.Alert"
                 android:excludeFromRecents="true"
diff --git a/core/res/res/drawable-hdpi/stat_notify_car_mode.png b/core/res/res/drawable-hdpi/stat_notify_car_mode.png
new file mode 100644
index 0000000..6c51b32
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_car_mode.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_car_mode.png b/core/res/res/drawable-mdpi/stat_notify_car_mode.png
new file mode 100644
index 0000000..c664244
--- /dev/null
+++ b/core/res/res/drawable-mdpi/stat_notify_car_mode.png
Binary files differ
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6f34b4f..f1501ae 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -680,6 +680,11 @@
         restricted usually to system process.</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_movePackage">Move application resources</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_movePackage">Allows an application to move application resources from internal to external media and vice versa.</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_readLogs">read system log files</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_readLogs">Allows an application to read from the
@@ -1694,6 +1699,17 @@
         <item quantity="other"><xliff:g id="count">%d</xliff:g> hours ago</item>
     </plurals>
 
+    <!-- This is used to express that something occurred within the last X days (e.g., Last 7 days). -->
+    <plurals name="last_num_days">
+        <item quantity="other">Last <xliff:g id="count">%d</xliff:g> days</item>
+    </plurals>
+
+    <!-- This is used to express that something has occurred within the last month -->
+    <string name="last_month">Last month</string>
+
+    <!-- This is used to express that something happened longer ago than the previous options -->
+    <string name="older">Older</string>
+
     <!-- This is used to express that something occurred some number of days in the past (e.g., 5 days ago). -->
     <plurals name="num_days_ago">
         <item quantity="one">yesterday</item>
@@ -2261,4 +2277,9 @@
     <!-- See TETHER_STOP_DIALOG.  If there was an error disconnect, this is the text. -->
     <string name="tether_stop_error_message">We\'ve encountered a problem turning off Tethering. Please try again.</string>
 
+    <!-- Strings for car mode notification -->
+    <!-- Shown when car mode is enabled -->
+    <string name="car_mode_disable_notification_title">Car mode enabled</string>
+    <string name="car_mode_disable_notification_message">Select to disable car mode.</string>
+
 </resources>
diff --git a/core/res/res/xml-mdpi/password_kbd_qwerty.xml b/core/res/res/xml-mdpi/password_kbd_qwerty.xml
index a3d4e88..bae1b42 100755
--- a/core/res/res/xml-mdpi/password_kbd_qwerty.xml
+++ b/core/res/res/xml-mdpi/password_kbd_qwerty.xml
@@ -80,8 +80,8 @@
         <Key android:keyLabel="=" />
         <Key android:codes="46" android:keyLabel="."
             android:keyWidth="10%p"/>
-        <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
+        <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_ok"
+            android:iconPreview="@drawable/sym_keyboard_feedback_ok"
             android:keyWidth="20%p" android:keyEdgeFlags="right"/>
     </Row>
 
diff --git a/core/res/res/xml-mdpi/password_kbd_qwerty_shifted.xml b/core/res/res/xml-mdpi/password_kbd_qwerty_shifted.xml
index 2285d91..612df9c 100755
--- a/core/res/res/xml-mdpi/password_kbd_qwerty_shifted.xml
+++ b/core/res/res/xml-mdpi/password_kbd_qwerty_shifted.xml
@@ -79,8 +79,8 @@
             android:keyWidth="20%p" android:isRepeatable="true"/>
         <Key android:keyLabel="+" />
         <Key android:codes="46" android:keyLabel="."/>
-        <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
+        <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_ok"
+            android:iconPreview="@drawable/sym_keyboard_feedback_ok"
             android:keyWidth="20%p" android:keyEdgeFlags="right"/>
     </Row>
 
diff --git a/core/tests/coretests/src/android/app/SearchManagerTest.java b/core/tests/coretests/src/android/app/SearchManagerTest.java
index fc7e787..08b7f60 100644
--- a/core/tests/coretests/src/android/app/SearchManagerTest.java
+++ b/core/tests/coretests/src/android/app/SearchManagerTest.java
@@ -120,23 +120,6 @@
         assertSame(searchManager1, searchManager2 );
     }
 
-    @MediumTest
-    public void testSearchables() {
-        SearchManager searchManager = (SearchManager)
-                mContext.getSystemService(Context.SEARCH_SERVICE);
-        SearchableInfo si;
-
-        si = searchManager.getSearchableInfo(SEARCHABLE_ACTIVITY, false);
-        assertNotNull(si);
-        assertFalse(searchManager.isDefaultSearchable(si));
-        si = searchManager.getSearchableInfo(SEARCHABLE_ACTIVITY, true);
-        assertNotNull(si);
-        assertTrue(searchManager.isDefaultSearchable(si));
-        si = searchManager.getSearchableInfo(null, true);
-        assertNotNull(si);
-        assertTrue(searchManager.isDefaultSearchable(si));
-    }
-
     /**
      * Tests that startSearch() can be called multiple times without stopSearch()
      * in between.
diff --git a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
index ca650e0..e43031c 100644
--- a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
@@ -944,6 +944,7 @@
         Assert.assertNull(cur.getString(3));
         Assert.assertEquals(1234, cur.getLong(4));
         Assert.assertNull(cur.getString(5));
+        cur.close();
 
         cv = new ContentValues();
         cv.put("s", "two");
@@ -956,6 +957,7 @@
         Assert.assertNull(cur.getString(3));
         Assert.assertEquals(1234, cur.getLong(4));
         Assert.assertNull(cur.getString(5));
+        cur.close();
 
         cv = new ContentValues();
         cv.put("t", "goodbye world");
@@ -975,6 +977,7 @@
         Assert.assertEquals(2345, cur.getLong(3));
         Assert.assertEquals(3456, cur.getLong(4));
         Assert.assertEquals("tricky", cur.getString(5));
+        cur.close();
 
         cv = new ContentValues();
         cv.put("s", "three");
@@ -987,6 +990,7 @@
         Assert.assertEquals("three", cur.getString(1));
         Assert.assertEquals("hello world", cur.getString(2));
         Assert.assertEquals(6789, cur.getLong(3));
+        cur.close();
 
         ih.close();
     }
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteGeneralTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteGeneralTest.java
new file mode 100644
index 0000000..af7ccceb
--- /dev/null
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteGeneralTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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.database.sqlite;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+import android.test.FlakyTest;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import java.io.File;
+
+public class SQLiteGeneralTest extends AndroidTestCase {
+
+    private SQLiteDatabase mDatabase;
+    private File mDatabaseFile;
+    Boolean exceptionRecvd = false;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        exceptionRecvd = false;
+        File dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE);
+        mDatabaseFile = new File(dbDir, "database_test.db");
+        if (mDatabaseFile.exists()) {
+            mDatabaseFile.delete();
+        }
+        mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
+        assertNotNull(mDatabase);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mDatabase.close();
+        mDatabaseFile.delete();
+        super.tearDown();
+    }
+
+    @LargeTest
+    public void testUseOfSameSqlStatementBy2Threads() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test_pstmt (i INTEGER PRIMARY KEY, j text);");
+
+        // thread 1 creates a prepared statement
+        final String stmt = "SELECT * FROM test_pstmt WHERE i = ?";
+
+        // start 2 threads to do repeatedly execute "stmt"
+        // since these 2 threads are executing the same sql, they each should get
+        // their own copy and
+        // there SHOULD NOT be an error from sqlite: "prepared statement is busy"
+        class RunStmtThread extends Thread {
+            private static final int N = 1000;
+            @Override public void run() {
+                int i = 0;
+                try {
+                    // execute many times
+                    for (i = 0; i < N; i++) {
+                        SQLiteStatement s1 = mDatabase.compileStatement(stmt);
+                        s1.bindLong(1, i);
+                        s1.execute();
+                        s1.close();
+                    }
+                } catch (SQLiteException e) {
+                    fail("SQLiteException: " + e.getMessage());
+                    return;
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    fail("random unexpected exception: " + e.getMessage());
+                    return;
+                }
+            }
+        }
+        RunStmtThread t1 = new RunStmtThread();
+        t1.start();
+        RunStmtThread t2 = new RunStmtThread();
+        t2.start();
+        while (t1.isAlive() || t2.isAlive()) {
+            Thread.sleep(1000);
+        }
+    }
+
+    @FlakyTest
+    public void testUseOfSamePreparedStatementBy2Threads() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test_pstmt (i INTEGER PRIMARY KEY, j text);");
+
+        // thread 1 creates a prepared statement
+        final String stmt = "SELECT * FROM test_pstmt WHERE i = ?";
+        final SQLiteStatement s1 = mDatabase.compileStatement(stmt);
+
+        // start 2 threads to do repeatedly execute "stmt"
+        // since these 2 threads are executing the same prepared statement,
+        // should see an error from sqlite: "prepared statement is busy"
+        class RunStmtThread extends Thread {
+            private static final int N = 1000;
+            @Override public void run() {
+                int i = 0;
+                try {
+                    // execute many times
+                    for (i = 0; i < N; i++) {
+                        s1.bindLong(1, i);
+                        s1.execute();
+                    }
+                } catch (SQLiteException e) {
+                    // expect it
+                    assertTrue(e.getMessage().contains("library routine called out of sequence:"));
+                    exceptionRecvd = true;
+                    return;
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    fail("random unexpected exception: " + e.getMessage());
+                    return;
+                }
+            }
+        }
+        RunStmtThread t1 = new RunStmtThread();
+        t1.start();
+        RunStmtThread t2 = new RunStmtThread();
+        t2.start();
+        while (t1.isAlive() || t2.isAlive()) {
+            Thread.sleep(1000);
+        }
+        assertTrue(exceptionRecvd);
+    }
+}
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java
new file mode 100644
index 0000000..1e4db3d
--- /dev/null
+++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java
@@ -0,0 +1,319 @@
+/*
+ * 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.text;
+
+import android.graphics.Paint.FontMetricsInt;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.Layout.Alignment;
+import static android.text.Layout.Alignment.*;
+import android.util.Log;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests StaticLayout vertical metrics behavior.
+ */
+public class StaticLayoutTest extends TestCase {
+
+    /**
+     * Basic test showing expected behavior and relationship between font
+     * metrics and line metrics.
+     */
+    @SmallTest
+    public void testGetters1() {
+        LayoutBuilder b = builder();
+        FontMetricsInt fmi = b.paint.getFontMetricsInt();
+
+        // check default paint
+        Log.i("TG1:paint", fmi.toString());
+
+        Layout l = b.build();
+        assertVertMetrics(l, 0, 0,
+                fmi.ascent, fmi.descent);
+
+        // other quick metrics
+        assertEquals(0, l.getLineStart(0));
+        assertEquals(Layout.DIR_LEFT_TO_RIGHT, l.getParagraphDirection(0));
+        assertEquals(false, l.getLineContainsTab(0));
+        assertEquals(Layout.DIRS_ALL_LEFT_TO_RIGHT, l.getLineDirections(0));
+        assertEquals(0, l.getEllipsisCount(0));
+        assertEquals(0, l.getEllipsisStart(0));
+        assertEquals(b.width, l.getEllipsizedWidth());
+    }
+
+    /**
+     * Basic test showing effect of includePad = true with 1 line.
+     * Top and bottom padding are affected, as is the line descent and height.
+     */
+    @SmallTest
+    public void testGetters2() {
+        LayoutBuilder b = builder()
+            .setIncludePad(true);
+        FontMetricsInt fmi = b.paint.getFontMetricsInt();
+
+        Layout l = b.build();
+        assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent,
+                fmi.top, fmi.bottom);
+    }
+
+    /**
+     * Basic test showing effect of includePad = true wrapping to 2 lines.
+     * Ascent of top line and descent of bottom line are affected.
+     */
+    @SmallTest
+    public void testGetters3() {
+        LayoutBuilder b = builder()
+            .setIncludePad(true)
+            .setWidth(50);
+        FontMetricsInt fmi = b.paint.getFontMetricsInt();
+
+        Layout l =  b.build();
+        assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent,
+            fmi.top, fmi.descent,
+            fmi.ascent, fmi.bottom);
+    }
+
+    /**
+     * Basic test showing effect of includePad = true wrapping to 3 lines.
+     * First line ascent is top, bottom line descent is bottom.
+     */
+    @SmallTest
+    public void testGetters4() {
+        LayoutBuilder b = builder()
+            .setText("This is a longer test")
+            .setIncludePad(true)
+            .setWidth(50);
+        FontMetricsInt fmi = b.paint.getFontMetricsInt();
+
+        Layout l = b.build();
+        assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent,
+                fmi.top, fmi.descent,
+                fmi.ascent, fmi.descent,
+                fmi.ascent, fmi.bottom);
+    }
+
+    /**
+     * Basic test showing effect of includePad = true wrapping to 3 lines and
+     * large text. See effect of leading. Currently, we don't expect there to
+     * even be non-zero leading.
+     */
+    @SmallTest
+    public void testGetters5() {
+        LayoutBuilder b = builder()
+            .setText("This is a longer test")
+            .setIncludePad(true)
+            .setWidth(150);
+        b.paint.setTextSize(36);
+        FontMetricsInt fmi = b.paint.getFontMetricsInt();
+
+        if (fmi.leading == 0) { // nothing to test
+            Log.i("TG5", "leading is 0, skipping test");
+            return;
+        }
+
+        // So far, leading is not used, so this is the same as TG4.  If we start
+        // using leading, this will fail.
+        Layout l = b.build();
+        assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent,
+                fmi.top, fmi.descent,
+                fmi.ascent, fmi.descent,
+                fmi.ascent, fmi.bottom);
+    }
+
+    /**
+     * Basic test showing effect of includePad = true, spacingAdd = 2, wrapping
+     * to 3 lines.
+     */
+    @SmallTest
+    public void testGetters6() {
+        int spacingAdd = 2; // int so expressions return int
+        LayoutBuilder b = builder()
+            .setText("This is a longer test")
+            .setIncludePad(true)
+            .setWidth(50)
+            .setSpacingAdd(spacingAdd);
+        FontMetricsInt fmi = b.paint.getFontMetricsInt();
+
+        Layout l = b.build();
+        assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent,
+                fmi.top, fmi.descent + spacingAdd,
+                fmi.ascent, fmi.descent + spacingAdd,
+                fmi.ascent, fmi.bottom + spacingAdd);
+    }
+
+    /**
+     * Basic test showing effect of includePad = true, spacingAdd = 2,
+     * spacingMult = 1.5, wrapping to 3 lines.
+     */
+    @SmallTest
+    public void testGetters7() {
+        LayoutBuilder b = builder()
+            .setText("This is a longer test")
+            .setIncludePad(true)
+            .setWidth(50)
+            .setSpacingAdd(2)
+            .setSpacingMult(1.5f);
+        FontMetricsInt fmi = b.paint.getFontMetricsInt();
+        Scaler s = new Scaler(b.spacingMult, b.spacingAdd);
+
+        Layout l = b.build();
+        assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent,
+                fmi.top, fmi.descent + s.scale(fmi.descent - fmi.top),
+                fmi.ascent, fmi.descent + s.scale(fmi.descent - fmi.ascent),
+                fmi.ascent, fmi.bottom + s.scale(fmi.bottom - fmi.ascent));
+    }
+
+    /**
+     * Basic test showing effect of includePad = true, spacingAdd = 0,
+     * spacingMult = 0.8 when wrapping to 3 lines.
+     */
+    @SmallTest
+    public void testGetters8() {
+        LayoutBuilder b = builder()
+            .setText("This is a longer test")
+            .setIncludePad(true)
+            .setWidth(50)
+            .setSpacingAdd(2)
+            .setSpacingMult(.8f);
+        FontMetricsInt fmi = b.paint.getFontMetricsInt();
+        Scaler s = new Scaler(b.spacingMult, b.spacingAdd);
+
+        Layout l = b.build();
+        assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent,
+                fmi.top, fmi.descent + s.scale(fmi.descent - fmi.top),
+                fmi.ascent, fmi.descent + s.scale(fmi.descent - fmi.ascent),
+                fmi.ascent, fmi.bottom + s.scale(fmi.bottom - fmi.ascent));
+    }
+
+    // ----- test utility classes and methods -----
+
+    // Models the effect of the scale and add parameters.  I think the current
+    // implementation misbehaves.
+    private static class Scaler {
+        private final float sMult;
+        private final float sAdd;
+
+        Scaler(float sMult, float sAdd) {
+            this.sMult = sMult - 1;
+            this.sAdd = sAdd;
+        }
+
+        public int scale(float height) {
+            int altVal = (int)(height * sMult + sAdd + 0.5); // existing impl
+            int rndVal = Math.round(height * sMult + sAdd);
+            if (altVal != rndVal) {
+                Log.i("Scale", "expected scale: " + rndVal +
+                        " != returned scale: " + altVal);
+            }
+            return altVal; // existing implementation
+        }
+    }
+
+    private static LayoutBuilder builder() {
+        return new LayoutBuilder();
+    }
+
+    private static class LayoutBuilder {
+        String text = "This is a test";
+        TextPaint paint = new TextPaint(); // default
+        int width = 100;
+        Alignment align = ALIGN_NORMAL;
+        float spacingMult = 1;
+        float spacingAdd = 0;
+        boolean includePad = false;
+
+        LayoutBuilder setText(String text) {
+            this.text = text;
+            return this;
+        }
+
+        LayoutBuilder setPaint(TextPaint paint) {
+            this.paint = paint;
+            return this;
+        }
+
+        LayoutBuilder setWidth(int width) {
+            this.width = width;
+            return this;
+        }
+
+        LayoutBuilder setAlignment(Alignment align) {
+            this.align = align;
+            return this;
+        }
+
+        LayoutBuilder setSpacingMult(float spacingMult) {
+            this.spacingMult = spacingMult;
+            return this;
+        }
+
+        LayoutBuilder setSpacingAdd(float spacingAdd) {
+            this.spacingAdd = spacingAdd;
+            return this;
+        }
+
+        LayoutBuilder setIncludePad(boolean includePad) {
+            this.includePad = includePad;
+            return this;
+        }
+
+       Layout build() {
+            return  new StaticLayout(text, paint, width, align, spacingMult,
+                spacingAdd, includePad);
+        }
+    }
+
+    private void assertVertMetrics(Layout l, int topPad, int botPad, int... values) {
+        assertTopBotPadding(l, topPad, botPad);
+        assertLinesMetrics(l, values);
+    }
+
+    private void assertLinesMetrics(Layout l, int... values) {
+        // sanity check
+        if ((values.length & 0x1) != 0) {
+            throw new IllegalArgumentException(String.valueOf(values.length));
+        }
+
+        int lines = values.length >> 1;
+        assertEquals(lines, l.getLineCount());
+
+        int t = 0;
+        for (int i = 0, n = 0; i < lines; ++i, n += 2) {
+            int a = values[n];
+            int d = values[n+1];
+            int h = -a + d;
+            assertLineMetrics(l, i, t, a, d, h);
+            t += h;
+        }
+
+        assertEquals(t, l.getHeight());
+    }
+
+    private void assertLineMetrics(Layout l, int line,
+            int top, int ascent, int descent, int height) {
+        String info = "line " + line;
+        assertEquals(info, top, l.getLineTop(line));
+        assertEquals(info, ascent, l.getLineAscent(line));
+        assertEquals(info, descent, l.getLineDescent(line));
+        assertEquals(info, height, l.getLineBottom(line) - top);
+    }
+
+    private void assertTopBotPadding(Layout l, int topPad, int botPad) {
+        assertEquals(topPad, l.getTopPadding());
+        assertEquals(botPad, l.getBottomPadding());
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/listview/ListGetCheckItemIdsTest.java b/core/tests/coretests/src/android/widget/listview/ListGetCheckItemIdsTest.java
new file mode 100644
index 0000000..33d61a0
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/listview/ListGetCheckItemIdsTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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.widget.listview;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+
+import java.util.Arrays;
+
+/**
+ * Testing the ListView getCheckItemIds() method in different situations.
+ */
+public class ListGetCheckItemIdsTest extends ActivityInstrumentationTestCase2<ListSimple> {
+    private ListView mListView;
+
+    public ListGetCheckItemIdsTest() {
+        super(ListSimple.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mListView = getActivity().getListView();
+    }
+
+    private void assertChecked(String message, long... expectedIds) {
+        // Sort the two arrays since we are actually doing a set equality.
+        long[] checkItemIds = mListView.getCheckItemIds();
+        long[] sortedCheckItemsIds = new long[checkItemIds.length];
+        System.arraycopy(checkItemIds, 0, sortedCheckItemsIds, 0, checkItemIds.length);
+        Arrays.sort(sortedCheckItemsIds);
+
+        long[] sortedExpectedIds = new long[expectedIds.length];
+        System.arraycopy(expectedIds, 0, sortedExpectedIds, 0, expectedIds.length);
+        Arrays.sort(sortedExpectedIds);
+
+        assertTrue(message, Arrays.equals(sortedExpectedIds, sortedCheckItemsIds));
+    }
+
+    @MediumTest
+    @UiThreadTest
+    public void testNoneCheck() {
+        mListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
+
+        mListView.setItemChecked(0, true);
+        assertChecked("None check choice has item checked");
+    }
+
+    @MediumTest
+    @UiThreadTest
+    public void testSimpleCheck() {
+        mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+        assertChecked("Item checked when setting Single mode");
+
+        // Test a check at each position
+        int childCount = mListView.getChildCount();
+        for (int i=0; i<childCount; i++) {
+            mListView.setItemChecked(i, true);
+            assertChecked("Only element " + i + " should be checked", i);
+        }
+
+        // Check an element and uncheck some others
+        for (int i = 0; i < childCount; i++) {
+            mListView.setItemChecked(i, true);
+            mListView.setItemChecked((i - 3 + childCount) % childCount, false);
+            mListView.setItemChecked((i + 1) % childCount, false);
+            assertChecked("Only element " + i + " should be checked", i);
+        }
+    }
+
+    @MediumTest
+    @UiThreadTest
+    public void testMultipleCheck() {
+        mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
+        assertChecked("Item checked when setting Multiple mode");
+
+        int childCount = mListView.getChildCount();
+        assertTrue("Tests requires at least 4 items", childCount >= 4);
+
+        mListView.setItemChecked(1, true);
+        assertChecked("First element non checked", 1);
+
+        mListView.setItemChecked(3, true);
+        assertChecked("Second element not checked", 1, 3);
+
+        mListView.setItemChecked(0, true);
+        assertChecked("Third element not checked", 0, 1, 3);
+
+        mListView.setItemChecked(2, false);
+        assertChecked("Unchecked element appears checked", 0, 1, 3);
+
+        mListView.setItemChecked(1, false);
+        assertChecked("Unchecked element remains", 0, 3);
+
+        mListView.setItemChecked(2, false);
+        assertChecked("Already unchecked element appears", 0, 3);
+
+        mListView.setItemChecked(3, false);
+        assertChecked("Unchecked 3 remains", 0);
+
+        mListView.setItemChecked(3, false);
+        assertChecked("Twice unchecked 3 remains", 0);
+
+        mListView.setItemChecked(0, false);
+        assertChecked("Checked items after last element unchecked");
+    }
+
+    @MediumTest
+    @UiThreadTest
+    public void testClearChoices() {
+        mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+        mListView.setItemChecked(0, true);
+        mListView.clearChoices();
+        assertChecked("Item checked after SINGLE clear choice");
+
+        mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
+        int childCount = mListView.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            mListView.setItemChecked(0, i % 3 == 0);
+        }
+        mListView.clearChoices();
+        assertChecked("Item checked after MULTIPLE clear choice");
+    }
+}
diff --git a/core/tests/hosttests/Android.mk b/core/tests/hosttests/Android.mk
new file mode 100644
index 0000000..0001201
--- /dev/null
+++ b/core/tests/hosttests/Android.mk
@@ -0,0 +1,32 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+#LOCAL_TEST_TYPE := hostSideOnly
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := FrameworkCoreHostTests
+
+LOCAL_JAVA_LIBRARIES := hosttestlib ddmlib junit
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+# Build the test APKs using their own makefiles
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/core/tests/hosttests/README b/core/tests/hosttests/README
new file mode 100644
index 0000000..d3bdb83
--- /dev/null
+++ b/core/tests/hosttests/README
@@ -0,0 +1,6 @@
+This dir contains tests which run on a host machine, and test aspects of
+package install etc via adb.
+
+To run, do:
+runtest framework-core-host
+
diff --git a/core/tests/hosttests/src/android/content/pm/PackageManagerHostTests.java b/core/tests/hosttests/src/android/content/pm/PackageManagerHostTests.java
new file mode 100644
index 0000000..9c9d777
--- /dev/null
+++ b/core/tests/hosttests/src/android/content/pm/PackageManagerHostTests.java
@@ -0,0 +1,216 @@
+/*
+ * 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.content.pm;
+
+import com.android.ddmlib.IShellOutputReceiver;
+import com.android.ddmlib.Log;
+import com.android.ddmlib.MultiLineReceiver;
+import com.android.ddmlib.SyncService;
+import com.android.ddmlib.SyncService.ISyncProgressMonitor;
+import com.android.ddmlib.SyncService.SyncResult;
+import com.android.hosttest.DeviceTestCase;
+import com.android.hosttest.DeviceTestSuite;
+
+import java.io.File;
+import java.io.IOException;
+
+import junit.framework.Test;
+
+/**
+ * Set of tests that verify host side install cases
+ */
+public class PackageManagerHostTests extends DeviceTestCase {
+
+    // testPushAppPrivate constants
+    // these constants must match values defined in test-apps/SimpleTestApp
+    private static final String SIMPLE_APK = "SimpleTestApp.apk";
+    private static final String SIMPLE_PKG = "com.android.framework.simpletestapp";
+    // TODO: get this value from Android Environment instead of hardcoding
+    private static final String APP_PRIVATE_PATH = "/data/app-private/";
+
+    private static final String LOG_TAG = "PackageManagerHostTests";
+
+    private static final int MAX_WAIT_FOR_DEVICE_TIME = 120 * 1000;
+    private static final int WAIT_FOR_DEVICE_POLL_TIME = 10 * 1000;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // ensure apk path has been set before test is run
+        assertNotNull(getTestAppPath());
+    }
+
+    /**
+     * Regression test to verify that pushing an apk to the private app directory doesn't install
+     * the app, and otherwise cause the system to blow up.
+     * <p/>
+     * Assumes adb is running as root in device under test.
+     */
+    public void testPushAppPrivate() throws IOException, InterruptedException {
+        Log.i(LOG_TAG, "testing pushing an apk to /data/app-private");
+        final String apkAppPrivatePath =  APP_PRIVATE_PATH + SIMPLE_APK;
+
+        // cleanup test app just in case it was accidently installed
+        getDevice().uninstallPackage(SIMPLE_PKG);
+        executeShellCommand("stop");
+        pushFile(getTestAppFilePath(SIMPLE_APK), apkAppPrivatePath);
+        // sanity check to make sure file is there
+        assertTrue(doesRemoteFileExist(apkAppPrivatePath));
+        executeShellCommand("start");
+
+        waitForDevice();
+
+        // grep for package to make sure its not installed
+        assertFalse(doesPackageExist(SIMPLE_PKG));
+        // ensure it has been deleted from app-private
+        assertFalse(doesRemoteFileExist(apkAppPrivatePath));
+    }
+
+    /**
+     * Helper method to push a file to device
+     * @param apkAppPrivatePath
+     * @throws IOException
+     */
+    private void pushFile(final String localFilePath, final String destFilePath)
+            throws IOException {
+        SyncResult result = getDevice().getSyncService().pushFile(
+                localFilePath, destFilePath,
+                new NullSyncProgressMonitor());
+        assertEquals(SyncService.RESULT_OK, result.getCode());
+    }
+
+    /**
+     * Helper method to determine if file on device exists.
+     *
+     * @param destPath the absolute path of file on device to check
+     * @return <code>true</code> if file exists, <code>false</code> otherwise.
+     * @throws IOException if adb shell command failed
+     */
+    private boolean doesRemoteFileExist(String destPath) throws IOException {
+        String lsGrep = executeShellCommand(String.format("ls %s",
+                destPath));
+        return !lsGrep.contains("No such file or directory");
+    }
+
+    /**
+     * Helper method to determine if package on device exists.
+     *
+     * @param packageName the Android manifest package to check.
+     * @return <code>true</code> if package exists, <code>false</code> otherwise
+     * @throws IOException if adb shell command failed
+     */
+    private boolean doesPackageExist(String packageName) throws IOException {
+        String pkgGrep = executeShellCommand(String.format("pm path %s",
+                packageName));
+        return pkgGrep.contains("package:");
+    }
+
+    /**
+     * Waits for device's package manager to respond.
+     *
+     * @throws InterruptedException
+     * @throws IOException
+     */
+    private void waitForDevice() throws InterruptedException, IOException {
+        Log.i(LOG_TAG, "waiting for device");
+        int currentWaitTime = 0;
+        // poll the package manager until it returns something for android
+        while (!doesPackageExist("android")) {
+            Thread.sleep(WAIT_FOR_DEVICE_POLL_TIME);
+            currentWaitTime += WAIT_FOR_DEVICE_POLL_TIME;
+            if (currentWaitTime > MAX_WAIT_FOR_DEVICE_TIME) {
+                Log.e(LOG_TAG, "time out waiting for device");
+                throw new InterruptedException();
+            }
+        }
+    }
+
+    /**
+     * Helper method which executes a adb shell command and returns output as a {@link String}
+     * @return
+     * @throws IOException
+     */
+    private String executeShellCommand(String command) throws IOException {
+        Log.d(LOG_TAG, String.format("adb shell %s", command));
+        CollectingOutputReceiver receiver = new CollectingOutputReceiver();
+        getDevice().executeShellCommand(command, receiver);
+        String output = receiver.getOutput();
+        Log.d(LOG_TAG, String.format("Result: %s", output));
+        return output;
+    }
+
+    /**
+     * Get the absolute file system location of test app with given filename
+     * @param fileName the file name of the test app apk
+     * @return {@link String} of absolute file path
+     */
+    private String getTestAppFilePath(String fileName) {
+        return String.format("%s%s%s", getTestAppPath(), File.separator, fileName);
+    }
+
+    public static Test suite() {
+        return new DeviceTestSuite(PackageManagerHostTests.class);
+    }
+
+    /**
+     * A {@link IShellOutputReceiver} which collects the whole shell output into one {@link String}
+     */
+    private static class CollectingOutputReceiver extends MultiLineReceiver {
+
+        private StringBuffer mOutputBuffer = new StringBuffer();
+
+        public String getOutput() {
+            return mOutputBuffer.toString();
+        }
+
+        @Override
+        public void processNewLines(String[] lines) {
+            for (String line: lines) {
+                mOutputBuffer.append(line);
+                mOutputBuffer.append("\n");
+            }
+        }
+
+        public boolean isCancelled() {
+            return false;
+        }
+    }
+
+    private static class NullSyncProgressMonitor implements ISyncProgressMonitor {
+        public void advance(int work) {
+            // ignore
+        }
+
+        public boolean isCanceled() {
+            // ignore
+            return false;
+        }
+
+        public void start(int totalWork) {
+            // ignore
+
+        }
+
+        public void startSubTask(String name) {
+            // ignore
+        }
+
+        public void stop() {
+            // ignore
+        }
+    }
+}
diff --git a/core/tests/hosttests/test-apps/Android.mk b/core/tests/hosttests/test-apps/Android.mk
new file mode 100644
index 0000000..e25764f
--- /dev/null
+++ b/core/tests/hosttests/test-apps/Android.mk
@@ -0,0 +1,21 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Build the test APKs using their own makefiles
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/core/tests/hosttests/test-apps/SimpleTestApp/Android.mk b/core/tests/hosttests/test-apps/SimpleTestApp/Android.mk
new file mode 100644
index 0000000..82543aa
--- /dev/null
+++ b/core/tests/hosttests/test-apps/SimpleTestApp/Android.mk
@@ -0,0 +1,27 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := SimpleTestApp
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/SimpleTestApp/AndroidManifest.xml b/core/tests/hosttests/test-apps/SimpleTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..ae36fe7
--- /dev/null
+++ b/core/tests/hosttests/test-apps/SimpleTestApp/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+       package="com.android.framework.simpletestapp">
+
+    <!--
+    A simple empty app used to test various install scenarios/
+    -->
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/SimpleTestApp/src/com/android/framework/simpletestapp/SimpleAppActivity.java b/core/tests/hosttests/test-apps/SimpleTestApp/src/com/android/framework/simpletestapp/SimpleAppActivity.java
new file mode 100644
index 0000000..b7bbf94
--- /dev/null
+++ b/core/tests/hosttests/test-apps/SimpleTestApp/src/com/android/framework/simpletestapp/SimpleAppActivity.java
@@ -0,0 +1,25 @@
+/*
+ * 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.framework.simpletestapp;
+
+import android.app.Activity;
+
+/**
+ * Empty activity, not needed for this test
+ */
+public class SimpleAppActivity extends Activity {
+
+}
diff --git a/docs/html/guide/practices/design/performance.jd b/docs/html/guide/practices/design/performance.jd
index ec34ac9..ab3b3d3 100644
--- a/docs/html/guide/practices/design/performance.jd
+++ b/docs/html/guide/practices/design/performance.jd
@@ -1,39 +1,37 @@
 page.title=Designing for Performance
 @jd:body
 
-<p>An Android application should be fast. Well, it's probably more accurate to
-say that it should be <em>efficient</em>. That is, it should execute as
-efficiently as possible in the mobile device environment, with its limited
-computing power and data storage, smaller screen, and constrained battery life. 
+<p>An Android application should be <em>efficient</em>. It will run on a mobile
+device with limited computing power and storage, a smaller screen, and
+constrained battery life. Battery life is one reason you might want to
+optimize your app even if it already seems to run "fast enough". Battery life
+is important to users, and Android's battery usage breakdown means users will
+know if your app is responsible draining their battery.</p>
 
-<p>As you develop your application, keep in mind that, while the application may
-perform well enough in your emulator, running on your dual-core development
-computer, it will not perform that well when run a mobile device &mdash; even
-the most powerful mobile device can't match the capabilities of a typical
-desktop system. For that reason, you should strive to write efficient code, to
-ensure the best possible performance on a variety of mobile devices.</p>
-
-<p>Generally speaking, writing fast or efficient code means keeping memory
-allocations to a minimum, writing tight code, and avoiding certain language and
-programming idioms that can subtly cripple performance. In object-oriented
-terms, most of this work takes place at the <em>method</em> level, on the order of
-actual lines of code, loops, and so on.</p>
+<p>One of the trickiest problems you'll face when optimizing Android apps is
+that it's not generally the case that you can say "device X is a factor F
+faster/slower than device Y".
+This is especially true if one of the devices is the emulator, or one of the
+devices has a JIT. If you want to know how your app performs on a given device,
+you need to test it on that device. Drawing conclusions from the emulator is
+particularly dangerous, as is attempting to compare JIT versus non-JIT
+performance: the performance <em>profiles</em> can differ wildly.</p>
 
 <p>This document covers these topics: </p>
 <ul>
     <li><a href="#intro">Introduction</a></li>
     <li><a href="#optimize_judiciously">Optimize Judiciously</a></li>
     <li><a href="#object_creation">Avoid Creating Objects</a></li>
-    <li><a href="#native_methods">Use Native Methods</a></li>
-    <li><a href="#prefer_virtual">Prefer Virtual Over Interface</a></li>
+    <li><a href="#myths">Performance Myths</a></li>
     <li><a href="#prefer_static">Prefer Static Over Virtual</a></li>
     <li><a href="#internal_get_set">Avoid Internal Getters/Setters</a></li>
-    <li><a href="#cache_fields">Cache Field Lookups</a></li>
-    <li><a href="#use_final">Declare Constants Final</a></li>
-    <li><a href="#foreach">Use Enhanced For Loop Syntax With Caution</a></li>
-    <li><a href="#avoid_enums">Avoid Enums</a></li>
+    <li><a href="#use_final">Use Static Final For Constants</a></li>
+    <li><a href="#foreach">Use Enhanced For Loop Syntax</a></li>
+    <li><a href="#avoid_enums">Avoid Enums Where You Only Need Ints</a></li>
     <li><a href="#package_inner">Use Package Scope with Inner Classes</a></li>
-    <li><a href="#avoidfloat">Avoid Float</a> </li>
+    <li><a href="#avoidfloat">Use Floating-Point Judiciously</a> </li>
+    <li><a href="#library">Know And Use The Libraries</a></li>
+    <li><a href="#native_methods">Use Native Methods Judiciously</a></li>
     <li><a href="#samples">Some Sample Performance Numbers</a> </li>
     <li><a href="#closing_notes">Closing Notes</a></li>
 </ul>
@@ -41,43 +39,17 @@
 <a name="intro" id="intro"></a>
 <h2>Introduction</h2>
 
-<p>There are two basic rules for resource-constrained systems:</p>
+<p>There are two basic rules for writing efficient code:</p>
 
 <ul>
     <li>Don't do work that you don't need to do.</li>
     <li>Don't allocate memory if you can avoid it.</li>
 </ul>
 
-<p>All the tips below follow from these two basic tenets.</p>
-
-<p>Some would argue that much of the advice on this page amounts to "premature
-optimization." While it's true that micro-optimizations sometimes make it
-harder to develop efficient data structures and algorithms, on embedded
-devices like handsets you often simply have no choice.  For instance, if you
-bring your assumptions about VM performance on desktop machines to Android,
-you're quite likely to write code that exhausts system memory.  This will bring
-your application to a crawl &mdash; let alone what it will do to other programs
-running on the system!</p>
-
-<p>That's why these guidelines are important.  Android's success depends on
-the user experience that your applications provide, and that user experience
-depends in part on whether your code is responsive and snappy, or slow and
-aggravating.  Since all our applications will run on the same devices, we're
-all in this together, in a way.  Think of this document as like the rules of
-the road you had to learn when you got your driver's license:  things run
-smoothly when everybody follows them, but when you don't, you get your car
-smashed up.</p>
-
-<p>Before we get down to brass tacks, a brief observation: nearly all issues
-described below are valid whether or not the VM features a JIT compiler. If I
-have two methods that accomplish the same thing, and the interpreted execution
-of foo() is faster than bar(), then the compiled version of foo() will
-probably be as fast or faster than compiled bar(). It is unwise to rely on a
-compiler to "save" you and make your code fast enough.</p>
-
 <h2 id="optimize_judiciously">Optimize Judiciously</h2>
 
-<p>As you get started thinking about how to design your application, consider
+<p>As you get started thinking about how to design your application, and as
+you write it, consider
 the cautionary points about optimization that Josh Bloch makes in his book
 <em>Effective Java</em>. Here's "Item 47: Optimize Judiciously", excerpted from
 the latest edition of the book with permission. Although Josh didn't have
@@ -273,8 +245,8 @@
     instead of creating a short-lived temporary object.</li>
 </ul>
 
-<p>A somewhat more radical idea is to slice up multidimensional arrays into parallel
-single one-dimension arrays:</p>
+<p>A somewhat more radical idea is to slice up multidimensional arrays into
+parallel single one-dimension arrays:</p>
 
 <ul>
     <li>An array of ints is a much better than an array of Integers,
@@ -294,49 +266,32 @@
 can.  Fewer objects created mean less-frequent garbage collection, which has
 a direct impact on user experience.</p>
 
-<a name="native_methods" id="native_methods"></a>
-<h2>Use Native Methods</h2>
+<a name="myths" id="myths"></a>
+<h2>Performance Myths</h2>
 
-<p>When processing strings, don't hesitate to use specialty methods like
-String.indexOf(), String.lastIndexOf(), and their cousins. These are typically
-implemented in C/C++ code that easily runs 10-100x faster than doing the same
-thing in a Java loop.</p>
+<p>Previous versions of this document made various misleading claims. We
+address some of them here.</p>
 
-<p>The flip side of that advice is that punching through to a native
-method is more expensive than calling an interpreted method. Don't use native
-methods for trivial computation, if you can avoid it.</p>
+<p>On devices without a JIT, it is true that invoking methods via a
+variable with an exact type rather than an interface is slightly more
+efficient. (So, for example, it was cheaper to invoke methods on a
+<code>Map map</code> than a <code>HashMap map</code>, even though in both
+cases the map was a <code>HashMap</code>.) It was not the case that this
+was 2x slower; the actual difference was more like 6% slower. Furthermore,
+the JIT makes the two effectively indistinguishable.</p>
 
-<a name="prefer_virtual" id="prefer_virtual"></a>
-<h2>Prefer Virtual Over Interface</h2>
-
-<p>Suppose you have a HashMap object.  You can declare it as a HashMap or as
-a generic Map:</p>
-
-<pre>Map myMap1 = new HashMap();
-HashMap myMap2 = new HashMap();</pre>
-
-<p>Which is better?</p>
-
-<p>Conventional wisdom says that you should prefer Map, because it
-allows you to change the underlying implementation to anything that
-implements the Map interface.  Conventional wisdom is correct for
-conventional programming, but isn't so great for embedded systems.  Calling
-through an interface reference can take 2x longer than a virtual
-method call through a concrete reference.</p>
-
-<p>If you have chosen a HashMap because it fits what you're doing, there
-is little value in calling it a Map.  Given the availability of
-IDEs that refactor your code for you, there's not much value in calling
-it a Map even if you're not sure where the code is headed. (Again, though,
-public APIs are an exception:  a good API usually trumps small performance
-concerns.)</p>
+<p>On devices without a JIT, caching field accesses is about 20% faster than
+repeatedly accesssing the field. With a JIT, field access costs about the same
+as local access, so this isn't a worthwhile optimization unless you feel it
+makes your code easier to read. (This is true of final, static, and static
+final fields too.)
 
 <a name="prefer_static" id="prefer_static"></a>
 <h2>Prefer Static Over Virtual</h2>
 
-<p>If you don't need to access an object's fields, make your method static.  It can
-be called faster, because it doesn't require a virtual method table
-indirection.  It's also good practice, because you can tell from the method
+<p>If you don't need to access an object's fields, make your method static.
+Invocations will be about 15%-20% faster.
+It's also good practice, because you can tell from the method
 signature that calling the method can't alter the object's state.</p>
 
 <a name="internal_get_set" id="internal_get_set"></a>
@@ -354,62 +309,14 @@
 in the public interface, but within a class you should always access
 fields directly.</p>
 
-<a name="cache_fields" id="cache_fields"></a>
-<h2>Cache Field Lookups</h2>
-
-<p>Accessing object fields is much slower than accessing local variables.
-Instead of writing:</p>
-<pre>for (int i = 0; i &lt; this.mCount; i++)
-      dumpItem(this.mItems[i]);</pre>
-
-<p>You should write:</p>
-<pre>  int count = this.mCount;
-  Item[] items = this.mItems;
- 
-  for (int i = 0; i &lt; count; i++)
-      dumpItems(items[i]);
-</pre>
-
-<p>(We're using an explicit "this" to make it clear that these are
-member variables.)</p>
-
-<p>A similar guideline is never call a method in the second clause of a "for"
-statement.  For example, the following code will execute the getCount() method
-once per iteration, which is a huge waste when you could have simply cached
-the value as an int:</p>
-
-<pre>for (int i = 0; i &lt; this.getCount(); i++)
-    dumpItems(this.getItem(i));
-</pre>
-
-<p>It's also usually a good idea to create a local variable if you're going to be
-accessing an instance field more than once.  For example:</p>
-
-<pre>
-    protected void drawHorizontalScrollBar(Canvas canvas, int width, int height) {
-        if (isHorizontalScrollBarEnabled()) {
-            int size = <strong>mScrollBar</strong>.getSize(<em>false</em>);
-            if (size &lt;= 0) {
-                size = mScrollBarSize;
-            }
-            <strong>mScrollBar</strong>.setBounds(0, <em>height</em> - size, width, height);
-            <strong>mScrollBar</strong>.setParams(
-                    computeHorizontalScrollRange(),
-                    computeHorizontalScrollOffset(),
-                    computeHorizontalScrollExtent(), <em>false</em>);
-            <strong>mScrollBar</strong>.draw(canvas);
-        }
-    }</pre>
-
-<p>That's four separate lookups of the member field <code>mScrollBar</code>.
-By caching mScrollBar in a local stack variable, the four member field lookups
-become four stack variable references, which are much more efficient.</p>
-
-<p>Incidentally, method arguments have the same performance characteristics
-as local variables.</p>
+<p>Without a JIT, direct field access is about 3x faster than invoking a
+trivial getter. With the JIT (where direct field access is as cheap as
+accessing a local), direct field access is about 7x faster than invoking a
+trivial getter. This is true in Froyo, but will improve in the future when
+the JIT inlines getter methods.</p>
 
 <a name="use_final" id="use_final"></a>
-<h2>Declare Constants Final</h2>
+<h2>Use Static Final For Constants</h2>
 
 <p>Consider the following declaration at the top of a class:</p>
 
@@ -429,39 +336,40 @@
 static final String strVal = "Hello, world!";</pre>
 
 <p>The class no longer requires a <code>&lt;clinit&gt;</code> method,
-because the constants go into classfile static field initializers, which are
-handled directly by the VM.  Code accessing <code>intVal</code> will use
+because the constants go into static field initializers in the dex file.
+Code that refers to <code>intVal</code> will use
 the integer value 42 directly, and accesses to <code>strVal</code> will
 use a relatively inexpensive "string constant" instruction instead of a
-field lookup.</p>
-
-<p>Declaring a method or class "final" does not confer any immediate
-performance benefits, but it does allow certain optimizations. For example, if
-the compiler knows that a "getter" method can't be overridden by a sub-class,
-it can inline the method call.</p>
-
-<p>You can also declare local variables final. However, this has no definitive
-performance benefits. For local variables, only use "final" if it makes the
-code clearer (or you have to, e.g. for use in an anonymous inner class).</p>
+field lookup. (Note that this optimization only applies to primitive types and
+<code>String</code> constants, not arbitrary reference types. Still, it's good
+practice to declare constants <code>static final</code> whenever possible.)</p>
 
 <a name="foreach" id="foreach"></a>
-<h2>Use Enhanced For Loop Syntax With Caution</h2>
+<h2>Use Enhanced For Loop Syntax</h2>
 
-<p>The enhanced for loop (also sometimes known as "for-each" loop) can be used for collections that implement the Iterable interface.
-With these objects, an iterator is allocated to make interface calls
-to hasNext() and next(). With an ArrayList, you're better off walking through
-it directly, but for other collections the enhanced for loop syntax will be equivalent
-to explicit iterator usage.</p>
+<p>The enhanced for loop (also sometimes known as "for-each" loop) can be used
+for collections that implement the Iterable interface and for arrays.
+With collections, an iterator is allocated to make interface calls
+to hasNext() and next(). With an ArrayList, a hand-written counted loop is
+about 3x faster (with or without JIT), but for other collections the enhanced
+for loop syntax will be exactly equivalent to explicit iterator usage.</p>
 
-<p>Nevertheless, the following code shows an acceptable use of the enhanced for loop:</p>
+<p>There are several alternatives for iterating through an array:</p>
 
 <pre>public class Foo {
     int mSplat;
-    static Foo mArray[] = new Foo[27];
+}
+public class ArrayBenchmark {
+    Foo[] mArray = new Foo[27];
+    {
+        for (int i = 0; i &lt; mArray.length; ++i) {
+            mArray[i] = new Foo();
+        }
+    }
 
     public static void zero() {
         int sum = 0;
-        for (int i = 0; i &lt; mArray.length; i++) {
+        for (int i = 0; i &lt; mArray.length; ++i) {
             sum += mArray[i].mSplat;
         }
     }
@@ -471,53 +379,51 @@
         Foo[] localArray = mArray;
         int len = localArray.length;
 
-        for (int i = 0; i &lt; len; i++) {
+        for (int i = 0; i &lt; len; ++i) {
             sum += localArray[i].mSplat;
         }
     }
 
     public static void two() {
         int sum = 0;
-        for (Foo a: mArray) {
+        for (Foo a : mArray) {
             sum += a.mSplat;
         }
     }
 }</pre>
 
-<p><strong>zero()</strong> retrieves the static field twice and gets the array
-length once for every iteration through the loop.</p>
+<p><strong>zero()</strong> is slowest, because the JIT can't yet optimize away
+the cost of getting the array length once for every iteration through the
+loop.</p>
 
-<p><strong>one()</strong> pulls everything out into local variables, avoiding
-the lookups.</p>
+<p><strong>one()</strong> is faster. It pulls everything out into local
+variables, avoiding the lookups. Only the array length offers a performance
+benefit.</p>
 
-<p><strong>two()</strong> uses the enhanced for loop syntax introduced in version 1.5 of
-the Java programming language. The code generated by the compiler takes care
-of copying the array reference and the array length to local variables, making
-it a good choice for walking through all elements of an array. It does
-generate an extra local load/store in the main loop (apparently preserving
-"a"), making it a teensy bit slower and 4 bytes longer than one().</p>
+<p><strong>two()</strong> is fastest for devices without a JIT, and
+indistinguishable from <strong>one()</strong> for devices with a JIT.
+It uses the enhanced for loop syntax introduced in version 1.5 of the Java
+programming language.</p>
 
-<p>To summarize all that a bit more clearly: enhanced for loop syntax performs well
-with arrays, but be cautious when using it with Iterable objects since there is
-additional object creation.</p>
+<p>To summarize: use the enhanced for loop by default, but consider a
+hand-written counted loop for performance-critical ArrayList iteration.</p>
+
+<p>(See also <em>Effective Java</em> item 46.)</p>
 
 <a name="avoid_enums" id="avoid_enums"></a>
-<h2>Avoid Enums</h2>
+<h2>Avoid Enums Where You Only Need Ints</h2>
 
 <p>Enums are very convenient, but unfortunately can be painful when size
 and speed matter.  For example, this:</p>
 
-<pre>public class Foo {
-   public enum Shrubbery { GROUND, CRAWLING, HANGING }
-}</pre>
+<pre>public enum Shrubbery { GROUND, CRAWLING, HANGING }</pre>
 
-<p>turns into a 900 byte .class file (Foo$Shrubbery.class). On first use, the
+<p>adds 740 bytes to your .dex file compared to the equivalent class
+with three public static final ints. On first use, the
 class initializer invokes the &lt;init&gt; method on objects representing each
 of the enumerated values. Each object gets its own static field, and the full
 set is stored in an array (a static field called "$VALUES"). That's a lot of
-code and data, just for three integers.</p>
-
-<p>This:</p>
+code and data, just for three integers. Additionally, this:</p>
 
 <pre>Shrubbery shrub = Shrubbery.GROUND;</pre>
 
@@ -529,34 +435,11 @@
 by all means use enums for public APIs, but try to avoid them when performance
 matters.</p>
 
-<p>In some circumstances it can be helpful to get enum integer values
-through the <code>ordinal()</code> method.  For example, replace:</p>
-
-<pre>for (int n = 0; n &lt; list.size(); n++) {
-    if (list.items[n].e == MyEnum.VAL_X)
-       // do stuff 1
-    else if (list.items[n].e == MyEnum.VAL_Y)
-       // do stuff 2
-}</pre>
-
-<p>with:</p>
-
-<pre>   int valX = MyEnum.VAL_X.ordinal();
-   int valY = MyEnum.VAL_Y.ordinal();
-   int count = list.size();
-   MyItem items = list.items();
-
-   for (int  n = 0; n &lt; count; n++)
-   {
-        int  valItem = items[n].e.ordinal();
-
-        if (valItem == valX)
-          // do stuff 1
-        else if (valItem == valY)
-          // do stuff 2
-   }</pre>
-
-<p>In some cases, this will be faster, though this is not guaranteed.</p>
+<p>If you're using <code>Enum.ordinal</code>, that's usually a sign that you
+should be using ints instead. As a rule of thumb, if an enum doesn't have a
+constructor and doesn't define its own methods, and it's used in
+performance-critical code, you should consider <code>static final int</code>
+constants instead.</p>
 
 <a name="package_inner" id="package_inner"></a>
 <h2>Use Package Scope with Inner Classes</h2>
@@ -588,10 +471,11 @@
 in the outer class.  This is legal, and the code prints "Value is 27" as
 expected.</p>
 
-<p>The problem is that Foo$Inner is technically (behind the scenes) a totally
-separate class, which makes direct access to Foo's private
-members illegal.  To bridge that gap, the compiler generates a
-couple of synthetic methods:</p>
+<p>The problem is that the VM considers direct access to Foo's private members
+from Foo$Inner to be illegal because Foo and Foo$Inner are different classes,
+even though the Java language allows an inner class to access an outer class'
+private members. To bridge the gap, the compiler generates a couple of
+synthetic methods:</p>
 
 <pre>/*package*/ static int Foo.access$100(Foo foo) {
     return foo.mValue;
@@ -612,31 +496,53 @@
 by inner classes to have package scope, rather than private scope.
 This runs faster and removes the overhead of the generated methods.
 (Unfortunately it also means the fields could be accessed directly by other
-classes in the same package, which runs counter to the standard OO
+classes in the same package, which runs counter to the standard
 practice of making all fields private. Once again, if you're
 designing a public API you might want to carefully consider using this
 optimization.)</p>
 
 <a name="avoidfloat" id="avoidfloat"></a>
-<h2>Avoid Float</h2>
+<h2>Use Floating-Point Judiciously</h2>
 
-<p>Before the release of the Pentium CPU, it was common for game authors to do
-as much as possible with integer math. With the Pentium, the floating point
-math co-processor became a built-in feature, and by interleaving integer and
-floating-point operations your game would actually go faster than it would
-with purely integer math. The common practice on desktop systems is to use
-floating point freely.</p>
+<p>As a rule of thumb, floating-point is about 2x slower than integer on
+Android devices. This is true on a FPU-less, JIT-less G1 and a Nexus One with
+an FPU and the JIT. (Of course, absolute speed difference between those two
+devices is about 10x for arithmetic operations.)</p>
 
-<p>Unfortunately, embedded processors frequently do not have hardware floating
-point support, so all operations on "float" and "double" are performed in
-software. Some basic floating point operations can take on the order of a
-millisecond to complete.</p>
+<p>In speed terms, there's no difference between <code>float</code> and
+<code>double</code> on the more modern hardware. Space-wise, <code>double</code>
+is 2x larger. As with desktop machines, assuming space isn't an issue, you
+should prefer <code>double</code> to <code>float</code>.</p>
 
 <p>Also, even for integers, some chips have hardware multiply but lack
 hardware divide. In such cases, integer division and modulus operations are
 performed in software &mdash; something to think about if you're designing a
 hash table or doing lots of math.</p>
 
+<a name="library" id="library"></a>
+<h2>Know And Use The Libraries</h2>
+
+<p>In addition to all the usual reasons to prefer library code over rolling
+your own, bear in mind that the system is at liberty to replace calls
+to library methods with hand-coded assembler, which may be better than the
+best code the JIT can produce for the equivalent Java. The typical example
+here is <code>String.indexOf</code> and friends, which Dalvik replaces with
+an inlined intrinsic. Similarly, the <code>System.arraycopy</code> method
+is about 9x faster than a hand-coded loop on a Nexus One with the JIT.</p>
+
+<p>(See also <em>Effective Java</em> item 47.)</p>
+
+<a name="native_methods" id="native_methods"></a>
+<h2>Use Native Methods Judiciously</h2>
+
+<p>Native code isn't necessarily more efficient than Java. There's a cost
+associated with the Java-native transition, it can be significantly more
+difficult to arrange timely collection of your native resources, and you
+need to compile your code for each architecture you wish to run on (rather
+than rely on it having a JIT).</p>
+
+<p>(See also <em>Effective Java</em> item 54.)</p>
+
 <a name="samples" id="samples"></a>
 <h2>Some Sample Performance Numbers</h2>
 
@@ -714,11 +620,6 @@
 <a name="closing_notes" id="closing_notes"></a>
 <h2>Closing Notes</h2>
 
-<p>The best way to write good, efficient code for embedded systems is to
-understand what the code you write really does. If you really want to allocate
-an iterator, by all means use enhanced for loop syntax on a List; just make it a
-deliberate choice, not an inadvertent side effect.</p>
-
-<p>Forewarned is forearmed!  Know what you're getting into!  Insert your
-favorite maxim here, but always think carefully about what your code is doing,
-and be on the lookout for ways to speed it up.</p>
+<p>One last thing: always measure. Before you start optimizing, make sure you
+have a problem. Make sure you can accurately measure your existing performance,
+or you won't be able to measure the benefit of the alternatives you try.</p>
diff --git a/graphics/java/android/graphics/AvoidXfermode.java b/graphics/java/android/graphics/AvoidXfermode.java
index 2ed042b..7e2722d 100644
--- a/graphics/java/android/graphics/AvoidXfermode.java
+++ b/graphics/java/android/graphics/AvoidXfermode.java
@@ -38,15 +38,15 @@
      *
      * There are two modes, and each mode interprets a tolerance value.
      *
-     * AVOID: In this mode, drawing is allowed only on destination pixels that
+     * Avoid: In this mode, drawing is allowed only on destination pixels that
      * are different from the op-color.
-     *   Tolerance near 0: avoid anything close to the op-color
-     *   Tolerance near 255: avoid only colors very close to the op-color
-     *
-     * TARGET: In this mode, drawing only occurs on destination pixels that
+     * Tolerance near 0: avoid any colors even remotely similar to the op-color
+     * Tolerance near 255: avoid only colors nearly identical to the op-color
+     
+     * Target: In this mode, drawing only occurs on destination pixels that
      * are similar to the op-color
-     *   Tolerance near 0: draw on colors that are very close to op-color
-     *   Tolerance near 255: draw on colors that  to the op-color
+     * Tolerance near 0: draw only on colors that are nearly identical to the op-color
+     * Tolerance near 255: draw on any colors even remotely similar to the op-color
      */
     public AvoidXfermode(int opColor, int tolerance, Mode mode) {
         if (tolerance < 0 || tolerance > 255) {
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
new file mode 100644
index 0000000..f126374
--- /dev/null
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -0,0 +1,76 @@
+/*
+ * 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;
+
+public class ImageFormat
+{
+    /* these constants are chosen to be binary compatible with
+     * their previous location in PixelFormat.java */
+    
+    public static final int UNKNOWN = 0;
+
+    /** RGB format used for pictures encoded as RGB_565   
+     *  see {@link android.hardware.Camera.Parameters#setPictureFormat(int)}.
+     */
+    public static final int RGB_565 = 4;
+
+    /**
+     * YCbCr formats, used for video. These are not necessarily supported
+     * by the hardware.
+     */
+    public static final int NV16 = 0x10;
+
+    
+    /** YCrCb format used for images, which uses the NV21 encoding format.   
+     *  This is the default format for camera preview images, when not
+     *  otherwise set with 
+     *  {@link android.hardware.Camera.Parameters#setPreviewFormat(int)}.
+     */
+    public static final int NV21 = 0x11;
+
+
+    /** YCbCr format used for images, which uses YUYV (YUY2) encoding format.
+     *  This is an alternative format for camera preview images. Whether this
+     *  format is supported by the camera hardware can be determined by
+     *  {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}.
+     */
+    public static final int YUY2 = 0x14;
+
+    
+    /**
+     * Encoded formats.  These are not necessarily supported by the hardware.
+     */
+    public static final int JPEG = 0x100;
+
+
+    /**
+     * Use this function to retrieve the number of bits per pixel of
+     * an ImageFormat.
+     * @param format
+     * @return the number of bits per pixel of the given format or -1 if the
+     * format doesn't exist or is not supported.
+     */
+    public static int getBitsPerPixel(int format) {
+        switch (format) {
+            case RGB_565:   return 16;
+            case NV16:      return 16;
+            case NV21:      return 12;
+            case YUY2:      return 16;
+        }
+        return -1;
+    }
+}
diff --git a/graphics/java/android/graphics/PixelFormat.java b/graphics/java/android/graphics/PixelFormat.java
index c76cee7..182f14d 100644
--- a/graphics/java/android/graphics/PixelFormat.java
+++ b/graphics/java/android/graphics/PixelFormat.java
@@ -18,8 +18,7 @@
 
 public class PixelFormat
 {
-    /* these constants need to match those
-       in ui/PixelFormat.h & pixelflinger/format.h */
+    /* these constants need to match those in hardware/hardware.h */
     
     public static final int UNKNOWN     = 0;
 
@@ -46,30 +45,34 @@
     public static final int L_8         = 9;
     public static final int LA_88       = 0xA;
     public static final int RGB_332     = 0xB;
-    
+
+
     /**
-     * YCbCr formats, used for video. These are not necessarily supported
-     * by the hardware.
+     * @deprecated use {@link android.graphics.ImageFormat#NV16 
+     * ImageFormat.NV16} instead.
      */
+    @Deprecated
     public static final int YCbCr_422_SP= 0x10;
 
-    /** YCbCr format used for images, which uses the NV21 encoding format.   
-     *  This is the default format for camera preview images, when not
-     *  otherwise set with 
-     *  {@link android.hardware.Camera.Parameters#setPreviewFormat(int)}.
+    /**
+     * @deprecated use {@link android.graphics.ImageFormat#NV21 
+     * ImageFormat.NV21} instead.
      */
+    @Deprecated
     public static final int YCbCr_420_SP= 0x11;
 
-    /** YCbCr format used for images, which uses YUYV (YUY2) encoding format.
-     *  This is an alternative format for camera preview images. Whether this
-     *  format is supported by the camera hardware can be determined by
-     *  {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}.
+    /**
+     * @deprecated use {@link android.graphics.ImageFormat#YUY2 
+     * ImageFormat.YUY2} instead.
      */
+    @Deprecated
     public static final int YCbCr_422_I = 0x14;
 
     /**
-     * Encoded formats.  These are not necessarily supported by the hardware.
+     * @deprecated use {@link android.graphics.ImageFormat#JPEG 
+     * ImageFormat.JPEG} instead.
      */
+    @Deprecated
     public static final int JPEG        = 0x100;
 
     /*
diff --git a/graphics/java/android/graphics/YuvImage.java b/graphics/java/android/graphics/YuvImage.java
index 5a4531b..9368da6 100644
--- a/graphics/java/android/graphics/YuvImage.java
+++ b/graphics/java/android/graphics/YuvImage.java
@@ -22,7 +22,7 @@
  * 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.
- * Currently only PixelFormat.YCbCr_420_SP and PixelFormat.YCbCr_422_I are supported.
+ * Currently only ImageFormat.NV21 and ImageFormat.YUY2 are supported.
  *
  * To compress a rectangle region in the YUV data, users have to specify the
  * region by left, top, width and height.
@@ -77,11 +77,11 @@
      *                null.
      */
     public YuvImage(byte[] yuv, int format, int width, int height, int[] strides) {
-        if (format != PixelFormat.YCbCr_420_SP &&
-                format != PixelFormat.YCbCr_422_I) {
+        if (format != ImageFormat.NV21 &&
+                format != ImageFormat.YUY2) {
             throw new IllegalArgumentException(
-                    "only support PixelFormat.YCbCr_420_SP " +
-                    "and PixelFormat.YCbCr_422_I for now");
+                    "only support ImageFormat.NV21 " +
+                    "and ImageFormat.YUY2 for now");
         }
 
         if (width <= 0  || height <= 0) {
@@ -107,7 +107,7 @@
 
     /**
      * Compress a rectangle region in the YuvImage to a jpeg.
-     * Only PixelFormat.YCbCr_420_SP and PixelFormat.YCbCr_422_I
+     * Only ImageFormat.NV21 and ImageFormat.YUY2
      * are supported for now.
      *
      * @param rectangle The rectangle region to be compressed. The medthod checks if rectangle is
@@ -181,14 +181,14 @@
 
     int[] calculateOffsets(int left, int top) {
         int[] offsets = null;
-        if (mFormat == PixelFormat.YCbCr_420_SP) {
+        if (mFormat == ImageFormat.NV21) {
             offsets = new int[] {top * mStrides[0] + left,
                   mHeight * mStrides[0] + top / 2 * mStrides[1]
                   + left / 2 * 2 };
             return offsets;
         }
 
-        if (mFormat == PixelFormat.YCbCr_422_I) {
+        if (mFormat == ImageFormat.YUY2) {
             offsets = new int[] {top * mStrides[0] + left / 2 * 4};
             return offsets;
         }
@@ -198,12 +198,12 @@
 
     private int[] calculateStrides(int width, int format) {
         int[] strides = null;
-        if (format == PixelFormat.YCbCr_420_SP) {
+        if (format == ImageFormat.NV21) {
             strides = new int[] {width, width};
             return strides;
         }
 
-        if (format == PixelFormat.YCbCr_422_I) {
+        if (format == ImageFormat.YUY2) {
             strides = new int[] {width * 2};
             return strides;
         }
@@ -214,7 +214,7 @@
    private void adjustRectangle(Rect rect) {
        int width = rect.width();
        int height = rect.height();
-       if (mFormat == PixelFormat.YCbCr_420_SP) {
+       if (mFormat == ImageFormat.NV21) {
            // Make sure left, top, width and height are all even.
            width &= ~1;
            height &= ~1;
@@ -224,7 +224,7 @@
            rect.bottom = rect.top + height;
         }
 
-        if (mFormat == PixelFormat.YCbCr_422_I) {
+        if (mFormat == ImageFormat.YUY2) {
             // Make sure left and width are both even.
             width &= ~1;
             rect.left &= ~1;
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index b1d588e..b94df84 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -238,7 +238,10 @@
             final int count = sets.length;
             mStateListState.mStateSets = new int[count][];
             for (int i = 0; i < count; i++) {
-                mStateListState.mStateSets[i] = sets[i].clone();
+                final int[] set = sets[i];
+                if (set != null) {
+                    mStateListState.mStateSets[i] = set.clone();
+                }
             }
             mMutated = true;
         }
diff --git a/include/ui/Region.h b/include/ui/Region.h
index 2bcad5b..925fd06 100644
--- a/include/ui/Region.h
+++ b/include/ui/Region.h
@@ -21,7 +21,6 @@
 #include <sys/types.h>
 
 #include <utils/Vector.h>
-#include <binder/Parcel.h>
 
 #include <ui/Rect.h>
 
@@ -39,7 +38,6 @@
                         Region();
                         Region(const Region& rhs);
     explicit            Region(const Rect& rhs);
-    explicit            Region(const Parcel& parcel);
     explicit            Region(const void* buffer);
                         ~Region();
                         
@@ -118,10 +116,6 @@
             // be sorted in Y and X and must not make the region invalid.
             void        addRectUnchecked(int l, int t, int r, int b);
 
-            // flatten/unflatten a region to/from a Parcel
-            status_t    write(Parcel& parcel) const;
-            status_t    read(const Parcel& parcel);
-
             // flatten/unflatten a region to/from a raw buffer
             ssize_t     write(void* buffer, size_t size) const;
     static  ssize_t     writeEmpty(void* buffer, size_t size);
diff --git a/libs/rs/java/Fountain/AndroidManifest.xml b/libs/rs/java/Fountain/AndroidManifest.xml
index 1185930..951c451 100644
--- a/libs/rs/java/Fountain/AndroidManifest.xml
+++ b/libs/rs/java/Fountain/AndroidManifest.xml
@@ -1,7 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.fountain">
-    <application android:label="Fountain">
+    <application 
+        android:label="Fountain"
+        android:icon="@drawable/test_pattern">
         <activity android:name="Fountain">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/libs/rs/java/Fountain/res/drawable/test_pattern.png b/libs/rs/java/Fountain/res/drawable/test_pattern.png
new file mode 100644
index 0000000..e7d1455
--- /dev/null
+++ b/libs/rs/java/Fountain/res/drawable/test_pattern.png
Binary files differ
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index 207ad15..6288bc4 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -34,6 +34,12 @@
 
 Element::~Element()
 {
+    for (uint32_t ct = 0; ct < mRSC->mStateElement.mElements.size(); ct++) {
+        if (mRSC->mStateElement.mElements[ct] == this) {
+            mRSC->mStateElement.mElements.removeAt(ct);
+            break;
+        }
+    }
     clear();
 }
 
@@ -78,27 +84,62 @@
 }
 
 
-Element * Element::create(Context *rsc, RsDataType dt, RsDataKind dk,
+const Element * Element::create(Context *rsc, RsDataType dt, RsDataKind dk,
                             bool isNorm, uint32_t vecSize)
 {
+    // Look for an existing match.
+    for (uint32_t ct=0; ct < rsc->mStateElement.mElements.size(); ct++) {
+        const Element *ee = rsc->mStateElement.mElements[ct];
+        if (!ee->getFieldCount() &&
+            (ee->getComponent().getType() == dt) &&
+            (ee->getComponent().getKind() == dk) &&
+            (ee->getComponent().getIsNormalized() == isNorm) &&
+            (ee->getComponent().getVectorSize() == vecSize)) {
+            // Match
+            ee->incUserRef();
+            return ee;
+        }
+    }
+
     Element *e = new Element(rsc);
     e->mComponent.set(dt, dk, isNorm, vecSize);
     e->mBits = e->mComponent.getBits();
+    rsc->mStateElement.mElements.push(e);
     return e;
 }
 
-Element * Element::create(Context *rsc, size_t count, const Element **ein,
+const Element * Element::create(Context *rsc, size_t count, const Element **ein,
                             const char **nin, const size_t * lengths)
 {
+    // Look for an existing match.
+    for (uint32_t ct=0; ct < rsc->mStateElement.mElements.size(); ct++) {
+        const Element *ee = rsc->mStateElement.mElements[ct];
+        if (ee->getFieldCount() == count) {
+            bool match = true;
+            for (uint32_t i=0; i < count; i++) {
+                if ((ee->mFields[i].e.get() != ein[i]) ||
+                    (ee->mFields[i].name.length() != lengths[i]) ||
+                    (ee->mFields[i].name != nin[i])) {
+                    match = false;
+                    break;
+                }
+            }
+            if (match) {
+                ee->incUserRef();
+                return ee;
+            }
+        }
+    }
+
     Element *e = new Element(rsc);
     e->mFields = new ElementField_t [count];
     e->mFieldCount = count;
-
     for (size_t ct=0; ct < count; ct++) {
         e->mFields[ct].e.set(ein[ct]);
         e->mFields[ct].name.setTo(nin[ct], lengths[ct]);
     }
 
+    rsc->mStateElement.mElements.push(e);
     return e;
 }
 
@@ -168,6 +209,7 @@
 
 ElementState::~ElementState()
 {
+    rsAssert(!mElements.size());
 }
 
 
@@ -184,9 +226,9 @@
                             uint32_t vecSize)
 {
     //LOGE("rsi_ElementCreate %i %i %i %i", dt, dk, norm, vecSize);
-    Element *e = Element::create(rsc, dt, dk, norm, vecSize);
+    const Element *e = Element::create(rsc, dt, dk, norm, vecSize);
     e->incUserRef();
-    return e;
+    return (RsElement)e;
 }
 
 RsElement rsi_ElementCreate2(Context *rsc,
@@ -196,9 +238,9 @@
                              const size_t * nameLengths)
 {
     //LOGE("rsi_ElementCreate2 %i", count);
-    Element *e = Element::create(rsc, count, (const Element **)ein, names, nameLengths);
+    const Element *e = Element::create(rsc, count, (const Element **)ein, names, nameLengths);
     e->incUserRef();
-    return e;
+    return (RsElement)e;
 }
 
 
diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h
index 777e8ee..02a1ca2 100644
--- a/libs/rs/rsElement.h
+++ b/libs/rs/rsElement.h
@@ -60,9 +60,9 @@
 
     void dumpLOGV(const char *prefix) const;
 
-    static Element * create(Context *rsc, RsDataType dt, RsDataKind dk,
+    static const Element * create(Context *rsc, RsDataType dt, RsDataKind dk,
                             bool isNorm, uint32_t vecSize);
-    static Element * create(Context *rsc, size_t count, const Element **,
+    static const Element * create(Context *rsc, size_t count, const Element **,
                             const char **, const size_t * lengths);
 
 protected:
@@ -89,6 +89,8 @@
     ElementState();
     ~ElementState();
 
+    // Cache of all existing elements.
+    Vector<const Element *> mElements;
 };
 
 
diff --git a/libs/rs/rsObjectBase.cpp b/libs/rs/rsObjectBase.cpp
index 89c5b00..677413e 100644
--- a/libs/rs/rsObjectBase.cpp
+++ b/libs/rs/rsObjectBase.cpp
@@ -191,6 +191,7 @@
     LOGV("Dumping all objects");
     const ObjectBase * o = rsc->mObjHead;
     while (o) {
+        LOGV(" Object %p", o);
         o->dumpLOGV("  ");
         o = o->mNext;
     }
diff --git a/libs/rs/rsObjectBase.h b/libs/rs/rsObjectBase.h
index f247022..bb03b87 100644
--- a/libs/rs/rsObjectBase.h
+++ b/libs/rs/rsObjectBase.h
@@ -56,6 +56,7 @@
 protected:
     const char *mAllocFile;
     uint32_t mAllocLine;
+    Context *mRSC;
 
 private:
     void add() const;
@@ -64,7 +65,6 @@
     bool checkDelete() const;
 
     char * mName;
-    Context *mRSC;
     mutable int32_t mSysRefCount;
     mutable int32_t mUserRefCount;
 
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index 28f13d4..a2b2df4 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -364,7 +364,7 @@
 
 void ProgramVertexState::init(Context *rsc, int32_t w, int32_t h)
 {
-    RsElement e = Element::create(rsc, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
+    RsElement e = (RsElement) Element::create(rsc, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
 
     rsi_TypeBegin(rsc, e);
     rsi_TypeAdd(rsc, RS_DIMENSION_X, 48);
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index 22a267a..9d24c6c 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -31,6 +31,12 @@
 
 Type::~Type()
 {
+    for (uint32_t ct = 0; ct < mRSC->mStateType.mTypes.size(); ct++) {
+        if (mRSC->mStateType.mTypes[ct] == this) {
+            mRSC->mStateType.mTypes.removeAt(ct);
+            break;
+        }
+    }
     if (mLODs) {
         delete [] mLODs;
     }
@@ -341,6 +347,18 @@
 {
     TypeState * stc = &rsc->mStateType;
 
+    for (uint32_t ct=0; ct < stc->mTypes.size(); ct++) {
+        Type *t = stc->mTypes[ct];
+        if (t->getElement() != stc->mElement.get()) continue;
+        if (t->getDimX() != stc->mX) continue;
+        if (t->getDimY() != stc->mY) continue;
+        if (t->getDimZ() != stc->mZ) continue;
+        if (t->getDimLOD() != stc->mLOD) continue;
+        if (t->getDimFaces() != stc->mFaces) continue;
+        t->incUserRef();
+        return t;
+    }
+
     Type * st = new Type(rsc);
     st->incUserRef();
     st->setDimX(stc->mX);
@@ -351,7 +369,7 @@
     st->setDimFaces(stc->mFaces);
     st->compute();
     stc->mElement.clear();
-
+    stc->mTypes.push(st);
     return st;
 }
 
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
index 4fa4933..28e6274 100644
--- a/libs/rs/rsType.h
+++ b/libs/rs/rsType.h
@@ -137,6 +137,10 @@
     uint32_t mLOD;
     bool mFaces;
     ObjectBaseRef<const Element> mElement;
+
+
+    // Cache of all existing types.
+    Vector<Type *> mTypes;
 };
 
 
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index 5b96e9d..a3d293f 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -52,6 +52,7 @@
       mTransformed(false),
       mUseLinearFiltering(false),
       mOrientation(0),
+      mLeft(0), mTop(0),
       mTransactionFlags(0),
       mPremultipliedAlpha(true),
       mInvalidate(0)
diff --git a/libs/surfaceflinger_client/LayerState.cpp b/libs/surfaceflinger_client/LayerState.cpp
index 114a9e9..01c4c7e 100644
--- a/libs/surfaceflinger_client/LayerState.cpp
+++ b/libs/surfaceflinger_client/LayerState.cpp
@@ -22,17 +22,37 @@
 
 status_t layer_state_t::write(Parcel& output) const
 {
+    status_t err;
+
+    size_t len = transparentRegion.write(NULL, 0);
+    err = output.writeInt32(len);
+    if (err < NO_ERROR) return err;
+
+    void* buf = output.writeInplace(len);
+    if (buf == NULL) return NO_MEMORY;
+
+    err = transparentRegion.write(buf, len);
+    if (err < NO_ERROR) return err;
+
+    // NOTE: regions are at the end of the structure
     size_t size = sizeof(layer_state_t);
-    transparentRegion.write(output);
     size -= sizeof(transparentRegion);
-    output.write(this, size);
-    return NO_ERROR;
+    err = output.write(this, size);
+    return err;
 }
 
 status_t layer_state_t::read(const Parcel& input)
 {
+    status_t err;
+    size_t len = input.readInt32();
+    void const* buf = input.readInplace(len);
+    if (buf == NULL) return NO_MEMORY;
+
+    err = transparentRegion.read(buf);
+    if (err < NO_ERROR) return err;
+
+    // NOTE: regions are at the end of the structure
     size_t size = sizeof(layer_state_t);
-    transparentRegion.read(input);
     size -= sizeof(transparentRegion);
     input.read(this, size);
     return NO_ERROR;
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index d21ed57..12db908 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -63,16 +63,10 @@
 {
 }
 
-Region::Region(const Parcel& parcel)
-{
-    status_t err = read(parcel);
-    LOGE_IF(err<0, "error %s reading Region from parcel", strerror(err));
-}
-
 Region::Region(const void* buffer)
 {
     status_t err = read(buffer);
-    LOGE_IF(err<0, "error %s reading Region from parcel", strerror(err));
+    LOGE_IF(err<0, "error %s reading Region from buffer", strerror(err));
 }
 
 Region::~Region()
@@ -532,37 +526,6 @@
 
 // ----------------------------------------------------------------------------
 
-status_t Region::write(Parcel& parcel) const
-{
-#if VALIDATE_REGIONS
-    validate(*this, "write(Parcel)");
-#endif
-    status_t err;
-    const size_t count = mStorage.size();
-    const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
-    void* buffer = parcel.writeInplace(sizeNeeded);
-    if (!buffer) return NO_MEMORY;
-    ssize_t written = Region::write(buffer, sizeNeeded);
-    if (written < 0) return status_t(written);
-    return NO_ERROR;
-}
-
-status_t Region::read(const Parcel& parcel)
-{
-    void const* buffer = parcel.readInplace(sizeof(int32_t));
-    if (!buffer) return NO_MEMORY;
-    const size_t count = *static_cast<int32_t const *>(buffer);
-    void const* dummy = parcel.readInplace((1+count)*sizeof(Rect));
-    if (!dummy) return NO_MEMORY;
-    const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
-    const ssize_t read = Region::read(buffer);
-    if (read < 0) return status_t(read);
-#if VALIDATE_REGIONS
-    validate(*this, "read(Parcel)");
-#endif
-    return NO_ERROR;
-}
-
 ssize_t Region::write(void* buffer, size_t size) const
 {
 #if VALIDATE_REGIONS
@@ -570,12 +533,14 @@
 #endif
     const size_t count = mStorage.size();
     const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
-    if (sizeNeeded > size) return NO_MEMORY;
-    int32_t* const p = static_cast<int32_t*>(buffer); 
-    *p = count;
-    memcpy(p+1, &mBounds, sizeof(Rect));
-    if (count) {
-        memcpy(p+5, mStorage.array(), count*sizeof(Rect));
+    if (buffer != NULL) {
+        if (sizeNeeded > size) return NO_MEMORY;
+        int32_t* const p = static_cast<int32_t*>(buffer);
+        *p = count;
+        memcpy(p+1, &mBounds, sizeof(Rect));
+        if (count) {
+            memcpy(p+5, mStorage.array(), count*sizeof(Rect));
+        }
     }
     return ssize_t(sizeNeeded);
 }
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 8c24ee1..2c0399e 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -59,8 +59,10 @@
 
     Location getLastKnownLocation(String provider);
 
-    /* used by location providers to tell the location manager when it has a new location */
-    void reportLocation(in Location location);
+    // Used by location providers to tell the location manager when it has a new location.
+    // Passive is true if the location is coming from the passive provider, in which case
+    // it need not be shared with other providers.
+    void reportLocation(in Location location, boolean passive);
 
     String getFromLocation(double latitude, double longitude, int maxResults,
         in GeocoderParams params, out List<Address> addrs);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 9027fc2..da760a1 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -81,6 +81,19 @@
     public static final String GPS_PROVIDER = "gps";
 
     /**
+     * A special location provider for receiving locations without actually initiating
+     * a location fix. This provider can be used to passively receive location updates
+     * when other applications or services request them without actually requesting
+     * the locations yourself.  This provider will return locations generated by other
+     * providers.  You can query the {@link Location#getProvider()} method to determine
+     * the origin of the location update.
+     *
+     * Requires the permission android.permission.ACCESS_FINE_LOCATION, although if the GPS
+     * is not enabled this provider might only return coarse fixes.
+     */
+    public static final String PASSIVE_PROVIDER = "passive";
+
+    /**
      * Key used for the Bundle extra holding a boolean indicating whether
      * a proximity alert is entering (true) or exiting (false)..
      */
diff --git a/location/java/android/location/LocationProvider.java b/location/java/android/location/LocationProvider.java
index 3faba58..bb3e2a5 100644
--- a/location/java/android/location/LocationProvider.java
+++ b/location/java/android/location/LocationProvider.java
@@ -71,6 +71,10 @@
      * false otherwise.
      */
     public boolean meetsCriteria(Criteria criteria) {
+        // We do not want to match the special passive provider based on criteria.
+        if (LocationManager.PASSIVE_PROVIDER.equals(mName)) {
+            return false;
+        }
         if ((criteria.getAccuracy() != Criteria.NO_REQUIREMENT) && 
             (criteria.getAccuracy() < getAccuracy())) {
             return false;
diff --git a/location/java/android/location/provider/LocationProvider.java b/location/java/android/location/provider/LocationProvider.java
index 0d028c0..4163def 100644
--- a/location/java/android/location/provider/LocationProvider.java
+++ b/location/java/android/location/provider/LocationProvider.java
@@ -156,7 +156,7 @@
      */
     public void reportLocation(Location location) {
         try {
-            mLocationManager.reportLocation(location);
+            mLocationManager.reportLocation(location, false);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in reportLocation: ", e);
         }
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index dce3b27..8e84106 100755
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -863,7 +863,7 @@
             }
 
             try {
-                mLocationManager.reportLocation(mLocation);
+                mLocationManager.reportLocation(mLocation, false);
             } catch (RemoteException e) {
                 Log.e(TAG, "RemoteException calling reportLocation");
             }
diff --git a/location/java/com/android/internal/location/MockProvider.java b/location/java/com/android/internal/location/MockProvider.java
index 2f6fdee..bc1893e 100644
--- a/location/java/com/android/internal/location/MockProvider.java
+++ b/location/java/com/android/internal/location/MockProvider.java
@@ -143,7 +143,7 @@
         mLocation.set(l);
         mHasLocation = true;
         try {
-            mLocationManager.reportLocation(mLocation);
+            mLocationManager.reportLocation(mLocation, false);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException calling reportLocation");
         }
diff --git a/location/java/com/android/internal/location/PassiveProvider.java b/location/java/com/android/internal/location/PassiveProvider.java
new file mode 100644
index 0000000..7eb711d
--- /dev/null
+++ b/location/java/com/android/internal/location/PassiveProvider.java
@@ -0,0 +1,139 @@
+/*
+ * 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.internal.location;
+
+import android.location.ILocationManager;
+import android.location.Location;
+import android.location.LocationManager;
+import android.location.LocationProvider;
+import android.location.LocationProviderInterface;
+import android.net.NetworkInfo;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * A passive location provider reports locations received from other providers
+ * for clients that want to listen passively without actually triggering
+ * location updates.
+ *
+ * {@hide}
+ */
+public class PassiveProvider implements LocationProviderInterface {
+
+    private static final String TAG = "PassiveProvider";
+
+    private final ILocationManager mLocationManager;
+    private boolean mTracking;
+
+    public PassiveProvider(ILocationManager locationManager) {
+        mLocationManager = locationManager;
+    }
+
+    public String getName() {
+        return LocationManager.PASSIVE_PROVIDER;
+    }
+
+    public boolean requiresNetwork() {
+        return false;
+    }
+
+    public boolean requiresSatellite() {
+        return false;
+    }
+
+    public boolean requiresCell() {
+        return false;
+    }
+
+    public boolean hasMonetaryCost() {
+        return false;
+    }
+
+    public boolean supportsAltitude() {
+        return false;
+    }
+
+    public boolean supportsSpeed() {
+        return false;
+    }
+
+    public boolean supportsBearing() {
+        return false;
+    }
+
+    public int getPowerRequirement() {
+        return -1;
+    }
+
+    public int getAccuracy() {
+        return -1;
+    }
+
+    public boolean isEnabled() {
+        return true;
+    }
+
+    public void enable() {
+    }
+
+    public void disable() {
+    }
+
+    public int getStatus(Bundle extras) {
+        if (mTracking) {
+            return LocationProvider.AVAILABLE;
+        } else {
+            return LocationProvider.TEMPORARILY_UNAVAILABLE;
+        }
+    }
+
+    public long getStatusUpdateTime() {
+        return -1;
+    }
+
+    public void enableLocationTracking(boolean enable) {
+        mTracking = enable;
+    }
+
+    public void setMinTime(long minTime) {
+    }
+
+    public void updateNetworkState(int state, NetworkInfo info) {
+    }
+
+    public void updateLocation(Location location) {
+        if (mTracking) {
+            try {
+                // pass the location back to the location manager
+                mLocationManager.reportLocation(location, true);
+            } catch (RemoteException e) {
+                Log.e(TAG, "RemoteException calling reportLocation");
+            }
+        }
+    }
+
+    public boolean sendExtraCommand(String command, Bundle extras) {
+        return false;
+    }
+
+    public void addListener(int uid) {
+    }
+
+    public void removeListener(int uid) {
+    }
+}
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 34252ab..1f02608 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -500,22 +500,6 @@
             doScanFile(path, mimeType, lastModified, fileSize, false);
         }
 
-        private boolean isMetadataSupported(int fileType) {
-            if (mFileType == MediaFile.FILE_TYPE_MP3 ||
-                    mFileType == MediaFile.FILE_TYPE_MP4 ||
-                    mFileType == MediaFile.FILE_TYPE_M4A ||
-                    mFileType == MediaFile.FILE_TYPE_3GPP ||
-                    mFileType == MediaFile.FILE_TYPE_3GPP2 ||
-                    mFileType == MediaFile.FILE_TYPE_OGG ||
-                    mFileType == MediaFile.FILE_TYPE_AAC ||
-                    mFileType == MediaFile.FILE_TYPE_MID ||
-                    mFileType == MediaFile.FILE_TYPE_WMA) {
-                // we only extract metadata from MP3, M4A, OGG, MID, AAC and WMA files.
-                // check MP4 files, to determine if they contain only audio.
-                return true;
-            }
-            return false;
-        }
         public Uri doScanFile(String path, String mimeType, long lastModified, long fileSize, boolean scanAlways) {
             Uri result = null;
 //            long t1 = System.currentTimeMillis();
@@ -531,10 +515,8 @@
                     boolean music = (lowpath.indexOf(MUSIC_DIR) > 0) ||
                         (!ringtones && !notifications && !alarms && !podcasts);
 
-                    if( isMetadataSupported(mFileType) ) {
+                    if (!MediaFile.isImageFileType(mFileType)) {
                         processFile(path, mimeType, this);
-                    } else if (MediaFile.isImageFileType(mFileType)) {
-                        // we used to compute the width and height but it's not worth it
                     }
 
                     result = endFile(entry, ringtones, notifications, alarms, music, podcasts);
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 62a4fe9..18ce5c1 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -327,8 +327,6 @@
      * iterates through all the active streams and pauses any that
      * are playing. It also sets a flag so that any streams that
      * are playing can be resumed by calling autoResume().
-     *
-     * @hide
      */
     public native final void autoPause();
 
@@ -337,8 +335,6 @@
      *
      * Automatically resumes all streams that were paused in previous
      * calls to autoPause().
-     *
-     * @hide
      */
     public native final void autoResume();
 
@@ -412,8 +408,6 @@
     /**
      * Interface definition for a callback to be invoked when all the
      * sounds are loaded.
-     *
-     * @hide
      */
     public interface OnLoadCompleteListener
     {
@@ -429,8 +423,6 @@
 
     /**
      * Sets the callback hook for the OnLoadCompleteListener.
-     *
-     * @hide
      */
     public void setOnLoadCompleteListener(OnLoadCompleteListener listener)
     {
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index f201667..43762e7 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -58,7 +58,7 @@
 
     int pathRemaining = PATH_MAX - pathLength;
     strcpy(pathBuffer, path);
-    if (pathBuffer[pathLength - 1] != '/') {
+    if (pathLength > 0 && pathBuffer[pathLength - 1]) {
         pathBuffer[pathLength] = '/';
         pathBuffer[pathLength + 1] = 0;
         --pathRemaining;
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index b4fc035..50dad33 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1614,6 +1614,8 @@
     size_t actualSize = (*me->mCallback)(
             me, buffer->raw, buffer->size, me->mCallbackCookie);
 
+    buffer->size = actualSize;
+
     if (actualSize > 0) {
         me->snoopWrite(buffer->raw, actualSize);
     }
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 071bb9e..2a65766 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -85,6 +85,8 @@
 
 ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
         LOCAL_LDLIBS += -lpthread -ldl
+        LOCAL_SHARED_LIBRARIES += libdvm
+        LOCAL_CPPFLAGS += -DANDROID_SIMULATOR
 endif
 
 ifneq ($(TARGET_SIMULATOR),true)
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 12d7ee2..7997cd6 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -99,13 +99,13 @@
                     : AudioSystem::CHANNEL_OUT_MONO,
                 8192, 0, &AudioCallback, this, 0);
 
-        if (mAudioTrack->initCheck() != OK) {
+        if ((err = mAudioTrack->initCheck()) != OK) {
             delete mAudioTrack;
             mAudioTrack = NULL;
 
             mSource->stop();
 
-            return mAudioTrack->initCheck();
+            return err;
         }
 
         mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 1c9f4fd..b3a73b0 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -178,7 +178,8 @@
 }
 
 AwesomePlayer::AwesomePlayer()
-    : mTimeSource(NULL),
+    : mQueueStarted(false),
+      mTimeSource(NULL),
       mVideoRendererIsPreview(false),
       mAudioPlayer(NULL),
       mFlags(0),
@@ -201,13 +202,13 @@
 
     mAudioStatusEventPending = false;
 
-    mQueue.start();
-
     reset();
 }
 
 AwesomePlayer::~AwesomePlayer() {
-    mQueue.stop();
+    if (mQueueStarted) {
+        mQueue.stop();
+    }
 
     reset();
 
@@ -401,6 +402,9 @@
 
 void AwesomePlayer::onBufferingUpdate() {
     Mutex::Autolock autoLock(mLock);
+    if (!mBufferingEventPending) {
+        return;
+    }
     mBufferingEventPending = false;
 
     if (mDurationUs >= 0) {
@@ -425,6 +429,9 @@
     // Posted whenever any stream finishes playing.
 
     Mutex::Autolock autoLock(mLock);
+    if (!mStreamDoneEventPending) {
+        return;
+    }
     mStreamDoneEventPending = false;
 
     if (mFlags & LOOPING) {
@@ -437,6 +444,8 @@
         notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
 
         pause_l();
+
+        mFlags |= AT_EOS;
     }
 }
 
@@ -511,6 +520,12 @@
 
     postBufferingEvent_l();
 
+    if (mFlags & AT_EOS) {
+        // Legacy behaviour, if a stream finishes playing and then
+        // is started again, we play from the start...
+        seekTo_l(0);
+    }
+
     return OK;
 }
 
@@ -645,6 +660,7 @@
 status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
     mSeeking = true;
     mSeekTimeUs = timeUs;
+    mFlags &= ~AT_EOS;
 
     seekAudioIfNecessary_l();
 
@@ -918,6 +934,12 @@
 
 void AwesomePlayer::onCheckAudioStatus() {
     Mutex::Autolock autoLock(mLock);
+    if (!mAudioStatusEventPending) {
+        // Event was dispatched and while we were blocking on the mutex,
+        // has already been cancelled.
+        return;
+    }
+
     mAudioStatusEventPending = false;
 
     if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
@@ -977,6 +999,11 @@
         return UNKNOWN_ERROR;  // async prepare already pending
     }
 
+    if (!mQueueStarted) {
+        mQueue.start();
+        mQueueStarted = true;
+    }
+
     mFlags |= PREPARING;
     mAsyncPrepareEvent = new AwesomeEvent(
             this, &AwesomePlayer::onPrepareAsyncEvent);
@@ -1077,7 +1104,7 @@
     state->mUriHeaders = mUriHeaders;
     state->mFileSource = mFileSource;
 
-    state->mFlags = mFlags & (PLAYING | LOOPING);
+    state->mFlags = mFlags & (PLAYING | LOOPING | AT_EOS);
     getPosition_l(&state->mPositionUs);
 
     if (mLastVideoBuffer) {
@@ -1138,7 +1165,7 @@
 
     seekTo_l(state->mPositionUs);
 
-    mFlags = state->mFlags & LOOPING;
+    mFlags = state->mFlags & (LOOPING | AT_EOS);
 
     if (state->mLastVideoFrame && mISurface != NULL) {
         mVideoRenderer =
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 75b7b6f..6cf7cff 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -102,7 +102,6 @@
     { MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" },
     { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
     { MEDIA_MIMETYPE_AUDIO_MPEG, "MP3Decoder" },
-    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" },
     { MEDIA_MIMETYPE_AUDIO_AMR_NB, "AMRNBDecoder" },
     { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" },
     { MEDIA_MIMETYPE_AUDIO_AMR_WB, "AMRWBDecoder" },
diff --git a/media/libstagefright/Prefetcher.cpp b/media/libstagefright/Prefetcher.cpp
index 76ca77b..363e121 100644
--- a/media/libstagefright/Prefetcher.cpp
+++ b/media/libstagefright/Prefetcher.cpp
@@ -337,24 +337,20 @@
 void PrefetchedSource::cacheMore() {
     MediaSource::ReadOptions options;
 
-    {
-        Mutex::Autolock autoLock(mLock);
+    Mutex::Autolock autoLock(mLock);
 
-        if (!mStarted) {
-            return;
-        }
+    if (!mStarted) {
+        return;
+    }
 
-        if (mSeekTimeUs >= 0) {
-            options.setSeekTo(mSeekTimeUs);
-            mSeekTimeUs = -1;
-        }
+    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();
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index d079e70..6307bc5 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -28,6 +28,10 @@
 
 #include <media/stagefright/MediaDebug.h>
 
+#ifdef ANDROID_SIMULATOR
+#include <jni.h>
+#endif
+
 namespace android {
 
 TimedEventQueue::TimedEventQueue()
@@ -183,8 +187,26 @@
 
 // static
 void *TimedEventQueue::ThreadWrapper(void *me) {
+
+#ifdef ANDROID_SIMULATOR
+    // The simulator runs everything as one process, so any
+    // Binder calls happen on this thread instead of a thread
+    // in another process. We therefore need to make sure that
+    // this thread can do calls into interpreted code.
+    // On the device this is not an issue because the remote
+    // thread will already be set up correctly for this.
+    JavaVM *vm;
+    int numvms;
+    JNI_GetCreatedJavaVMs(&vm, 1, &numvms);
+    JNIEnv *env;
+    vm->AttachCurrentThread(&env, NULL);
+#endif
+
     static_cast<TimedEventQueue *>(me)->threadEntry();
 
+#ifdef ANDROID_SIMULATOR
+    vm->DetachCurrentThread();
+#endif
     return NULL;
 }
 
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 114d4c6..ce8eeae 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -92,12 +92,14 @@
         FIRST_FRAME = 4,
         PREPARING   = 8,
         PREPARED    = 16,
+        AT_EOS      = 32,
     };
 
     mutable Mutex mLock;
 
     OMXClient mClient;
     TimedEventQueue mQueue;
+    bool mQueueStarted;
     wp<MediaPlayerBase> mListener;
 
     sp<ISurface> mISurface;
diff --git a/media/sdutils/Android.mk b/media/sdutils/Android.mk
deleted file mode 100644
index 74e1eca..0000000
--- a/media/sdutils/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-ifeq ($(TARGET_ARCH),arm)
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	sdutil.cpp \
-
-LOCAL_SHARED_LIBRARIES := libhardware_legacy libbinder libcutils libutils libc
-
-LOCAL_MODULE:= sdutil
-LOCAL_MODULE_TAGS := debug
-
-include $(BUILD_EXECUTABLE)
-
-endif
diff --git a/media/sdutils/sdutil.cpp b/media/sdutils/sdutil.cpp
deleted file mode 100644
index 6d3e87c..0000000
--- a/media/sdutils/sdutil.cpp
+++ /dev/null
@@ -1,197 +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.
- */
-
-#include <hardware_legacy/IMountService.h>
-#include <binder/BpBinder.h>
-#include <binder/IServiceManager.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-namespace android {
-
-static sp<IMountService> gMountService;
-
-static void init() {
-    sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> binder = sm->getService(String16("mount"));
-    gMountService = interface_cast<IMountService>(binder);
-    if (gMountService == 0) {
-        fprintf(stderr, "could not get MountService\n");
-        exit(1);
-    }
-}
-
-static int mount(const char* path) {
-    String16 string(path);
-    return gMountService->mountVolume(string);
-}
-
-static int share(const char *path, const char *method) {
-    String16 sPath(path);
-    String16 sMethod(method);
-    return gMountService->shareVolume(sPath, sMethod);
-}
-
-static int unshare(const char *path, const char *method) {
-    String16 sPath(path);
-    String16 sMethod(method);
-    return gMountService->unshareVolume(sPath, sMethod);
-}
-
-static bool shared(const char *path, const char *method) {
-    String16 sPath(path);
-    String16 sMethod(method);
-    return gMountService->getVolumeShared(sPath, sMethod);
-}
-
-static int asec_create(const char *id, int sizeMb, const char *fstype,
-                       const char *key, int ownerUid) {
-    String16 sId(id);
-    String16 sFstype(fstype);
-    String16 sKey(key);
-
-    return gMountService->createSecureContainer(
-            sId, sizeMb, sFstype, sKey, ownerUid);
-}
-
-static int asec_finalize(const char *id) {
-    String16 sId(id);
-    return gMountService->finalizeSecureContainer(sId);
-}
-
-static int asec_destroy(const char *id) {
-    String16 sId(id);
-    return gMountService->destroySecureContainer(sId);
-}
-
-static int asec_mount(const char *id, const char *key, int ownerUid) {
-    String16 sId(id);
-    String16 sKey(key);
-    return gMountService->mountSecureContainer(sId, sKey, ownerUid);
-}
-
-static int asec_unmount(const char *id) {
-    String16 sId(id);
-    return gMountService->unmountSecureContainer(sId);
-}
-
-static int asec_rename(const char *oldId, const char *newId) {
-    String16 sOldId(oldId);
-    String16 sNewId(newId);
-    return gMountService->renameSecureContainer(sOldId, sNewId);
-}
-
-static int asec_path(const char *id) {
-    String16 sId(id);
-    gMountService->getSecureContainerPath(sId);
-    return 0;
-}
-
-static int unmount(const char* path) {
-    String16 string(path);
-    return gMountService->unmountVolume(string);
-}
-
-static int format(const char* path) {
-    String16 string(path);
-    return gMountService->formatVolume(string);
-}
-
-};
-
-static void usage(void);
-
-int main(int argc, char **argv)
-{
-    if (argc < 2)
-        usage();
-
-    android::init();
-    int rc = 0;
-    
-    if (strcmp(argv[1], "mount") == 0) {
-        rc = android::mount(argv[2]);
-    } else if (strcmp(argv[1], "format") == 0) {
-        rc = android::format(argv[2]);
-    } else if (strcmp(argv[1], "unmount") == 0) {
-        rc = android::unmount(argv[2]);
-    } else if (strcmp(argv[1], "share") == 0) {
-        if (argc != 3)
-            usage();
-        rc = android::share(argv[2], argv[3]);
-    } else if (strcmp(argv[1], "unshare") == 0) {
-        if (argc != 3)
-            usage();
-        rc = android::unshare(argv[2], argv[3]);
-    } else if (strcmp(argv[1], "shared") == 0) {
-        if (argc != 3)
-            usage();
-        fprintf(stdout, "%s\n", (android::shared(argv[2], argv[3]) ? "true" : "false"));
-    } else if (!strcmp(argv[1], "asec")) {
-        if (argc < 3)
-            usage();
-
-        if (!strcmp(argv[2], "create")) {
-
-            if (argc != 8)
-                usage();
-            rc = android::asec_create(argv[3], atoi(argv[4]), argv[5], argv[6], atoi(argv[7]));
-        } else if (!strcmp(argv[3], "finalize")) {
-            rc = android::asec_finalize(argv[3]);
-        } else if (!strcmp(argv[3], "destroy")) {
-            return android::asec_destroy(argv[3]);
-        } else if (!strcmp(argv[3], "mount")) {
-            if (argc != 6)
-                usage();
-            rc = android::asec_mount(argv[3], argv[4], atoi(argv[5]));
-        } else if (!strcmp(argv[3], "rename")) {
-            if (argc != 5)
-                usage();
-            rc = android::asec_rename(argv[3], argv[4]);
-        } else if (!strcmp(argv[3], "unmount")) {
-            rc = android::asec_unmount(argv[3]);
-        } else if (!strcmp(argv[3], "path")) {
-            rc = android::asec_path(argv[3]);
-        }
-    }
-
-    fprintf(stdout, "Operation completed with code %d\n", rc);
-    return rc;
-}
-
-static void usage()
-{
-    fprintf(stderr, "usage:\n"
-                    "    sdutil mount <mount path>          - mounts the SD card at the given mount point\n"
-                    "    sdutil unmount <mount path>        - unmounts the SD card at the given mount point\n"
-                    "    sdutil format <mount path>         - formats the SD card at the given mount point\n"
-                    "    sdutil share <path> <method>       - shares a volume\n"
-                    "    sdutil unshare <path> <method>     - unshares a volume\n"
-                    "    sdutil shared <path> <method>      - Queries volume share state\n"
-                    "    sdutil asec create <id> <sizeMb> <fstype> <key> <ownerUid>\n"
-                    "    sdutil asec finalize <id>\n"
-                    "    sdutil asec destroy <id>\n"
-                    "    sdutil asec mount <id> <key> <ownerUid>\n"
-                    "    sdutil asec unmount <id>\n"
-                    "    sdutil asec rename <oldId, newId>\n"
-                    "    sdutil asec path <id>\n"
-                    );
-    exit(1);
-}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
index 6087268..0e883e6 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
@@ -48,7 +48,7 @@
   
     public static final long PAUSE_WAIT_TIME = 3000;
     public static final long WAIT_TIME = 2000;
-    public static final long WAIT_LONG = 4000;
+    public static final long WAIT_SNAPSHOT_TIME = 5000;
   
     //Streaming Video
     public static final String VIDEO_HTTP3GP = "http://pvs.pv.com/jj/lipsync0.3gp";  
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java
index fa0986a..784db97 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java
@@ -192,7 +192,7 @@
             }
             mCamera.setPreviewCallback(null);
             mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
-            Thread.sleep(MediaNames.WAIT_LONG);
+            Thread.sleep(MediaNames.WAIT_SNAPSHOT_TIME);
         } catch (Exception e) {
             Log.v(TAG, e.toString());
         }      
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 933a7e5..95ab684 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -102,7 +102,11 @@
             File sourceFile = new File(archiveFilePath);
             DisplayMetrics metrics = new DisplayMetrics();
             metrics.setToDefaults();
-            PackageParser.Package pkg = packageParser.parsePackage(sourceFile, archiveFilePath, metrics, 0);
+            PackageParser.Package pkg = packageParser.parsePackage(sourceFile,
+                    archiveFilePath, metrics, 0);
+            // Nuke the parser reference right away and force a gc
+            Runtime.getRuntime().gc();
+            packageParser = null;
             if (pkg == null) {
                 Log.w(TAG, "Failed to parse package");
                 return PackageHelper.RECOMMEND_FAILED_INVALID_APK;
@@ -115,7 +119,7 @@
                 return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
             } else {
                 // Implies install on internal storage.
-                return 0;
+                return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
             }
         }
     };
diff --git a/services/java/com/android/server/AccessibilityManagerService.java b/services/java/com/android/server/AccessibilityManagerService.java
index 407983d..477ea0c 100644
--- a/services/java/com/android/server/AccessibilityManagerService.java
+++ b/services/java/com/android/server/AccessibilityManagerService.java
@@ -16,8 +16,6 @@
 
 package com.android.server;
 
-import static android.util.Config.LOGV;
-
 import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.HandlerCaller.SomeArgs;
 
@@ -47,6 +45,7 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.text.TextUtils.SimpleStringSplitter;
+import android.util.Config;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.accessibility.AccessibilityEvent;
@@ -137,10 +136,6 @@
 
         registerPackageChangeAndBootCompletedBroadcastReceiver();
         registerSettingsContentObservers();
-
-        synchronized (mLock) {
-            populateAccessibilityServiceListLocked();
-        }
     }
 
     /**
@@ -155,13 +150,19 @@
             public void onReceive(Context context, Intent intent) {
                 synchronized (mLock) {
                     populateAccessibilityServiceListLocked();
-                    manageServicesLocked();
 
                     if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) {
+                        // get the accessibility enabled setting on boot
                         mIsEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
                                 Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
-                        updateClientsLocked();
+
+                        // if accessibility is enabled inform our clients we are on
+                        if (mIsEnabled) {
+                            updateClientsLocked();
+                        }
                     }
+
+                    manageServicesLocked();
                 }
             }
         };
@@ -169,7 +170,6 @@
         // package changes
         IntentFilter packageFilter = new IntentFilter();
         packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
-        packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         packageFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
         packageFilter.addDataScheme("package");
@@ -409,7 +409,7 @@
 
         try {
             listener.onAccessibilityEvent(event);
-            if (LOGV) {
+            if (Config.DEBUG) {
                 Log.i(LOG_TAG, "Event " + event + " sent to " + listener);
             }
         } catch (RemoteException re) {
@@ -434,7 +434,7 @@
         mServices.remove(service);
         mHandler.removeMessages(service.mId);
 
-        if (LOGV) {
+        if (Config.DEBUG) {
             Log.i(LOG_TAG, "Dead service " + service.mService + " removed");
         }
 
@@ -547,6 +547,7 @@
 
         Map<ComponentName, Service> componentNameToServiceMap = mComponentNameToServiceMap;
         List<Service> services = mServices;
+        boolean isEnabled = mIsEnabled;
 
         for (int i = 0, count = installedServices.size(); i < count; i++) {
             ServiceInfo intalledService = installedServices.get(i);
@@ -554,7 +555,7 @@
                     intalledService.name);
             Service service = componentNameToServiceMap.get(componentName);
 
-            if (enabledServices.contains(componentName)) {
+            if (isEnabled && enabledServices.contains(componentName)) {
                 if (service == null) {
                     new Service(componentName).bind();
                 }
@@ -578,6 +579,7 @@
             } catch (RemoteException re) {
                 mClients.remove(i);
                 count--;
+                i--;
             }
         }
     }
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index d43039d..f79a02a 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.app.ActivityManagerNative;
+import android.app.ActivityThread;
 import android.app.AlarmManager;
 import android.app.IActivityManager;
 import android.app.IApplicationThread;
@@ -34,6 +35,7 @@
 import android.content.ServiceConnection;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageDataObserver;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.Signature;
@@ -66,6 +68,7 @@
 import java.io.EOFException;
 import java.io.File;
 import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -112,6 +115,7 @@
 
     private Context mContext;
     private PackageManager mPackageManager;
+    IPackageManager mPackageManagerBinder;
     private IActivityManager mActivityManager;
     private PowerManager mPowerManager;
     private AlarmManager mAlarmManager;
@@ -178,13 +182,15 @@
         public IRestoreObserver observer;
         public long token;
         public PackageInfo pkgInfo;
+        public int pmToken; // in post-install restore, the PM's token for this transaction
 
         RestoreParams(IBackupTransport _transport, IRestoreObserver _obs,
-                long _token, PackageInfo _pkg) {
+                long _token, PackageInfo _pkg, int _pmToken) {
             transport = _transport;
             observer = _obs;
             token = _token;
             pkgInfo = _pkg;
+            pmToken = _pmToken;
         }
 
         RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token) {
@@ -192,6 +198,7 @@
             observer = _obs;
             token = _token;
             pkgInfo = null;
+            pmToken = 0;
         }
     }
 
@@ -301,7 +308,7 @@
                 RestoreParams params = (RestoreParams)msg.obj;
                 Log.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
                 (new PerformRestoreTask(params.transport, params.observer,
-                        params.token, params.pkgInfo)).run();
+                        params.token, params.pkgInfo, params.pmToken)).run();
                 break;
             }
 
@@ -348,6 +355,7 @@
     public BackupManagerService(Context context) {
         mContext = context;
         mPackageManager = context.getPackageManager();
+        mPackageManagerBinder = ActivityThread.getPackageManager();
         mActivityManager = ActivityManagerNative.getDefault();
 
         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
@@ -517,6 +525,9 @@
                     }
                 }
             }
+        } catch (FileNotFoundException fnf) {
+            // Probably innocuous
+            Log.v(TAG, "No ancestral data");
         } catch (IOException e) {
             Log.w(TAG, "Unable to read token file", e);
         }
@@ -1111,6 +1122,18 @@
         }
     }
 
+    // Get the restore-set token for the best-available restore set for this package:
+    // the active set if possible, else the ancestral one.  Returns zero if none available.
+    long getAvailableRestoreToken(String packageName) {
+        long token = mAncestralToken;
+        synchronized (mQueueLock) {
+            if (mEverStoredApps.contains(packageName)) {
+                token = mCurrentToken;
+            }
+        }
+        return token;
+    }
+
     // -----
     // Utility methods used by the asynchronous-with-timeout backup/restore operations
     boolean waitUntilOperationComplete(int token) {
@@ -1128,12 +1151,14 @@
             }
         }
         mBackupHandler.removeMessages(MSG_TIMEOUT);
-        if (DEBUG) Log.v(TAG, "operation " + token + " complete: finalState=" + finalState);
+        if (DEBUG) Log.v(TAG, "operation " + Integer.toHexString(token)
+                + " complete: finalState=" + finalState);
         return finalState == OP_ACKNOWLEDGED;
     }
 
     void prepareOperationTimeout(int token, long interval) {
-        if (DEBUG) Log.v(TAG, "starting timeout: token=" + token + " interval=" + interval);
+        if (DEBUG) Log.v(TAG, "starting timeout: token=" + Integer.toHexString(token)
+                + " interval=" + interval);
         mCurrentOperations.put(token, OP_PENDING);
         Message msg = mBackupHandler.obtainMessage(MSG_TIMEOUT, token, 0);
         mBackupHandler.sendMessageDelayed(msg, interval);
@@ -1472,6 +1497,7 @@
         private long mToken;
         private PackageInfo mTargetPackage;
         private File mStateDir;
+        private int mPmToken;
 
         class RestoreRequest {
             public PackageInfo app;
@@ -1484,11 +1510,12 @@
         }
 
         PerformRestoreTask(IBackupTransport transport, IRestoreObserver observer,
-                long restoreSetToken, PackageInfo targetPackage) {
+                long restoreSetToken, PackageInfo targetPackage, int pmToken) {
             mTransport = transport;
             mObserver = observer;
             mToken = restoreSetToken;
             mTargetPackage = targetPackage;
+            mPmToken = pmToken;
 
             try {
                 mStateDir = new File(mBaseStateDir, transport.transportDirName());
@@ -1501,25 +1528,7 @@
             long startRealtime = SystemClock.elapsedRealtime();
             if (DEBUG) Log.v(TAG, "Beginning restore process mTransport=" + mTransport
                     + " mObserver=" + mObserver + " mToken=" + Long.toHexString(mToken)
-                    + " mTargetPackage=" + mTargetPackage);
-            /**
-             * Restore sequence:
-             *
-             * 1. get the restore set description for our identity
-             * 2. for each app in the restore set:
-             *    2.a. if it's restorable on this device, add it to the restore queue
-             * 3. for each app in the restore queue:
-             *    3.a. clear the app data
-             *    3.b. get the restore data for the app from the transport
-             *    3.c. launch the backup agent for the app
-             *    3.d. agent.doRestore() with the data from the server
-             *    3.e. unbind the agent [and kill the app?]
-             * 4. shut down the transport
-             *
-             * On errors, we try our best to recover and move on to the next
-             * application, but if necessary we abort the whole operation --
-             * the user is waiting, after all.
-             */
+                    + " mTargetPackage=" + mTargetPackage + " mPmToken=" + mPmToken);
 
             PackageManagerBackupAgent pmAgent = null;
             int error = -1; // assume error
@@ -1605,6 +1614,7 @@
                         EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
                         return;
                     } else if (packageName.equals("")) {
+                        if (DEBUG) Log.v(TAG, "No next package, finishing restore");
                         break;
                     }
 
@@ -1729,6 +1739,15 @@
                     writeRestoreTokens();
                 }
 
+                // We must under all circumstances tell the Package Manager to
+                // proceed with install notifications if it's waiting for us.
+                if (mPmToken > 0) {
+                    if (DEBUG) Log.v(TAG, "finishing PM token " + mPmToken);
+                    try {
+                        mPackageManagerBinder.finishPackageInstall(mPmToken);
+                    } catch (RemoteException e) { /* can't happen */ }
+                }
+
                 // done; we can finally release the wakelock
                 mWakelock.release();
             }
@@ -2165,7 +2184,7 @@
     public String getCurrentTransport() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "getCurrentTransport");
-        Log.v(TAG, "... getCurrentTransport() returning " + mCurrentTransport);
+        if (DEBUG) Log.v(TAG, "... getCurrentTransport() returning " + mCurrentTransport);
         return mCurrentTransport;
     }
 
@@ -2244,6 +2263,45 @@
         }
     }
 
+    // An application being installed will need a restore pass, then the Package Manager
+    // will need to be told when the restore is finished.
+    public void restoreAtInstall(String packageName, int token) {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            Log.w(TAG, "Non-system process uid=" + Binder.getCallingUid()
+                    + " attemping install-time restore");
+            return;
+        }
+
+        long restoreSet = getAvailableRestoreToken(packageName);
+        if (DEBUG) Log.v(TAG, "restoreAtInstall pkg=" + packageName
+                + " token=" + Integer.toHexString(token));
+
+        if (restoreSet != 0) {
+            // okay, we're going to attempt a restore of this package from this restore set.
+            // The eventual message back into the Package Manager to run the post-install
+            // steps for 'token' will be issued from the restore handling code.
+
+            // We can use a synthetic PackageInfo here because:
+            //   1. We know it's valid, since the Package Manager supplied the name
+            //   2. Only the packageName field will be used by the restore code
+            PackageInfo pkg = new PackageInfo();
+            pkg.packageName = packageName;
+
+            mWakelock.acquire();
+            Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
+            msg.obj = new RestoreParams(getTransport(mCurrentTransport), null,
+                    restoreSet, pkg, token);
+            mBackupHandler.sendMessage(msg);
+        } else {
+            // No way to attempt a restore; just tell the Package Manager to proceed
+            // with the post-install handling for this package.
+            if (DEBUG) Log.v(TAG, "No restore set -- skipping restore");
+            try {
+                mPackageManagerBinder.finishPackageInstall(token);
+            } catch (RemoteException e) { /* can't happen */ }
+        }
+    }
+
     // Hand off a restore session
     public IRestoreSession beginRestoreSession(String transport) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "beginRestoreSession");
@@ -2262,7 +2320,7 @@
     // completed the given outstanding asynchronous backup/restore operation.
     public void opComplete(int token) {
         synchronized (mCurrentOpLock) {
-            if (DEBUG) Log.v(TAG, "opComplete: " + token);
+            if (DEBUG) Log.v(TAG, "opComplete: " + Integer.toHexString(token));
             mCurrentOperations.put(token, OP_ACKNOWLEDGED);
             mCurrentOpLock.notifyAll();
         }
@@ -2285,6 +2343,7 @@
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                     "getAvailableRestoreSets");
 
+            long oldId = Binder.clearCallingIdentity();
             try {
                 if (mRestoreTransport == null) {
                     Log.w(TAG, "Null transport getting restore sets");
@@ -2298,6 +2357,8 @@
             } catch (Exception e) {
                 Log.e(TAG, "Error in getAvailableRestoreSets", e);
                 return null;
+            } finally {
+                Binder.restoreCallingIdentity(oldId);
             }
         }
 
@@ -2356,12 +2417,7 @@
             // So far so good; we're allowed to try to restore this package.  Now
             // check whether there is data for it in the current dataset, falling back
             // to the ancestral dataset if not.
-            long token = mAncestralToken;
-            synchronized (mQueueLock) {
-                if (mEverStoredApps.contains(packageName)) {
-                    token = mCurrentToken;
-                }
-            }
+            long token = getAvailableRestoreToken(packageName);
 
             // If we didn't come up with a place to look -- no ancestral dataset and
             // the app has never been backed up from this device -- there's nothing
@@ -2374,7 +2430,7 @@
             long oldId = Binder.clearCallingIdentity();
             mWakelock.acquire();
             Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
-            msg.obj = new RestoreParams(mRestoreTransport, observer, token, app);
+            msg.obj = new RestoreParams(mRestoreTransport, observer, token, app, 0);
             mBackupHandler.sendMessage(msg);
             Binder.restoreCallingIdentity(oldId);
             return 0;
@@ -2387,12 +2443,14 @@
             if (DEBUG) Log.d(TAG, "endRestoreSession");
 
             synchronized (this) {
+                long oldId = Binder.clearCallingIdentity();
                 try {
                     if (mRestoreTransport != null) mRestoreTransport.finishRestore();
                 } catch (Exception e) {
                     Log.e(TAG, "Error in finishRestore", e);
                 } finally {
                     mRestoreTransport = null;
+                    Binder.restoreCallingIdentity(oldId);
                 }
             }
 
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index f0bab81..4791718 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -22,8 +22,10 @@
 import android.app.IActivityManager;
 import android.app.IUiModeManager;
 import android.app.KeyguardManager;
-import android.app.StatusBarManager;
+import android.app.Notification;
+import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.app.StatusBarManager;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.content.ActivityNotFoundException;
@@ -55,6 +57,8 @@
 import android.text.format.Time;
 import android.util.Log;
 
+import com.android.internal.R;
+import com.android.internal.app.DisableCarModeActivity;
 import com.android.internal.widget.LockPatternUtils;
 
 import java.io.FileNotFoundException;
@@ -101,6 +105,7 @@
     private final Context mContext;
 
     private PowerManagerService mPowerManager;
+    private NotificationManager mNotificationManager;
 
     private KeyguardManager.KeyguardLock mKeyguardLock;
     private boolean mKeyguardDisabled;
@@ -125,7 +130,8 @@
 
             // Launch a dock activity
             String category;
-            if (mCarModeEnabled || mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
+            if (mCarModeEnabled) {
+                // Only launch car home when car mode is enabled.
                 category = Intent.CATEGORY_CAR_DOCK;
             } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
                 category = Intent.CATEGORY_DESK_DOCK;
@@ -332,9 +338,13 @@
                         if (mCarModeEnabled && mDockState != Intent.EXTRA_DOCK_STATE_CAR) {
                             // Pretend to be in DOCK_STATE_CAR.
                             intent.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_CAR);
+                        } else if (!mCarModeEnabled && mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
+                            // Pretend to be in DOCK_STATE_UNDOCKED.
+                            intent.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED);
                         } else {
                             intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
                         }
+                        intent.putExtra(Intent.EXTRA_PHYSICAL_DOCK_STATE, mDockState);
                         intent.putExtra(Intent.EXTRA_CAR_MODE_ENABLED, mCarModeEnabled);
 
                         // Check if this is Bluetooth Dock
@@ -462,6 +472,52 @@
         }
     };
 
+    private void adjustStatusBarCarMode() {
+        if (mStatusBarManager == null) {
+            mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE);
+        }
+
+        // Fear not: StatusBarService manages a list of requests to disable
+        // features of the status bar; these are ORed together to form the
+        // active disabled list. So if (for example) the device is locked and
+        // the status bar should be totally disabled, the calls below will
+        // have no effect until the device is unlocked.
+        if (mStatusBarManager != null) {
+            long ident = Binder.clearCallingIdentity();
+            mStatusBarManager.disable(mCarModeEnabled
+                ? StatusBarManager.DISABLE_NOTIFICATION_TICKER
+                : StatusBarManager.DISABLE_NONE);
+            Binder.restoreCallingIdentity(ident);
+        }
+
+        if (mNotificationManager == null) {
+            mNotificationManager = (NotificationManager)
+                    mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+        }
+
+        if (mNotificationManager != null) {
+            long ident = Binder.clearCallingIdentity();
+            if (mCarModeEnabled) {
+                Intent carModeOffIntent = new Intent(mContext, DisableCarModeActivity.class);
+
+                Notification n = new Notification();
+                n.icon = R.drawable.stat_notify_car_mode;
+                n.defaults = Notification.DEFAULT_LIGHTS;
+                n.flags = Notification.FLAG_ONGOING_EVENT;
+                n.when = 0;
+                n.setLatestEventInfo(
+                        mContext,
+                        mContext.getString(R.string.car_mode_disable_notification_title),
+                        mContext.getString(R.string.car_mode_disable_notification_message),
+                        PendingIntent.getActivity(mContext, 0, carModeOffIntent, 0));
+                mNotificationManager.notify(0, n);
+            } else {
+                mNotificationManager.cancel(0);
+            }
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
     private void setCarMode(boolean enabled) throws RemoteException {
         mCarModeEnabled = enabled;
         if (enabled) {
@@ -475,21 +531,7 @@
             setMode(Configuration.UI_MODE_TYPE_NORMAL,
                     Configuration.UI_MODE_NIGHT_UNDEFINED);
         }
-
-        if (mStatusBarManager == null) {
-            mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE);
-        }
-
-        // Fear not: StatusBarService manages a list of requests to disable
-        // features of the status bar; these are ORed together to form the
-        // active disabled list. So if (for example) the device is locked and
-        // the status bar should be totally disabled, the calls below will
-        // have no effect until the device is unlocked.
-        if (mStatusBarManager != null) {
-            mStatusBarManager.disable(enabled
-                ? StatusBarManager.DISABLE_NOTIFICATION_TICKER
-                : StatusBarManager.DISABLE_NONE);
-        }
+        adjustStatusBarCarMode();
     }
 
     private void setMode(int modeType, int modeNight) throws RemoteException {
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index e12f2e1..004fcf13 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -71,6 +71,7 @@
 import com.android.internal.location.GpsNetInitiatedHandler;
 import com.android.internal.location.LocationProviderProxy;
 import com.android.internal.location.MockProvider;
+import com.android.internal.location.PassiveProvider;
 
 /**
  * The service class that manages LocationProviders and issues location
@@ -452,6 +453,11 @@
             mGpsLocationProvider = gpsProvider;
         }
 
+        // create a passive location provider, which is always enabled
+        PassiveProvider passiveProvider = new PassiveProvider(this);
+        addProvider(passiveProvider);
+        mEnabledProviders.add(passiveProvider.getName());
+
         // initialize external network location and geocoder services
         Resources resources = mContext.getResources();
         String serviceName = resources.getString(
@@ -538,7 +544,8 @@
     }
 
     private void checkPermissionsSafe(String provider) {
-        if (LocationManager.GPS_PROVIDER.equals(provider)
+        if ((LocationManager.GPS_PROVIDER.equals(provider)
+                 || LocationManager.PASSIVE_PROVIDER.equals(provider))
             && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
                 != PackageManager.PERMISSION_GRANTED)) {
             throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
@@ -554,7 +561,8 @@
     }
 
     private boolean isAllowedProviderSafe(String provider) {
-        if (LocationManager.GPS_PROVIDER.equals(provider)
+        if ((LocationManager.GPS_PROVIDER.equals(provider)
+                || LocationManager.PASSIVE_PROVIDER.equals(provider))
             && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
                 != PackageManager.PERMISSION_GRANTED)) {
             return false;
@@ -1343,7 +1351,7 @@
         }
     }
 
-    public void reportLocation(Location location) {
+    public void reportLocation(Location location, boolean passive) {
         if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission");
@@ -1351,6 +1359,7 @@
 
         mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location);
         Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location);
+        m.arg1 = (passive ? 1 : 0);
         mLocationHandler.sendMessageAtFrontOfQueue(m);
     }
 
@@ -1415,8 +1424,8 @@
         return true;
     }
 
-    private void handleLocationChangedLocked(Location location) {
-        String provider = location.getProvider();
+    private void handleLocationChangedLocked(Location location, boolean passive) {
+        String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
         if (records == null || records.size() == 0) {
             return;
@@ -1502,17 +1511,20 @@
                     synchronized (mLock) {
                         Location location = (Location) msg.obj;
                         String provider = location.getProvider();
+                        boolean passive = (msg.arg1 == 1);
 
-                        // notify other providers of the new location
-                        for (int i = mProviders.size() - 1; i >= 0; i--) {
-                            LocationProviderInterface p = mProviders.get(i);
-                            if (!provider.equals(p.getName())) {
-                                p.updateLocation(location);
+                        if (!passive) {
+                            // notify other providers of the new location
+                            for (int i = mProviders.size() - 1; i >= 0; i--) {
+                                LocationProviderInterface p = mProviders.get(i);
+                                if (!provider.equals(p.getName())) {
+                                    p.updateLocation(location);
+                                }
                             }
                         }
 
                         if (isAllowedBySettingsLocked(provider)) {
-                            handleLocationChangedLocked(location);
+                            handleLocationChangedLocked(location, passive);
                         }
                     }
                 }
@@ -1687,6 +1699,10 @@
         boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
         checkMockPermissionsSafe();
 
+        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
+            throw new IllegalArgumentException("Cannot mock the passive location provider");
+        }
+
         long identity = Binder.clearCallingIdentity();
         synchronized (mLock) {
             MockProvider provider = new MockProvider(name, this,
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 4e2ffa4..2a78806 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -97,7 +97,7 @@
         public static final int OpFailedMediaBlank             = 402;
         public static final int OpFailedMediaCorrupt           = 403;
         public static final int OpFailedVolNotMounted          = 404;
-        public static final int OpFailedVolBusy                = 405;
+        public static final int OpFailedStorageBusy            = 405;
 
         /*
          * 600 series - Unsolicited broadcasts.
@@ -142,13 +142,31 @@
             if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
                 mBooted = true;
 
-                String path = Environment.getExternalStorageDirectory().getPath();
-                if (getVolumeState(path).equals(Environment.MEDIA_UNMOUNTED)) {
-                    int rc = doMountVolume(path);
-                    if (rc != StorageResultCode.OperationSucceeded) {
-                        Log.e(TAG, String.format("Boot-time mount failed (%d)", rc));
-                    }
+                /*
+                 * In the simulator, we need to broadcast a volume mounted event
+                 * to make the media scanner run.
+                 */
+                if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
+                    notifyVolumeStateChange(null, "/sdcard", VolumeState.NoMedia, VolumeState.Mounted);
+                    return;
                 }
+                new Thread() {
+                    public void run() {
+                        try {
+                            String path = Environment.getExternalStorageDirectory().getPath();
+                            if (getVolumeState(
+                                    Environment.getExternalStorageDirectory().getPath()).equals(
+                                            Environment.MEDIA_UNMOUNTED)) {
+                                int rc = doMountVolume(path);
+                                if (rc != StorageResultCode.OperationSucceeded) {
+                                    Log.e(TAG, String.format("Boot-time mount failed (%d)", rc));
+                                }
+                            }
+                        } catch (Exception ex) {
+                            Log.e(TAG, "Boot-time mount exception", ex);
+                        }
+                    }
+                }.start();
             }
         }
     };
@@ -184,7 +202,7 @@
         String vs = getVolumeState(path);
         if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
             mUmsEnabling = enable; // Override for isUsbMassStorageEnabled()
-            int rc = doUnmountVolume(path);
+            int rc = doUnmountVolume(path, false);
             mUmsEnabling = false; // Clear override
             if (rc != StorageResultCode.OperationSucceeded) {
                 Log.e(TAG, String.format("Failed to unmount before enabling UMS (%d)", rc));
@@ -527,7 +545,7 @@
         return rc;
     }
 
-    private int doUnmountVolume(String path) {
+    private int doUnmountVolume(String path, boolean force) {
         if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
             return VoldResponseCode.OpFailedVolNotMounted;
         }
@@ -537,7 +555,8 @@
         // notified that the applications installed on the media will be killed.
         mPms.updateExternalMediaStatus(false);
         try {
-            mConnector.doCommand(String.format("volume unmount %s", path));
+            mConnector.doCommand(String.format(
+                    "volume unmount %s%s", path, (force ? " force" : "")));
             return StorageResultCode.OperationSucceeded;
         } catch (NativeDaemonConnectorException e) {
             // Don't worry about mismatch in PackageManager since the
@@ -545,6 +564,8 @@
             int code = e.getCode();
             if (code == VoldResponseCode.OpFailedVolNotMounted) {
                 return StorageResultCode.OperationFailedStorageNotMounted;
+            } else if (code == VoldResponseCode.OpFailedStorageBusy) {
+                return StorageResultCode.OperationFailedStorageBusy;
             } else {
                 return StorageResultCode.OperationFailedInternalError;
             }
@@ -639,15 +660,6 @@
     public MountService(Context context) {
         mContext = context;
 
-        /*
-         * Vold does not run in the simulator, so fake out a mounted
-         * event to trigger MediaScanner
-         */
-        if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
-            updatePublicVolumeState("/sdcard", Environment.MEDIA_MOUNTED);
-            return;
-        }
-
         // XXX: This will go away soon in favor of IMountServiceObserver
         mPms = (PackageManagerService) ServiceManager.getService("package");
 
@@ -656,6 +668,16 @@
 
         mListeners = new ArrayList<MountServiceBinderListener>();
 
+        /*
+         * Vold does not run in the simulator, so pretend the connector thread
+         * ran and did its thing.
+         */
+        if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
+            mReady = true;
+            mUmsEnabling = true;
+            return;
+        }
+
         mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector");
         mReady = false;
         Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
@@ -733,7 +755,7 @@
             /*
              * If the media is mounted, then gracefully unmount it.
              */
-            if (doUnmountVolume(path) != StorageResultCode.OperationSucceeded) {
+            if (doUnmountVolume(path, true) != StorageResultCode.OperationSucceeded) {
                 Log.e(TAG, "Failed to unmount media for shutdown");
             }
         }
@@ -782,11 +804,11 @@
         return doMountVolume(path);
     }
 
-    public int unmountVolume(String path) {
+    public int unmountVolume(String path, boolean force) {
         validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
         waitForReady();
 
-        return doUnmountVolume(path);
+        return doUnmountVolume(path, force);
     }
 
     public int formatVolume(String path) {
@@ -878,16 +900,21 @@
         return rc;
     }
 
-    public int destroySecureContainer(String id) {
+    public int destroySecureContainer(String id, boolean force) {
         validatePermission(android.Manifest.permission.ASEC_DESTROY);
         waitForReady();
         warnOnNotMounted();
 
         int rc = StorageResultCode.OperationSucceeded;
         try {
-            mConnector.doCommand(String.format("asec destroy %s", id));
+            mConnector.doCommand(String.format("asec destroy %s%s", id, (force ? " force" : "")));
         } catch (NativeDaemonConnectorException e) {
-            rc = StorageResultCode.OperationFailedInternalError;
+            int code = e.getCode();
+            if (code == VoldResponseCode.OpFailedStorageBusy) {
+                rc = StorageResultCode.OperationFailedStorageBusy;
+            } else {
+                rc = StorageResultCode.OperationFailedInternalError;
+            }
         }
 
         if (rc == StorageResultCode.OperationSucceeded) {
@@ -928,7 +955,7 @@
         return rc;
     }
 
-    public int unmountSecureContainer(String id) {
+    public int unmountSecureContainer(String id, boolean force) {
         validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
         waitForReady();
         warnOnNotMounted();
@@ -940,11 +967,16 @@
          }
 
         int rc = StorageResultCode.OperationSucceeded;
-        String cmd = String.format("asec unmount %s", id);
+        String cmd = String.format("asec unmount %s%s", id, (force ? " force" : ""));
         try {
             mConnector.doCommand(cmd);
         } catch (NativeDaemonConnectorException e) {
-            rc = StorageResultCode.OperationFailedInternalError;
+            int code = e.getCode();
+            if (code == VoldResponseCode.OpFailedStorageBusy) {
+                rc = StorageResultCode.OperationFailedStorageBusy;
+            } else {
+                rc = StorageResultCode.OperationFailedInternalError;
+            }
         }
 
         if (rc == StorageResultCode.OperationSucceeded) {
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index d41aacf..958d089 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -28,6 +28,7 @@
 import android.net.INetworkManagementEventObserver;
 import android.os.INetworkManagementService;
 import android.os.Handler;
+import android.os.SystemProperties;
 import android.text.TextUtils;
 import android.util.Log;
 import java.util.ArrayList;
@@ -59,6 +60,10 @@
         public static final int TetherStatusResult        = 210;
         public static final int IpFwdStatusResult         = 211;
         public static final int InterfaceGetCfgResult     = 213;
+        public static final int SoftapStatusResult        = 214;
+        public static final int UsbRNDISStatusResult      = 215;
+
+        public static final int InterfaceChange           = 600;
     }
 
     /**
@@ -83,6 +88,10 @@
 
         mObservers = new ArrayList<INetworkManagementEventObserver>();
 
+        if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
+            return;
+        }
+
         mConnector = new NativeDaemonConnector(
                 new NetdCallbackReceiver(), "netd", 10, "NetdConnector");
         Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
@@ -147,12 +156,35 @@
         public void onDaemonConnected() {
             new Thread() {
                 public void run() {
-                    // XXX: Run some tests
                 }
             }.start();
         }
         public boolean onEvent(int code, String raw, String[] cooked) {
-           return false;
+            if (code == NetdResponseCode.InterfaceChange) {
+                /*
+                 * a network interface change occured
+                 * Format: "NNN Iface added <name>"
+                 *         "NNN Iface removed <name>"
+                 *         "NNN Iface changed <name> <up/down>"
+                 */
+                if (cooked.length < 4 || !cooked[1].equals("Iface")) {
+                    throw new IllegalStateException(
+                            String.format("Invalid event from daemon (%s)", raw));
+                }
+                if (cooked[2].equals("added")) {
+                    notifyInterfaceAdded(cooked[3]);
+                    return true;
+                } else if (cooked[2].equals("removed")) {
+                    notifyInterfaceRemoved(cooked[3]);
+                    return true;
+                } else if (cooked[2].equals("changed") && cooked.length == 5) {
+                    notifyInterfaceLinkStatusChanged(cooked[3], cooked[4].equals("up"));
+                    return true;
+                }
+                throw new IllegalStateException(
+                        String.format("Invalid event from daemon (%s)", raw));
+            }
+            return false;
         }
     }
 
@@ -393,4 +425,35 @@
                 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
         mConnector.doCommand(String.format("pppd detach %s", tty));
     }
+
+    public void startUsbRNDIS() throws IllegalStateException {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+        mConnector.doCommand("usb startrndis");
+    }
+
+    public void stopUsbRNDIS() throws IllegalStateException {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+        mConnector.doCommand("usb stoprndis");
+    }
+
+    public boolean isUsbRNDISStarted() throws IllegalStateException {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+        ArrayList<String> rsp = mConnector.doCommand("usb rndisstatus");
+
+        for (String line : rsp) {
+            String []tok = line.split(" ");
+            int code = Integer.parseInt(tok[0]);
+            if (code == NetdResponseCode.UsbRNDISStatusResult) {
+                if (tok[2].equals("started"))
+                    return true;
+                return false;
+            } else {
+                throw new IllegalStateException(String.format("Unexpected response code %d", code));
+            }
+        }
+        throw new IllegalStateException("Got an empty response");
+    }
 }
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 4326efc..38d8615 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -29,6 +29,7 @@
 
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
+import android.backup.IBackupManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -44,6 +45,7 @@
 import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.IPackageInstallObserver;
 import android.content.pm.IPackageManager;
+import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
@@ -122,6 +124,7 @@
     private static final boolean DEBUG_SETTINGS = false;
     private static final boolean DEBUG_PREFERRED = false;
     private static final boolean DEBUG_UPGRADE = false;
+    private static final boolean DEBUG_INSTALL = false;
 
     private static final boolean MULTIPLE_APPLICATION_UIDS = true;
     private static final int RADIO_UID = Process.PHONE_UID;
@@ -142,6 +145,9 @@
         FileObserver.CLOSE_WRITE /*| FileObserver.CREATE*/ | FileObserver.MOVED_TO;
 
     private static final int OBSERVER_EVENTS = REMOVE_EVENTS | ADD_EVENTS;
+    // Suffix used during package installation when copying/moving
+    // package apks to install directory.
+    private static final String INSTALL_PACKAGE_SUFFIX = "-";
 
     static final int SCAN_MONITOR = 1<<0;
     static final int SCAN_NO_DEX = 1<<1;
@@ -306,6 +312,7 @@
     static final int MCS_UNBIND = 6;
     static final int START_CLEANING_PACKAGE = 7;
     static final int FIND_INSTALL_LOC = 8;
+    static final int POST_INSTALL = 9;
     // Delay time in millisecs
     static final int BROADCAST_DELAY = 10 * 1000;
     private ServiceConnection mDefContainerConn = new ServiceConnection() {
@@ -320,9 +327,23 @@
         }
     };
 
+    // Recordkeeping of restore-after-install operations that are currently in flight
+    // between the Package Manager and the Backup Manager
+    class PostInstallData {
+        public InstallArgs args;
+        public PackageInstalledInfo res;
+
+        PostInstallData(InstallArgs _a, PackageInstalledInfo _r) {
+            args = _a;
+            res = _r;
+        }
+    };
+    final SparseArray<PostInstallData> mRunningInstalls = new SparseArray<PostInstallData>();
+    int mNextInstallToken = 1;  // nonzero; will be wrapped back to 1 when ++ overflows
+
     class PackageHandler extends Handler {
-        final ArrayList<InstallParams> mPendingInstalls =
-            new ArrayList<InstallParams>();
+        final ArrayList<HandlerParams> mPendingInstalls =
+            new ArrayList<HandlerParams>();
         // Service Connection to remote media container service to copy
         // package uri's from external media onto secure containers
         // or internal storage.
@@ -334,20 +355,19 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case INIT_COPY: {
-                    InstallParams params = (InstallParams) msg.obj;
+                    HandlerParams params = (HandlerParams) msg.obj;
                     Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
                     if (mContainerService != null) {
                         // No need to add to pending list. Use remote stub directly
-                        handleStartCopy(params);
+                        params.handleStartCopy(mContainerService);
                     } else {
                         if (mContext.bindService(service, mDefContainerConn,
                                 Context.BIND_AUTO_CREATE)) {
                             mPendingInstalls.add(params);
                         } else {
                             Log.e(TAG, "Failed to bind to media container service");
-                            // Indicate install failure TODO add new error code
-                            processPendingInstall(createInstallArgs(params),
-                                    PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
+                            // Indicate service bind error
+                            params.handleServiceError();
                         }
                     }
                     break;
@@ -358,9 +378,9 @@
                         mContainerService = (IMediaContainerService) msg.obj;
                     }
                     if (mPendingInstalls.size() > 0) {
-                        InstallParams params = mPendingInstalls.remove(0);
+                        HandlerParams params = mPendingInstalls.remove(0);
                         if (params != null) {
-                            handleStartCopy(params);
+                            params.handleStartCopy(mContainerService);
                         }
                     }
                     break;
@@ -419,55 +439,52 @@
                     }
                     startCleaningPackages();
                 } break;
-            }
-        }
+                case POST_INSTALL: {
+                    if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
+                    PostInstallData data = mRunningInstalls.get(msg.arg1);
+                    mRunningInstalls.delete(msg.arg1);
 
-        // Utility method to initiate copying apk via media
-        // container service.
-        private void handleStartCopy(InstallParams params) {
-            int ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
-            if (mContainerService != null) {
-                // Remote call to find out default install location
-                int loc = params.getInstallLocation(mContainerService);
-                // Use install location to create InstallArgs and temporary
-                // install location
-                if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE){
-                    ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-                } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
-                    ret = PackageManager.INSTALL_FAILED_INVALID_APK;
-                } else {
-                    if ((params.flags & PackageManager.INSTALL_EXTERNAL) == 0){
-                        if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
-                            // Set the flag to install on external media.
-                            params.flags |= PackageManager.INSTALL_EXTERNAL;
-                        } else {
-                            // Make sure the flag for installing on external
-                            // media is unset
-                            params.flags &= ~PackageManager.INSTALL_EXTERNAL;
+                    if (data != null) {
+                        InstallArgs args = data.args;
+                        PackageInstalledInfo res = data.res;
+
+                        if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+                            res.removedInfo.sendBroadcast(false, true);
+                            Bundle extras = new Bundle(1);
+                            extras.putInt(Intent.EXTRA_UID, res.uid);
+                            final boolean update = res.removedInfo.removedPackage != null;
+                            if (update) {
+                                extras.putBoolean(Intent.EXTRA_REPLACING, true);
+                            }
+                            sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
+                                    res.pkg.applicationInfo.packageName,
+                                    extras);
+                            if (update) {
+                                sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
+                                        res.pkg.applicationInfo.packageName,
+                                        extras);
+                            }
+                            if (res.removedInfo.args != null) {
+                                // Remove the replaced package's older resources safely now
+                                synchronized (mInstallLock) {
+                                    res.removedInfo.args.doPostDeleteLI(true);
+                                }
+                            }
                         }
-                    }
-                    // Disable forward locked apps on sdcard.
-                    if ((params.flags & PackageManager.INSTALL_FORWARD_LOCK) != 0 &&
-                            (params.flags & PackageManager.INSTALL_EXTERNAL) != 0) {
-                        // Make sure forward locked apps can only be installed
-                        // on internal storage
-                        Log.w(TAG, "Cannot install protected apps on sdcard");
-                        ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
+                        Runtime.getRuntime().gc();
+
+                        if (args.observer != null) {
+                            try {
+                                args.observer.packageInstalled(res.name, res.returnCode);
+                            } catch (RemoteException e) {
+                                Log.i(TAG, "Observer no longer exists.");
+                            }
+                        }
                     } else {
-                        ret = PackageManager.INSTALL_SUCCEEDED;
+                        Log.e(TAG, "Bogus post-install token " + msg.arg1);
                     }
-                }
+                } break;
             }
-            mHandler.sendEmptyMessage(MCS_UNBIND);
-            // Create the file args now.
-            InstallArgs args = createInstallArgs(params);
-            if (ret == PackageManager.INSTALL_SUCCEEDED) {
-                // Create copy only if we are not in an erroneous state.
-                args.createCopyFile();
-                // Remote call to initiate copy
-                ret = args.copyApk(mContainerService);
-            }
-            processPendingInstall(args, ret);
         }
     }
 
@@ -2180,8 +2197,8 @@
         int i;
         for (i=0; i<files.length; i++) {
             File file = new File(dir, files[i]);
-            if (files[i] != null && files[i].endsWith(".zip")) {
-                // Public resource for forward locked package. Ignore
+            if (!isPackageFilename(files[i])) {
+                // Ignore entries which are not apk's
                 continue;
             }
             PackageParser.Package pkg = scanPackageLI(file,
@@ -2936,11 +2953,6 @@
             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
         }
 
-        // We don't expect installation to fail beyond this point,
-        if ((scanMode&SCAN_MONITOR) != 0) {
-            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.
@@ -2950,6 +2962,10 @@
         }
 
         synchronized (mPackages) {
+            // We don't expect installation to fail beyond this point,
+            if ((scanMode&SCAN_MONITOR) != 0) {
+                mAppDirs.put(pkg.mPath, pkg);
+            }
             // Add the new setting to mSettings
             mSettings.insertPackageSettingLP(pkgSetting, pkg);
             // Add the new setting to mPackages
@@ -4224,19 +4240,24 @@
                     return;
                 }
 
+                // Ignore packages that are being installed or
+                // have just been installed.
+                if (ignoreCodePath(fullPathStr)) {
+                    return;
+                }
+                PackageParser.Package p = null;
+                synchronized (mPackages) {
+                    p = mAppDirs.get(fullPathStr);
+                }
                 if ((event&REMOVE_EVENTS) != 0) {
-                    synchronized (mInstallLock) {
-                        PackageParser.Package p = mAppDirs.get(fullPathStr);
-                        if (p != null) {
-                            removePackageLI(p, true);
-                            removedPackage = p.applicationInfo.packageName;
-                            removedUid = p.applicationInfo.uid;
-                        }
+                    if (p != null) {
+                        removePackageLI(p, true);
+                        removedPackage = p.applicationInfo.packageName;
+                        removedUid = p.applicationInfo.uid;
                     }
                 }
 
                 if ((event&ADD_EVENTS) != 0) {
-                    PackageParser.Package p = mAppDirs.get(fullPathStr);
                     if (p == null) {
                         p = scanPackageLI(fullPath,
                                 (mIsRom ? PackageParser.PARSE_IS_SYSTEM : 0) |
@@ -4294,6 +4315,12 @@
         mHandler.sendMessage(msg);
     }
 
+    public void finishPackageInstall(int token) {
+        if (DEBUG_INSTALL) Log.v(TAG, "BM finishing package install for " + token);
+        Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
+        mHandler.sendMessage(msg);
+    }
+
     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() {
@@ -4312,48 +4339,73 @@
                     }
                     args.doPostInstall(res.returnCode);
                 }
-                if (args.observer != null) {
-                    try {
-                        args.observer.packageInstalled(res.name, res.returnCode);
-                    } catch (RemoteException e) {
-                        Log.i(TAG, "Observer no longer exists.");
-                    }
-                }
-                // There appears to be a subtle deadlock condition if the sendPackageBroadcast
-                // call appears in the synchronized block above.
-                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
-                    res.removedInfo.sendBroadcast(false, true);
-                    Bundle extras = new Bundle(1);
-                    extras.putInt(Intent.EXTRA_UID, res.uid);
-                    final boolean update = res.removedInfo.removedPackage != null;
-                    if (update) {
-                        extras.putBoolean(Intent.EXTRA_REPLACING, true);
-                    }
-                    sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
-                                         res.pkg.applicationInfo.packageName,
-                                         extras);
-                    if (update) {
-                        sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
-                                res.pkg.applicationInfo.packageName,
-                                extras);
-                    }
-                    if (res.removedInfo.args != null) {
-                        // Remove the replaced package's older resources safely now
-                        synchronized (mInstallLock) {
-                            res.removedInfo.args.doPostDeleteLI(true);
+
+                // A restore should be performed at this point if (a) the install
+                // succeeded, (b) the operation is not an update, and (c) the new
+                // package has a backupAgent defined.
+                final boolean update = res.removedInfo.removedPackage != null;
+                boolean doRestore = (!update
+                        && res.pkg != null
+                        && res.pkg.applicationInfo.backupAgentName != null);
+
+                // Set up the post-install work request bookkeeping.  This will be used
+                // and cleaned up by the post-install event handling regardless of whether
+                // there's a restore pass performed.  Token values are >= 1.
+                int token;
+                if (mNextInstallToken < 0) mNextInstallToken = 1;
+                token = mNextInstallToken++;
+
+                PostInstallData data = new PostInstallData(args, res);
+                mRunningInstalls.put(token, data);
+                if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
+
+                if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
+                    // Pass responsibility to the Backup Manager.  It will perform a
+                    // restore if appropriate, then pass responsibility back to the
+                    // Package Manager to run the post-install observer callbacks
+                    // and broadcasts.
+                    IBackupManager bm = IBackupManager.Stub.asInterface(
+                            ServiceManager.getService(Context.BACKUP_SERVICE));
+                    if (bm != null) {
+                        if (DEBUG_INSTALL) Log.v(TAG, "token " + token
+                                + " to BM for possible restore");
+                        try {
+                            bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
+                        } catch (RemoteException e) {
+                            // can't happen; the backup manager is local
+                        } catch (Exception e) {
+                            Log.e(TAG, "Exception trying to enqueue restore", e);
+                            doRestore = false;
                         }
+                    } else {
+                        Log.e(TAG, "Backup Manager not found!");
+                        doRestore = false;
                     }
                 }
-                Runtime.getRuntime().gc();
+
+                if (!doRestore) {
+                    // No restore possible, or the Backup Manager was mysteriously not
+                    // available -- just fire the post-install work request directly.
+                    if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
+                    Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
+                    mHandler.sendMessage(msg);
+                }
             }
         });
     }
 
-    static final class InstallParams {
+    interface HandlerParams {
+        void handleStartCopy(IMediaContainerService imcs);
+        void handleServiceError();
+    }
+
+    class InstallParams implements HandlerParams {
         final IPackageInstallObserver observer;
         int flags;
         final Uri packageURI;
         final String installerPackageName;
+        private InstallArgs mArgs;
+        private int mRet;
         InstallParams(Uri packageURI,
                 IPackageInstallObserver observer, int flags,
                 String installerPackageName) {
@@ -4363,13 +4415,118 @@
             this.installerPackageName = installerPackageName;
         }
 
-        public int getInstallLocation(IMediaContainerService imcs) {
+        private int getInstallLocation(IMediaContainerService imcs) {
             try {
                 return imcs.getRecommendedInstallLocation(packageURI);
             } catch (RemoteException e) {
             }
             return  -1;
         }
+
+        public void handleStartCopy(IMediaContainerService imcs) {
+            int ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+            if (imcs != null) {
+                // Remote call to find out default install location
+                int loc = getInstallLocation(imcs);
+                // Use install location to create InstallArgs and temporary
+                // install location
+                if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE){
+                    ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+                } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
+                    ret = PackageManager.INSTALL_FAILED_INVALID_APK;
+                } else {
+                    if ((flags & PackageManager.INSTALL_EXTERNAL) == 0){
+                        if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
+                            // Set the flag to install on external media.
+                            flags |= PackageManager.INSTALL_EXTERNAL;
+                        } else {
+                            // Make sure the flag for installing on external
+                            // media is unset
+                            flags &= ~PackageManager.INSTALL_EXTERNAL;
+                        }
+                    }
+                    // Disable forward locked apps on sdcard.
+                    if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0 &&
+                            (flags & PackageManager.INSTALL_EXTERNAL) != 0) {
+                        // Make sure forward locked apps can only be installed
+                        // on internal storage
+                        Log.w(TAG, "Cannot install protected apps on sdcard");
+                        ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
+                    } else {
+                        ret = PackageManager.INSTALL_SUCCEEDED;
+                    }
+                }
+            }
+            // Create the file args now.
+            mArgs = createInstallArgs(this);
+            if (ret == PackageManager.INSTALL_SUCCEEDED) {
+                // Create copy only if we are not in an erroneous state.
+                // Remote call to initiate copy using temporary file
+                ret = mArgs.copyApk(imcs, true);
+            }
+            mRet = ret;
+            mHandler.sendEmptyMessage(MCS_UNBIND);
+            handleReturnCode();
+        }
+
+        void handleReturnCode() {
+            processPendingInstall(mArgs, mRet);
+        }
+
+        public void handleServiceError() {
+            mArgs = createInstallArgs(this);
+            mRet = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+            handleReturnCode();
+        }
+    };
+
+    /*
+     * Utility class used in movePackage api.
+     * srcArgs and targetArgs are not set for invalid flags and make
+     * sure to do null checks when invoking methods on them.
+     * We probably want to return ErrorPrams for both failed installs
+     * and moves.
+     */
+    class MoveParams implements HandlerParams {
+        final IPackageMoveObserver observer;
+        final int flags;
+        final String packageName;
+        final InstallArgs srcArgs;
+        final InstallArgs targetArgs;
+        int mRet;
+        MoveParams(InstallArgs srcArgs,
+                IPackageMoveObserver observer,
+                int flags, String packageName) {
+            this.srcArgs = srcArgs;
+            this.observer = observer;
+            this.flags = flags;
+            this.packageName = packageName;
+            if (srcArgs != null) {
+                Uri packageUri = Uri.fromFile(new File(srcArgs.getCodePath()));
+                targetArgs = createInstallArgs(packageUri, flags, packageName);
+            } else {
+                targetArgs = null;
+            }
+        }
+
+        public void handleStartCopy(IMediaContainerService imcs) {
+            // Create the file args now.
+            mRet = targetArgs.copyApk(imcs, false);
+            targetArgs.doPreInstall(mRet);
+            mHandler.sendEmptyMessage(MCS_UNBIND);
+            handleReturnCode();
+        }
+
+        void handleReturnCode() {
+            targetArgs.doPostInstall(mRet);
+            // TODO invoke pending move
+            processPendingMove(this, mRet);
+        }
+
+        public void handleServiceError() {
+            mRet = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+            handleReturnCode();
+        }
     };
 
     private InstallArgs createInstallArgs(InstallParams params) {
@@ -4388,8 +4545,18 @@
         }
     }
 
+    private InstallArgs createInstallArgs(Uri packageURI, int flags, String pkgName) {
+        if (installOnSd(flags)) {
+            String cid = getNextCodePath(null, pkgName, "/" + SdInstallArgs.RES_FILE_NAME);
+            return new SdInstallArgs(packageURI, cid);
+        } else {
+            return new FileInstallArgs(packageURI, pkgName);
+        }
+    }
+
     static abstract class InstallArgs {
         final IPackageInstallObserver observer;
+        // Always refers to PackageManager flags only
         final int flags;
         final Uri packageURI;
         final String installerPackageName;
@@ -4404,7 +4571,7 @@
         }
 
         abstract void createCopyFile();
-        abstract int copyApk(IMediaContainerService imcs);
+        abstract int copyApk(IMediaContainerService imcs, boolean temp);
         abstract int doPreInstall(int status);
         abstract boolean doRename(int status, String pkgName, String oldCodePath);
         abstract int doPostInstall(int status);
@@ -4419,6 +4586,7 @@
         File installDir;
         String codeFileName;
         String resourceFileName;
+        boolean created = false;
 
         FileInstallArgs(InstallParams params) {
             super(params.packageURI, params.observer,
@@ -4433,6 +4601,15 @@
             resourceFileName = fullResourcePath;
         }
 
+        FileInstallArgs(Uri packageURI, String pkgName) {
+            super(packageURI, null, 0, null);
+            boolean fwdLocked = isFwdLocked(flags);
+            installDir = fwdLocked ? mDrmAppPrivateInstallDir : mAppInstallDir;
+            String apkName = getNextCodePath(null, pkgName, ".apk");
+            codeFileName = new File(installDir, apkName + ".apk").getPath();
+            resourceFileName = getResourcePathFromCodePath();
+        }
+
         String getCodePath() {
             return codeFileName;
         }
@@ -4442,11 +4619,29 @@
             installDir = fwdLocked ? mDrmAppPrivateInstallDir : mAppInstallDir;
             codeFileName = createTempPackageFile(installDir).getPath();
             resourceFileName = getResourcePathFromCodePath();
+            created = true;
         }
 
-        int copyApk(IMediaContainerService imcs) {
+        int copyApk(IMediaContainerService imcs, boolean temp) {
+            if (temp) {
+                // Generate temp file name
+                createCopyFile();
+            }
             // Get a ParcelFileDescriptor to write to the output file
             File codeFile = new File(codeFileName);
+            if (!created) {
+                try {
+                    codeFile.createNewFile();
+                    // Set permissions
+                    if (!setPermissions()) {
+                        // Failed setting permissions.
+                        return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+                    }
+                } catch (IOException e) {
+                   Log.w(TAG, "Failed to create file " + codeFile);
+                   return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+                }
+            }
             ParcelFileDescriptor out = null;
             try {
             out = ParcelFileDescriptor.open(codeFile,
@@ -4491,7 +4686,7 @@
                 codeFileName = desFile.getPath();
                 resourceFileName = getResourcePathFromCodePath();
                 // Set permissions
-                if (!setPermissions(pkgName)) {
+                if (!setPermissions()) {
                     // Failed setting permissions.
                     return false;
                 }
@@ -4558,7 +4753,7 @@
             }
         }
 
-        private boolean setPermissions(String pkgName) {
+        private boolean setPermissions() {
             // TODO Do this in a more elegant way later on. for now just a hack
             if (!isFwdLocked(flags)) {
                 final int filePermissions =
@@ -4594,7 +4789,7 @@
         }
 
         SdInstallArgs(String fullCodePath, String fullResourcePath) {
-            super(null, null, ApplicationInfo.FLAG_ON_SDCARD, null);
+            super(null, null, PackageManager.INSTALL_EXTERNAL, null);
             // Extract cid from fullCodePath
             int eidx = fullCodePath.lastIndexOf("/");
             String subStr1 = fullCodePath.substring(0, eidx);
@@ -4604,7 +4799,12 @@
         }
 
         SdInstallArgs(String cid) {
-            super(null, null,  ApplicationInfo.FLAG_ON_SDCARD, null);
+            super(null, null, PackageManager.INSTALL_EXTERNAL, null);
+            this.cid = cid;
+        }
+
+        SdInstallArgs(Uri packageURI, String cid) {
+            super(packageURI, null, PackageManager.INSTALL_EXTERNAL, null);
             this.cid = cid;
         }
 
@@ -4612,7 +4812,10 @@
             cid = getTempContainerId();
         }
 
-        int copyApk(IMediaContainerService imcs) {
+        int copyApk(IMediaContainerService imcs, boolean temp) {
+            if (temp) {
+                createCopyFile();
+            }
             try {
                 cachePath = imcs.copyResourceToContainer(
                         packageURI, cid,
@@ -4771,8 +4974,8 @@
             if (sidx != -1) {
                 subStr = subStr.substring(sidx + prefix.length());
                 if (subStr != null) {
-                    if (subStr.startsWith("-")) {
-                        subStr = subStr.substring(1);
+                    if (subStr.startsWith(INSTALL_PACKAGE_SUFFIX)) {
+                        subStr = subStr.substring(INSTALL_PACKAGE_SUFFIX.length());
                     }
                     try {
                         idx = Integer.parseInt(subStr);
@@ -4786,10 +4989,26 @@
                 }
             }
         }
-        idxStr = "-" + Integer.toString(idx);
+        idxStr = INSTALL_PACKAGE_SUFFIX + Integer.toString(idx);
         return prefix + idxStr;
     }
 
+    // Utility method used to ignore ADD/REMOVE events
+    // by directory observer.
+    private static boolean ignoreCodePath(String fullPathStr) {
+        String apkName = getApkName(fullPathStr);
+        int idx = apkName.lastIndexOf(INSTALL_PACKAGE_SUFFIX);
+        if (idx != -1 && ((idx+1) < apkName.length())) {
+            // Make sure the package ends with a numeral
+            String version = apkName.substring(idx+1);
+            try {
+                Integer.parseInt(version);
+                return true;
+            } catch (NumberFormatException e) {}
+        }
+        return false;
+    }
+    
     // 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.
@@ -5055,6 +5274,19 @@
         }
     }
 
+    // Utility method used to move dex files during install.
+    private int moveDexFiles(PackageParser.Package newPackage) {
+        int retCode;
+        if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
+            retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath);
+            if (retCode != 0) {
+                Log.e(TAG, "Couldn't rename dex file: " + newPackage.mPath);
+                return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+            }
+        }
+        return PackageManager.INSTALL_SUCCEEDED;
+    }
+
     private void updateSettingsLI(PackageParser.Package newPackage,
             String installerPackageName, PackageInstalledInfo res) {
         String pkgName = newPackage.packageName;
@@ -5066,27 +5298,20 @@
             mSettings.writeLP();
         }
 
-        int retCode = 0;
-        if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
-            retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath);
-            if (retCode != 0) {
-                Log.e(TAG, "Couldn't rename dex file: " + newPackage.mPath);
-                res.returnCode =  PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-                return;
-            }
+        if ((res.returnCode = moveDexFiles(newPackage))
+                != PackageManager.INSTALL_SUCCEEDED) {
+            // Discontinue if moving dex files failed.
+            return;
         }
-        res.returnCode = setPermissionsLI(newPackage);
-        if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+        if((res.returnCode = setPermissionsLI(newPackage))
+                != PackageManager.INSTALL_SUCCEEDED) {
+            if (mInstaller != null) {
+                mInstaller.rmdex(newPackage.mScanPath);
+            }
             return;
         } else {
             Log.d(TAG, "New package installed in " + newPackage.mPath);
         }
-        if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
-            if (mInstaller != null) {
-                mInstaller.rmdex(newPackage.mScanPath);
-            }
-        }
-
         synchronized (mPackages) {
             grantPermissionsLP(newPackage, true);
             res.name = pkgName;
@@ -6765,9 +6990,13 @@
         HashSet<String> loadedPermissions = new HashSet<String>();
 
         GrantedPermissions(int pkgFlags) {
+            setFlags(pkgFlags);
+        }
+
+        void setFlags(int pkgFlags) {
             this.pkgFlags = (pkgFlags & ApplicationInfo.FLAG_SYSTEM) |
-                    (pkgFlags & ApplicationInfo.FLAG_FORWARD_LOCK) |
-                    (pkgFlags & ApplicationInfo.FLAG_ON_SDCARD);
+            (pkgFlags & ApplicationInfo.FLAG_FORWARD_LOCK) |
+            (pkgFlags & ApplicationInfo.FLAG_ON_SDCARD);
         }
     }
 
@@ -8662,11 +8891,6 @@
                    uidArr[di++] = uidList[i];
                }
            }
-           if (true) {
-               for (int j = 0; j < num; j++) {
-                   Log.i(TAG, "uidArr[" + j + "]=" + uidArr[j]);
-               }
-           }
        }
        if (mediaStatus) {
            if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages");
@@ -8779,4 +9003,145 @@
            }
        }
    }
+
+   public void movePackage(final String packageName,
+           final IPackageMoveObserver observer, final int flags) {
+       if (packageName == null) {
+           return;
+       }
+       mContext.enforceCallingOrSelfPermission(
+               android.Manifest.permission.MOVE_PACKAGE, null);
+       int returnCode = PackageManager.MOVE_SUCCEEDED;
+       int currFlags = 0;
+       int newFlags = 0;
+       synchronized (mPackages) {
+           PackageParser.Package pkg = mPackages.get(packageName);
+           if (pkg == null) {
+               returnCode =  PackageManager.MOVE_FAILED_DOESNT_EXIST;
+           }
+           // Disable moving fwd locked apps and system packages
+           if (pkg.applicationInfo != null &&
+                   (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+               Log.w(TAG, "Cannot move system application");
+               returnCode = PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
+           } else if (pkg.applicationInfo != null &&
+                   (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0) {
+               Log.w(TAG, "Cannot move forward locked app.");
+               returnCode = PackageManager.MOVE_FAILED_FORWARD_LOCKED;
+           } else {
+               // Find install location first
+               if ((flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 &&
+                       (flags & PackageManager.MOVE_INTERNAL) != 0) {
+                   Log.w(TAG, "Ambigous flags specified for move location.");
+                   returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
+               } else {
+                   newFlags = (flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 ?
+                           PackageManager.INSTALL_EXTERNAL : 0;
+                   currFlags = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0 ?
+                           PackageManager.INSTALL_EXTERNAL : 0;
+                   if (newFlags == currFlags) {
+                       Log.w(TAG, "No move required. Trying to move to same location");
+                       returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
+                   }
+               }
+           }
+           if (returnCode != PackageManager.MOVE_SUCCEEDED) {
+               processPendingMove(new MoveParams(null, observer, 0, null), returnCode);
+           } else {
+               Message msg = mHandler.obtainMessage(INIT_COPY);
+               InstallArgs srcArgs = createInstallArgs(currFlags, pkg.applicationInfo.sourceDir,
+                       pkg.applicationInfo.publicSourceDir);
+               MoveParams mp = new MoveParams(srcArgs, observer, newFlags,
+                       packageName);
+               msg.obj = mp;
+               mHandler.sendMessage(msg);
+           }
+       }
+   }
+
+   private void processPendingMove(final MoveParams mp, final int currentStatus) {
+       // Queue up an async operation since the package deletion may take a little while.
+       mHandler.post(new Runnable() {
+           public void run() {
+               mHandler.removeCallbacks(this);
+               int returnCode = currentStatus;
+               boolean moveSucceeded = (returnCode == PackageManager.MOVE_SUCCEEDED);
+               if (moveSucceeded) {
+                   int uid = -1;
+                   synchronized (mPackages) {
+                       uid = mPackages.get(mp.packageName).applicationInfo.uid;
+                   }
+                   ArrayList<String> pkgList = new ArrayList<String>();
+                   pkgList.add(mp.packageName);
+                   int uidArr[] = new int[] { uid };
+                   // Send resources unavailable broadcast
+                   sendResourcesChangedBroadcast(false, pkgList, uidArr);
+
+                   // Update package code and resource paths
+                   synchronized (mPackages) {
+                       PackageParser.Package pkg = mPackages.get(mp.packageName);
+                       if (pkg != null) {
+                           String oldCodePath = pkg.mPath;
+                           String newCodePath = mp.targetArgs.getCodePath();
+                           String newResPath = mp.targetArgs.getResourcePath();
+                           pkg.mPath = newCodePath;
+                           // Move dex files around
+                           if (moveDexFiles(pkg)
+                                   != PackageManager.INSTALL_SUCCEEDED) {
+                               // Moving of dex files failed. Set
+                               // error code and abort move.
+                               pkg.mPath = pkg.mScanPath;
+                               returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+                               moveSucceeded = false;
+                           } else {
+                               pkg.mScanPath = newCodePath;
+                               pkg.applicationInfo.sourceDir = newCodePath;
+                               pkg.applicationInfo.publicSourceDir = newResPath;
+                               PackageSetting ps = (PackageSetting) pkg.mExtras;
+                               ps.codePath = new File(pkg.applicationInfo.sourceDir);
+                               ps.codePathString = ps.codePath.getPath();
+                               ps.resourcePath = new File(pkg.applicationInfo.publicSourceDir);
+                               ps.resourcePathString = ps.resourcePath.getPath();
+                               // Set the application info flag correctly.
+                               if ((mp.flags & PackageManager.INSTALL_EXTERNAL) != 0) {
+                                   pkg.applicationInfo.flags |= ApplicationInfo.FLAG_ON_SDCARD;
+                               } else {
+                                   pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_ON_SDCARD;
+                               }
+                               ps.setFlags(pkg.applicationInfo.flags);
+                               mAppDirs.remove(oldCodePath);
+                               mAppDirs.put(newCodePath, pkg);
+                               // Persist settings
+                               mSettings.writeLP();
+                           }
+                       }
+                   }
+                   if (moveSucceeded) {
+                       // Delete older code
+                       synchronized (mInstallLock) {
+                           mp.srcArgs.cleanUpResourcesLI();
+                       }
+                       // Send resources available broadcast
+                       sendResourcesChangedBroadcast(true, pkgList, uidArr);
+                       Runtime.getRuntime().gc();
+                   }
+               }
+               if (!moveSucceeded){
+                   // Clean up failed installation
+                   if (mp.targetArgs != null) {
+                       mp.targetArgs.doPostInstall(
+                               PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
+                   }
+               }
+               IPackageMoveObserver observer = mp.observer;
+               if (observer != null) {
+                   try {
+                       observer.packageMoved(mp.packageName, returnCode);
+                   } catch (RemoteException e) {
+                       Log.i(TAG, "Observer no longer exists.");
+                   }
+               }
+           }
+       });
+   }
 }
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 7fcf900..a481036e 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -373,10 +373,15 @@
     boolean mLayoutNeeded = true;
     boolean mAnimationPending = false;
     boolean mDisplayFrozen = false;
+    boolean mWaitingForConfig = false;
     boolean mWindowsFreezingScreen = false;
     long mFreezeGcPending = 0;
     int mAppsFreezingScreen = 0;
 
+    int mLayoutSeq = 0;
+    
+    Configuration mCurConfiguration = new Configuration();
+    
     // This is held as long as we have the screen frozen, to give us time to
     // perform a rotation animation when turning off shows the lock screen which
     // changes the orientation.
@@ -1828,7 +1833,7 @@
             }
 
             if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {
-                attachedWindow = windowForClientLocked(null, attrs.token);
+                attachedWindow = windowForClientLocked(null, attrs.token, false);
                 if (attachedWindow == null) {
                     Log.w(TAG, "Attempted to add window with token that is not a window: "
                           + attrs.token + ".  Aborting.");
@@ -1988,6 +1993,10 @@
             if (localLOGV) Log.v(
                 TAG, "New client " + client.asBinder()
                 + ": window=" + win);
+            
+            if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked()) {
+                reportNewConfig = true;
+            }
         }
 
         // sendNewConfiguration() checks caller permissions so we must call it with
@@ -1997,14 +2006,6 @@
         final long origId = Binder.clearCallingIdentity();
         if (reportNewConfig) {
             sendNewConfiguration();
-        } else {
-            // Update Orientation after adding a window, only if the window needs to be
-            // displayed right away
-            if (win.isVisibleOrAdding()) {
-                if (updateOrientationFromAppTokensUnchecked(null, null) != null) {
-                    sendNewConfiguration();
-                }
-            }
         }
         Binder.restoreCallingIdentity(origId);
 
@@ -2013,7 +2014,7 @@
 
     public void removeWindow(Session session, IWindow client) {
         synchronized(mWindowMap) {
-            WindowState win = windowForClientLocked(session, client);
+            WindowState win = windowForClientLocked(session, client, false);
             if (win == null) {
                 return;
             }
@@ -2081,8 +2082,9 @@
         // Removing a visible window will effect the computed orientation
         // So just update orientation if needed.
         if (wasVisible && computeForcedAppOrientationLocked()
-                != mForcedAppOrientation) {
-            mH.sendMessage(mH.obtainMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION));
+                != mForcedAppOrientation
+                && updateOrientationFromAppTokensLocked()) {
+            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
         }
         updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
         Binder.restoreCallingIdentity(origId);
@@ -2177,7 +2179,7 @@
         long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mWindowMap) {
-                WindowState w = windowForClientLocked(session, client);
+                WindowState w = windowForClientLocked(session, client, false);
                 if ((w != null) && (w.mSurface != null)) {
                     if (SHOW_TRANSACTIONS) Log.i(TAG, ">>> OPEN TRANSACTION");
                     Surface.openTransaction();
@@ -2203,7 +2205,7 @@
         long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mWindowMap) {
-                WindowState w = windowForClientLocked(session, client);
+                WindowState w = windowForClientLocked(session, client, false);
                 if (w != null) {
                     w.mGivenInsetsPending = false;
                     w.mGivenContentInsets.set(contentInsets);
@@ -2221,7 +2223,7 @@
     public void getWindowDisplayFrame(Session session, IWindow client,
             Rect outDisplayFrame) {
         synchronized(mWindowMap) {
-            WindowState win = windowForClientLocked(session, client);
+            WindowState win = windowForClientLocked(session, client, false);
             if (win == null) {
                 outDisplayFrame.setEmpty();
                 return;
@@ -2291,11 +2293,11 @@
             Surface outSurface) {
         boolean displayed = false;
         boolean inTouchMode;
-        Configuration newConfig = null;
+        boolean configChanged;
         long origId = Binder.clearCallingIdentity();
 
         synchronized(mWindowMap) {
-            WindowState win = windowForClientLocked(session, client);
+            WindowState win = windowForClientLocked(session, client, false);
             if (win == null) {
                 return 0;
             }
@@ -2507,7 +2509,7 @@
             if (assignLayers) {
                 assignLayersLocked();
             }
-            newConfig = updateOrientationFromAppTokensLocked(null, null);
+            configChanged = updateOrientationFromAppTokensLocked();
             performLayoutAndPlaceSurfacesLocked();
             if (displayed && win.mIsWallpaper) {
                 updateWallpaperOffsetLocked(win, mDisplay.getWidth(),
@@ -2533,7 +2535,7 @@
             inTouchMode = mInTouchMode;
         }
 
-        if (newConfig != null) {
+        if (configChanged) {
             sendNewConfiguration();
         }
 
@@ -2546,7 +2548,7 @@
     public void finishDrawingWindow(Session session, IWindow client) {
         final long origId = Binder.clearCallingIdentity();
         synchronized(mWindowMap) {
-            WindowState win = windowForClientLocked(session, client);
+            WindowState win = windowForClientLocked(session, client, false);
             if (win != null && win.finishDrawingLocked()) {
                 if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
                     adjustWallpaperWindowsLocked();
@@ -2988,62 +2990,62 @@
     }
 
     public int getOrientationFromAppTokensLocked() {
-            int pos = mAppTokens.size() - 1;
-            int curGroup = 0;
-            int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-            boolean findingBehind = false;
-            boolean haveGroup = false;
-            boolean lastFullscreen = false;
-            while (pos >= 0) {
-                AppWindowToken wtoken = mAppTokens.get(pos);
-                pos--;
-                // if we're about to tear down this window and not seek for
-                // the behind activity, don't use it for orientation
-                if (!findingBehind
-                        && (!wtoken.hidden && wtoken.hiddenRequested)) {
+        int pos = mAppTokens.size() - 1;
+        int curGroup = 0;
+        int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+        boolean findingBehind = false;
+        boolean haveGroup = false;
+        boolean lastFullscreen = false;
+        while (pos >= 0) {
+            AppWindowToken wtoken = mAppTokens.get(pos);
+            pos--;
+            // if we're about to tear down this window and not seek for
+            // the behind activity, don't use it for orientation
+            if (!findingBehind
+                    && (!wtoken.hidden && wtoken.hiddenRequested)) {
+                continue;
+            }
+
+            if (!haveGroup) {
+                // We ignore any hidden applications on the top.
+                if (wtoken.hiddenRequested || wtoken.willBeHidden) {
                     continue;
                 }
-
-                if (!haveGroup) {
-                    // We ignore any hidden applications on the top.
-                    if (wtoken.hiddenRequested || wtoken.willBeHidden) {
-                        continue;
-                    }
-                    haveGroup = true;
-                    curGroup = wtoken.groupId;
-                    lastOrientation = wtoken.requestedOrientation;
-                } else if (curGroup != wtoken.groupId) {
-                    // If we have hit a new application group, and the bottom
-                    // of the previous group didn't explicitly say to use
-                    // the orientation behind it, and the last app was
-                    // full screen, then we'll stick with the
-                    // user's orientation.
-                    if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
-                            && lastFullscreen) {
-                        return lastOrientation;
-                    }
+                haveGroup = true;
+                curGroup = wtoken.groupId;
+                lastOrientation = wtoken.requestedOrientation;
+            } else if (curGroup != wtoken.groupId) {
+                // If we have hit a new application group, and the bottom
+                // of the previous group didn't explicitly say to use
+                // the orientation behind it, and the last app was
+                // full screen, then we'll stick with the
+                // user's orientation.
+                if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
+                        && lastFullscreen) {
+                    return lastOrientation;
                 }
-                int or = wtoken.requestedOrientation;
-                // If this application is fullscreen, and didn't explicitly say
-                // to use the orientation behind it, then just take whatever
-                // orientation it has and ignores whatever is under it.
-                lastFullscreen = wtoken.appFullscreen;
-                if (lastFullscreen
-                        && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
-                    return or;
-                }
-                // If this application has requested an explicit orientation,
-                // then use it.
-                if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ||
-                        or == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ||
-                        or == ActivityInfo.SCREEN_ORIENTATION_SENSOR ||
-                        or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR ||
-                        or == ActivityInfo.SCREEN_ORIENTATION_USER) {
-                    return or;
-                }
-                findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
             }
-            return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+            int or = wtoken.requestedOrientation;
+            // If this application is fullscreen, and didn't explicitly say
+            // to use the orientation behind it, then just take whatever
+            // orientation it has and ignores whatever is under it.
+            lastFullscreen = wtoken.appFullscreen;
+            if (lastFullscreen
+                    && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
+                return or;
+            }
+            // If this application has requested an explicit orientation,
+            // then use it.
+            if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ||
+                    or == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ||
+                    or == ActivityInfo.SCREEN_ORIENTATION_SENSOR ||
+                    or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR ||
+                    or == ActivityInfo.SCREEN_ORIENTATION_USER) {
+                return or;
+            }
+            findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
+        }
+        return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
     }
 
     public Configuration updateOrientationFromAppTokens(
@@ -3053,81 +3055,75 @@
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
         }
 
-        Configuration config;
+        Configuration config = null;
         long ident = Binder.clearCallingIdentity();
-        config = updateOrientationFromAppTokensUnchecked(currentConfig,
-                freezeThisOneIfNeeded);
+        
+        synchronized(mWindowMap) {
+            if (updateOrientationFromAppTokensLocked()) {
+                if (freezeThisOneIfNeeded != null) {
+                    AppWindowToken wtoken = findAppWindowToken(
+                            freezeThisOneIfNeeded);
+                    if (wtoken != null) {
+                        startAppFreezingScreenLocked(wtoken,
+                                ActivityInfo.CONFIG_ORIENTATION);
+                    }
+                }
+                config = computeNewConfigurationLocked();
+                
+            } else if (currentConfig != null) {
+                // No obvious action we need to take, but if our current
+                // state mismatches the activity maanager's, update it
+                mTempConfiguration.setToDefaults();
+                if (computeNewConfigurationLocked(mTempConfiguration)) {
+                    if (currentConfig.diff(mTempConfiguration) != 0) {
+                        mWaitingForConfig = true;
+                        mLayoutNeeded = true;
+                        startFreezingDisplayLocked();
+                        config = new Configuration(mTempConfiguration);
+                    }
+                }
+            }
+        }
+        
         Binder.restoreCallingIdentity(ident);
         return config;
     }
 
-    Configuration updateOrientationFromAppTokensUnchecked(
-            Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
-        Configuration config;
-        synchronized(mWindowMap) {
-            config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded);
-            if (config != null) {
-                mLayoutNeeded = true;
-                performLayoutAndPlaceSurfacesLocked();
-            }
-        }
-        return config;
-    }
-
     /*
+     * Determine the new desired orientation of the display, returning
+     * a non-null new Configuration if it has changed from the current
+     * orientation.  IF TRUE IS RETURNED SOMEONE MUST CALL
+     * setNewConfiguration() TO TELL THE WINDOW MANAGER IT CAN UNFREEZE THE
+     * SCREEN.  This will typically be done for you if you call
+     * sendNewConfiguration().
+     * 
      * The orientation is computed from non-application windows first. If none of
      * the non-application windows specify orientation, the orientation is computed from
      * application tokens.
      * @see android.view.IWindowManager#updateOrientationFromAppTokens(
      * android.os.IBinder)
      */
-    Configuration updateOrientationFromAppTokensLocked(
-            Configuration appConfig, IBinder freezeThisOneIfNeeded) {
+    boolean updateOrientationFromAppTokensLocked() {
         boolean changed = false;
         long ident = Binder.clearCallingIdentity();
         try {
             int req = computeForcedAppOrientationLocked();
 
             if (req != mForcedAppOrientation) {
-                changed = true;
                 mForcedAppOrientation = req;
                 //send a message to Policy indicating orientation change to take
                 //action like disabling/enabling sensors etc.,
                 mPolicy.setCurrentOrientationLw(req);
-            }
-
-            if (changed) {
-                changed = setRotationUncheckedLocked(
-                        WindowManagerPolicy.USE_LAST_ROTATION,
-                        mLastRotationFlags & (~Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE));
-                if (changed) {
-                    if (freezeThisOneIfNeeded != null) {
-                        AppWindowToken wtoken = findAppWindowToken(
-                                freezeThisOneIfNeeded);
-                        if (wtoken != null) {
-                            startAppFreezingScreenLocked(wtoken,
-                                    ActivityInfo.CONFIG_ORIENTATION);
-                        }
-                    }
-                    return computeNewConfigurationLocked();
+                if (setRotationUncheckedLocked(WindowManagerPolicy.USE_LAST_ROTATION,
+                        mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE)) {
+                    changed = true;
                 }
             }
 
-            // No obvious action we need to take, but if our current
-            // state mismatches the activity maanager's, update it
-            if (appConfig != null) {
-                mTempConfiguration.setToDefaults();
-                if (computeNewConfigurationLocked(mTempConfiguration)) {
-                    if (appConfig.diff(mTempConfiguration) != 0) {
-                        return new Configuration(mTempConfiguration);
-                    }
-                }
-            }
+            return changed;
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
-
-        return null;
     }
 
     int computeForcedAppOrientationLocked() {
@@ -3138,6 +3134,19 @@
         return req;
     }
 
+    public void setNewConfiguration(Configuration config) {
+        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
+                "setNewConfiguration()")) {
+            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
+        }
+
+        synchronized(mWindowMap) {
+            mCurConfiguration = new Configuration(config);
+            mWaitingForConfig = false;
+            performLayoutAndPlaceSurfacesLocked();
+        }
+    }
+    
     public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "setAppOrientation()")) {
@@ -3648,9 +3657,7 @@
                     mLayoutNeeded = true;
                     performLayoutAndPlaceSurfacesLocked();
                 }
-                if (mAppsFreezingScreen == 0 && !mWindowsFreezingScreen) {
-                    stopFreezingDisplayLocked();
-                }
+                stopFreezingDisplayLocked();
             }
         }
     }
@@ -4403,20 +4410,21 @@
             changed = setRotationUncheckedLocked(rotation, animFlags);
         }
 
-        if (changed) {
-            sendNewConfiguration();
-            synchronized(mWindowMap) {
-                mLayoutNeeded = true;
-                performLayoutAndPlaceSurfacesLocked();
-            }
-        } else if (alwaysSendConfiguration) {
-            //update configuration ignoring orientation change
+        if (changed || alwaysSendConfiguration) {
             sendNewConfiguration();
         }
 
         Binder.restoreCallingIdentity(origId);
     }
 
+    /**
+     * Apply a new rotation to the screen, respecting the requests of
+     * applications.  Use WindowManagerPolicy.USE_LAST_ROTATION to simply
+     * re-evaluate the desired rotation.
+     * 
+     * Returns null if the rotation has been changed.  In this case YOU
+     * MUST CALL setNewConfiguration() TO UNFREEZE THE SCREEN.
+     */
     public boolean setRotationUncheckedLocked(int rotation, int animFlags) {
         boolean changed;
         if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) {
@@ -4442,6 +4450,8 @@
             mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
             mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),
                     2000);
+            mWaitingForConfig = true;
+            mLayoutNeeded = true;
             startFreezingDisplayLocked();
             Log.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
             mQueue.setOrientation(rotation);
@@ -6707,7 +6717,8 @@
                 long ident = Binder.clearCallingIdentity();
                 try {
                     return mPolicy.performHapticFeedbackLw(
-                            windowForClientLocked(this, window), effectId, always);
+                            windowForClientLocked(this, window, true),
+                            effectId, always);
                 } finally {
                     Binder.restoreCallingIdentity(ident);
                 }
@@ -6718,7 +6729,8 @@
             synchronized(mWindowMap) {
                 long ident = Binder.clearCallingIdentity();
                 try {
-                    setWindowWallpaperPositionLocked(windowForClientLocked(this, window),
+                    setWindowWallpaperPositionLocked(
+                            windowForClientLocked(this, window, true),
                             x, y, xStep, yStep);
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -6736,7 +6748,7 @@
                 long ident = Binder.clearCallingIdentity();
                 try {
                     return sendWindowWallpaperCommandLocked(
-                            windowForClientLocked(this, window),
+                            windowForClientLocked(this, window, true),
                             action, x, y, z, extras, sync);
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -6852,6 +6864,10 @@
 
         WindowState mNextOutsideTouch;
 
+        int mLayoutSeq = -1;
+        
+        Configuration mConfiguration = null;
+        
         // Actual frame shown on-screen (may be modified by animation)
         final Rect mShownFrame = new Rect();
         final Rect mLastShownFrame = new Rect();
@@ -7980,7 +7996,7 @@
             public void binderDied() {
                 try {
                     synchronized(mWindowMap) {
-                        WindowState win = windowForClientLocked(mSession, mClient);
+                        WindowState win = windowForClientLocked(mSession, mClient, false);
                         Log.i(TAG, "WIN DEATH: " + win);
                         if (win != null) {
                             removeWindowLocked(mSession, win);
@@ -8056,8 +8072,6 @@
         }
 
         void dump(PrintWriter pw, String prefix) {
-            StringBuilder sb = new StringBuilder(64);
-
             pw.print(prefix); pw.print("mSession="); pw.print(mSession);
                     pw.print(" mClient="); pw.println(mClient.asBinder());
             pw.print(prefix); pw.print("mAttrs="); pw.println(mAttrs);
@@ -8105,7 +8119,8 @@
                 pw.print(prefix); pw.print("mRelayoutCalled="); pw.println(mRelayoutCalled);
             }
             pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
-                    pw.print(" h="); pw.println(mRequestedHeight);
+                    pw.print(" h="); pw.print(mRequestedHeight);
+                    pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
             if (mXOffset != 0 || mYOffset != 0) {
                 pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset);
                         pw.print(" y="); pw.println(mYOffset);
@@ -8119,6 +8134,7 @@
                 pw.print(prefix); pw.print("mTouchableInsets="); pw.print(mTouchableInsets);
                         pw.print(" mGivenInsetsPending="); pw.println(mGivenInsetsPending);
             }
+            pw.print(prefix); pw.print("mConfiguration="); pw.println(mConfiguration);
             pw.print(prefix); pw.print("mShownFrame=");
                     mShownFrame.printShortString(pw);
                     pw.print(" last="); mLastShownFrame.printShortString(pw);
@@ -8693,7 +8709,7 @@
         public static final int FORCE_GC = 15;
         public static final int ENABLE_SCREEN = 16;
         public static final int APP_FREEZE_TIMEOUT = 17;
-        public static final int COMPUTE_AND_SEND_NEW_CONFIGURATION = 18;
+        public static final int SEND_NEW_CONFIGURATION = 18;
 
         private Session mLastReportedHold;
 
@@ -9019,10 +9035,9 @@
                     break;
                 }
 
-                case COMPUTE_AND_SEND_NEW_CONFIGURATION: {
-                    if (updateOrientationFromAppTokensUnchecked(null, null) != null) {
-                        sendNewConfiguration();
-                    }
+                case SEND_NEW_CONFIGURATION: {
+                    removeMessages(SEND_NEW_CONFIGURATION);
+                    sendNewConfiguration();
                     break;
                 }
 
@@ -9064,23 +9079,33 @@
     // Internals
     // -------------------------------------------------------------
 
-    final WindowState windowForClientLocked(Session session, IWindow client) {
-        return windowForClientLocked(session, client.asBinder());
+    final WindowState windowForClientLocked(Session session, IWindow client,
+            boolean throwOnError) {
+        return windowForClientLocked(session, client.asBinder(), throwOnError);
     }
 
-    final WindowState windowForClientLocked(Session session, IBinder client) {
+    final WindowState windowForClientLocked(Session session, IBinder client,
+            boolean throwOnError) {
         WindowState win = mWindowMap.get(client);
         if (localLOGV) Log.v(
             TAG, "Looking up client " + client + ": " + win);
         if (win == null) {
-            RuntimeException ex = new RuntimeException();
-            Log.w(TAG, "Requested window " + client + " does not exist", ex);
+            RuntimeException ex = new IllegalArgumentException(
+                    "Requested window " + client + " does not exist");
+            if (throwOnError) {
+                throw ex;
+            }
+            Log.w(TAG, "Failed looking up window", ex);
             return null;
         }
         if (session != null && win.mSession != session) {
-            RuntimeException ex = new RuntimeException();
-            Log.w(TAG, "Requested window " + client + " is in session " +
-                  win.mSession + ", not " + session, ex);
+            RuntimeException ex = new IllegalArgumentException(
+                    "Requested window " + client + " is in session " +
+                    win.mSession + ", not " + session);
+            if (throwOnError) {
+                throw ex;
+            }
+            Log.w(TAG, "Failed looking up window", ex);
             return null;
         }
 
@@ -9183,6 +9208,13 @@
             return;
         }
 
+        if (mWaitingForConfig) {
+            // Our configuration has changed (most likely rotation), but we
+            // don't yet have the complete configuration to report to
+            // applications.  Don't do any window layout until we have it.
+            return;
+        }
+        
         boolean recoveringMemory = false;
         if (mForceRemoves != null) {
             recoveringMemory = true;
@@ -9249,6 +9281,10 @@
         while (mLayoutNeeded) {
             mPolicy.beginLayoutLw(dw, dh);
 
+            int seq = mLayoutSeq+1;
+            if (seq < 0) seq = 0;
+            mLayoutSeq = seq;
+            
             // First perform layout of any root windows (not attached
             // to another window).
             int topAttached = -1;
@@ -9266,7 +9302,7 @@
                         || win.mAttachedHidden
                         || win.mExiting || win.mDestroying;
 
-                if (win.mLayoutAttached) {
+                if (!win.mLayoutAttached) {
                     if (DEBUG_LAYOUT) Log.v(TAG, "First pass " + win
                             + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
                             + " mLayoutAttached=" + win.mLayoutAttached);
@@ -9286,6 +9322,7 @@
                 if (!gone || !win.mHaveFrame) {
                     if (!win.mLayoutAttached) {
                         mPolicy.layoutWindowLw(win, win.mAttrs, null);
+                        win.mLayoutSeq = seq;
                         if (DEBUG_LAYOUT) Log.v(TAG, "-> mFrame="
                                 + win.mFrame + " mContainingFrame="
                                 + win.mContainingFrame + " mDisplayFrame="
@@ -9316,6 +9353,7 @@
                     if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
                             || !win.mHaveFrame) {
                         mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
+                        win.mLayoutSeq = seq;
                         if (DEBUG_LAYOUT) Log.v(TAG, "-> mFrame="
                                 + win.mFrame + " mContainingFrame="
                                 + win.mContainingFrame + " mDisplayFrame="
@@ -9336,11 +9374,8 @@
                 Log.w(TAG, "Layout repeat aborted after too many iterations");
                 mLayoutNeeded = false;
                 if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
-                    Configuration newConfig = updateOrientationFromAppTokensLocked(
-                            null, null);
-                    if (newConfig != null) {
-                        mLayoutNeeded = true;
-                        mH.sendEmptyMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION);
+                    if (updateOrientationFromAppTokensLocked()) {
+                        mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
                     }
                 }
             } else {
@@ -9349,10 +9384,8 @@
                 repeats++;
                 if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
                     if (DEBUG_LAYOUT) Log.v(TAG, "Computing new config from layout");
-                    Configuration newConfig = updateOrientationFromAppTokensLocked(
-                            null, null);
-                    if (newConfig != null) {
-                        mH.sendEmptyMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION);
+                    if (updateOrientationFromAppTokensLocked()) {
+                        mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
                     }
                 }
             }
@@ -9996,14 +10029,22 @@
                             }
                         }
                     }
-                    if (!w.mAppFreezing) {
+                    if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
                         w.mContentInsetsChanged =
                             !w.mLastContentInsets.equals(w.mContentInsets);
                         w.mVisibleInsetsChanged =
                             !w.mLastVisibleInsets.equals(w.mVisibleInsets);
+                        boolean configChanged =
+                            w.mConfiguration != mCurConfiguration
+                            && (w.mConfiguration == null
+                                    || mCurConfiguration.diff(w.mConfiguration) != 0);
+                        if (localLOGV) Log.v(TAG, "Resizing " + w
+                                + ": configChanged=" + configChanged
+                                + " last=" + w.mLastFrame + " frame=" + w.mFrame);
                         if (!w.mLastFrame.equals(w.mFrame)
                                 || w.mContentInsetsChanged
-                                || w.mVisibleInsetsChanged) {
+                                || w.mVisibleInsetsChanged
+                                || configChanged) {
                             w.mLastFrame.set(w.mFrame);
                             w.mLastContentInsets.set(w.mContentInsets);
                             w.mLastVisibleInsets.set(w.mVisibleInsets);
@@ -10014,7 +10055,7 @@
                                 if (DEBUG_ORIENTATION) Log.v(TAG,
                                         "Resizing while display frozen: " + w);
                                 w.mOrientationChanging = true;
-                                if (mWindowsFreezingScreen) {
+                                if (!mWindowsFreezingScreen) {
                                     mWindowsFreezingScreen = true;
                                     // XXX should probably keep timeout from
                                     // when we first froze the display.
@@ -10327,9 +10368,7 @@
                 mWindowsFreezingScreen = false;
                 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
             }
-            if (mAppsFreezingScreen == 0) {
-                stopFreezingDisplayLocked();
-            }
+            stopFreezingDisplayLocked();
         }
 
         i = mResizingWindows.size();
@@ -10340,9 +10379,20 @@
                 try {
                     if (DEBUG_ORIENTATION) Log.v(TAG, "Reporting new frame to "
                             + win + ": " + win.mFrame);
+                    boolean configChanged =
+                        win.mConfiguration != mCurConfiguration
+                        && (win.mConfiguration == null
+                                || mCurConfiguration.diff(win.mConfiguration) != 0);
+                    win.mConfiguration = mCurConfiguration;
+                    if (DEBUG_ORIENTATION && configChanged) {
+                        Log.i(TAG, "Sending new config to window " + win + ": "
+                                + win.mFrame.width() + "x" + win.mFrame.height()
+                                + " / " + win.mConfiguration);
+                    }
                     win.mClient.resized(win.mFrame.width(),
                             win.mFrame.height(), win.mLastContentInsets,
-                            win.mLastVisibleInsets, win.mDrawPending);
+                            win.mLastVisibleInsets, win.mDrawPending,
+                            configChanged ? win.mConfiguration : null);
                     win.mContentInsetsChanged = false;
                     win.mVisibleInsetsChanged = false;
                 } catch (RemoteException e) {
@@ -10732,6 +10782,10 @@
             return;
         }
 
+        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen) {
+            return;
+        }
+        
         mDisplayFrozen = false;
         mH.removeMessages(H.APP_FREEZE_TIMEOUT);
         if (PROFILE_ORIENTATION) {
@@ -10921,7 +10975,9 @@
                 pw.print("  mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
                 pw.print("  mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
             }
-            pw.print("  mInTouchMode="); pw.println(mInTouchMode);
+            pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
+            pw.print("  mInTouchMode="); pw.print(mInTouchMode);
+                    pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
             pw.print("  mSystemBooted="); pw.print(mSystemBooted);
                     pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
             pw.print("  mLayoutNeeded="); pw.print(mLayoutNeeded);
@@ -10939,7 +10995,8 @@
                     pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
             pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
                     pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
-                    pw.print(" mAppsFreezingScreen="); pw.println(mAppsFreezingScreen);
+                    pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen);
+                    pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig);
             pw.print("  mRotation="); pw.print(mRotation);
                     pw.print(", mForcedAppOrientation="); pw.print(mForcedAppOrientation);
                     pw.print(", mRequestedRotation="); pw.println(mRequestedRotation);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 3ecfd8a..45c3f00 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -766,6 +766,12 @@
     Configuration mConfiguration = new Configuration();
 
     /**
+     * Current sequencing integer of the configuration, for skipping old
+     * configurations.
+     */
+    int mConfigurationSeq = 0;
+    
+    /**
      * Hardware-reported OpenGLES version.
      */
     final int GL_ES_VERSION;
@@ -2662,20 +2668,6 @@
                         mConfiguration,
                         next.mayFreezeScreenLocked(next.app) ? next : null);
                 if (config != null) {
-                    /*
-                     * Explicitly restore the locale to the one from the
-                     * old configuration, since the one that comes back from
-                     * the window manager has the default (boot) locale.
-                     *
-                     * It looks like previously the locale picker only worked
-                     * by coincidence: usually it would do its setting of
-                     * the locale after the activity transition, so it didn't
-                     * matter that this lost it.  With the synchronized
-                     * block now keeping them from happening at the same time,
-                     * this one always would happen second and undo what the
-                     * locale picker had just done.
-                     */
-                    config.locale = mConfiguration.locale;
                     next.frozenBeforeDestroy = true;
                 }
                 updated = updateConfigurationLocked(config, next);
@@ -4638,11 +4630,12 @@
         if (activity != null && activity.shortComponentName != null) {
             info.append(" (").append(activity.shortComponentName).append(")");
         }
+        info.append("\n");
         if (annotation != null) {
-            info.append("\nReason: ").append(annotation).append("\n");
+            info.append("Reason: ").append(annotation).append("\n");
         }
         if (parent != null && parent != activity) {
-            info.append("\nParent: ").append(parent.shortComponentName);
+            info.append("Parent: ").append(parent.shortComponentName).append("\n");
         }
 
         String cpuInfo = null;
@@ -8346,7 +8339,9 @@
             mAlwaysFinishActivities = alwaysFinishActivities;
             // This happens before any activities are started, so we can
             // change mConfiguration in-place.
+            mConfiguration.locale = Locale.getDefault();
             mConfiguration.updateFrom(configuration);
+            mConfigurationSeq = mConfiguration.seq = 1;
             if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
         }
     }
@@ -13089,6 +13084,11 @@
                                      values.userSetLocale);
                 }
 
+                mConfigurationSeq++;
+                if (mConfigurationSeq <= 0) {
+                    mConfigurationSeq = 1;
+                }
+                newConfig.seq = mConfigurationSeq;
                 mConfiguration = newConfig;
                 Log.i(TAG, "Config changed: " + newConfig);
                 
@@ -13145,6 +13145,10 @@
             }
         }
         
+        if (values != null && mWindowManager != null) {
+            mWindowManager.setNewConfiguration(mConfiguration);
+        }
+        
         return kept;
     }
 
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 89761a8..2f2cc32 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -29,6 +29,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.util.Log;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -267,6 +268,9 @@
                         int[] outId = new int[1];
                         inm.enqueueNotification(localPackageName, localForegroundId,
                                 localForegroundNoti, outId);
+                    } catch (RuntimeException e) {
+                        Log.w(ActivityManagerService.TAG, "Error showing notification for service",
+                            e);
                     } catch (RemoteException e) {
                     }
                 }
@@ -288,6 +292,9 @@
                     }
                     try {
                         inm.cancelNotification(localPackageName, localForegroundId);
+                    } catch (RuntimeException e) {
+                        Log.w(ActivityManagerService.TAG, "Error canceling notification for"
+                            + " service", e);
                     } catch (RemoteException e) {
                     }
                 }
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index c7c3335..dab8b72 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -972,7 +972,7 @@
             return;
         }
 
-        prepareTracking(0);
+        prepareTracking(0, true);
         performFling(0, 2000.0f, true);
     }
     
@@ -980,7 +980,9 @@
         if (SPEW) {
             Log.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
                     + " mExpandedVisible=" + mExpandedVisible
+                    + " mExpanded=" + mExpanded
                     + " mAnimating=" + mAnimating
+                    + " mAnimY=" + mAnimY
                     + " mAnimVel=" + mAnimVel);
         }
         
@@ -988,12 +990,16 @@
             return;
         }
 
+        int y;
         if (mAnimating) {
-            return;
+            y = (int)mAnimY;
+        } else {
+            y = mDisplay.getHeight()-1;
         }
-
-        int y = mDisplay.getHeight()-1;
-        prepareTracking(y);
+        // Let the fling think that we're open so it goes in the right direction
+        // and doesn't try to re-open the windowshade.
+        mExpanded = true;
+        prepareTracking(y, false);
         performFling(y, -2000.0f, true);
     }
     
@@ -1108,10 +1114,9 @@
         }
     }
     
-    void prepareTracking(int y) {
+    void prepareTracking(int y, boolean opening) {
         mTracking = true;
         mVelocityTracker = VelocityTracker.obtain();
-        boolean opening = !mExpanded;
         if (opening) {
             mAnimAccel = 2000.0f;
             mAnimVel = 200;
@@ -1199,10 +1204,11 @@
     }
     
     boolean interceptTouchEvent(MotionEvent event) {
-        if (SPEW) Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event);
+        if (SPEW) Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
+                + mDisabled);
 
         if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
-            return true;
+            return false;
         }
         
         final int statusBarSize = mStatusBarView.getHeight();
@@ -1218,7 +1224,7 @@
             }
             if ((!mExpanded && y < hitSize) ||
                     (mExpanded && y > (mDisplay.getHeight()-hitSize))) {
-                prepareTracking(y);
+                prepareTracking(y, !mExpanded); // opening if we're not already fully visible
                 mVelocityTracker.addMovement(event);
             }
         } else if (mTracking) {
@@ -1679,9 +1685,7 @@
         if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
             if ((net & StatusBarManager.DISABLE_EXPAND) != 0) {
                 Log.d(TAG, "DISABLE_EXPAND: yes");
-                mAnimating = false;
-                updateExpandedViewPos(0);
-                performCollapse();
+                animateCollapse();
             }
         }
         if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 586f63f..6797f78 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1654,7 +1654,7 @@
         if (DBG) log("processPlusCodeWithinNanp,networkDialStr=" + networkDialStr);
         // If there is a plus sign at the beginning of the dial string,
         // Convert the plus sign to the default IDP since it's an international number
-        if (networkDialStr != null &
+        if (networkDialStr != null &&
             networkDialStr.charAt(0) == PLUS_SIGN_CHAR &&
             networkDialStr.length() > 1) {
             String newStr = networkDialStr.substring(1);
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
index 42167c7..962e96c 100644
--- a/test-runner/Android.mk
+++ b/test-runner/Android.mk
@@ -18,10 +18,13 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := core framework
 
 LOCAL_MODULE:= android.test.runner
 
 include $(BUILD_JAVA_LIBRARY)
+
+# additionally, build unit tests in a separate .apk
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/test-runner/android/test/ActivityInstrumentationTestCase.java b/test-runner/src/android/test/ActivityInstrumentationTestCase.java
similarity index 100%
rename from test-runner/android/test/ActivityInstrumentationTestCase.java
rename to test-runner/src/android/test/ActivityInstrumentationTestCase.java
diff --git a/test-runner/android/test/ActivityInstrumentationTestCase2.java b/test-runner/src/android/test/ActivityInstrumentationTestCase2.java
similarity index 100%
rename from test-runner/android/test/ActivityInstrumentationTestCase2.java
rename to test-runner/src/android/test/ActivityInstrumentationTestCase2.java
diff --git a/test-runner/android/test/ActivityTestCase.java b/test-runner/src/android/test/ActivityTestCase.java
similarity index 100%
rename from test-runner/android/test/ActivityTestCase.java
rename to test-runner/src/android/test/ActivityTestCase.java
diff --git a/test-runner/android/test/ActivityUnitTestCase.java b/test-runner/src/android/test/ActivityUnitTestCase.java
similarity index 100%
rename from test-runner/android/test/ActivityUnitTestCase.java
rename to test-runner/src/android/test/ActivityUnitTestCase.java
diff --git a/test-runner/android/test/AndroidTestRunner.java b/test-runner/src/android/test/AndroidTestRunner.java
similarity index 100%
rename from test-runner/android/test/AndroidTestRunner.java
rename to test-runner/src/android/test/AndroidTestRunner.java
diff --git a/test-runner/android/test/ApplicationTestCase.java b/test-runner/src/android/test/ApplicationTestCase.java
similarity index 100%
rename from test-runner/android/test/ApplicationTestCase.java
rename to test-runner/src/android/test/ApplicationTestCase.java
diff --git a/test-runner/android/test/AssertionFailedError.java b/test-runner/src/android/test/AssertionFailedError.java
similarity index 100%
rename from test-runner/android/test/AssertionFailedError.java
rename to test-runner/src/android/test/AssertionFailedError.java
diff --git a/test-runner/android/test/BundlePrinter.java b/test-runner/src/android/test/BundlePrinter.java
similarity index 100%
rename from test-runner/android/test/BundlePrinter.java
rename to test-runner/src/android/test/BundlePrinter.java
diff --git a/test-runner/android/test/BundleTestListener.java b/test-runner/src/android/test/BundleTestListener.java
similarity index 100%
rename from test-runner/android/test/BundleTestListener.java
rename to test-runner/src/android/test/BundleTestListener.java
diff --git a/test-runner/android/test/ClassPathPackageInfo.java b/test-runner/src/android/test/ClassPathPackageInfo.java
similarity index 100%
rename from test-runner/android/test/ClassPathPackageInfo.java
rename to test-runner/src/android/test/ClassPathPackageInfo.java
diff --git a/test-runner/android/test/ClassPathPackageInfoSource.java b/test-runner/src/android/test/ClassPathPackageInfoSource.java
similarity index 100%
rename from test-runner/android/test/ClassPathPackageInfoSource.java
rename to test-runner/src/android/test/ClassPathPackageInfoSource.java
diff --git a/test-runner/android/test/ComparisonFailure.java b/test-runner/src/android/test/ComparisonFailure.java
similarity index 100%
rename from test-runner/android/test/ComparisonFailure.java
rename to test-runner/src/android/test/ComparisonFailure.java
diff --git a/test-runner/android/test/DatabaseTestUtils.java b/test-runner/src/android/test/DatabaseTestUtils.java
similarity index 100%
rename from test-runner/android/test/DatabaseTestUtils.java
rename to test-runner/src/android/test/DatabaseTestUtils.java
diff --git a/test-runner/android/test/InstrumentationCoreTestRunner.java b/test-runner/src/android/test/InstrumentationCoreTestRunner.java
similarity index 100%
rename from test-runner/android/test/InstrumentationCoreTestRunner.java
rename to test-runner/src/android/test/InstrumentationCoreTestRunner.java
diff --git a/test-runner/android/test/InstrumentationTestRunner.java b/test-runner/src/android/test/InstrumentationTestRunner.java
similarity index 98%
rename from test-runner/android/test/InstrumentationTestRunner.java
rename to test-runner/src/android/test/InstrumentationTestRunner.java
index 3e9cd9f..4ae98e6 100644
--- a/test-runner/android/test/InstrumentationTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationTestRunner.java
@@ -480,8 +480,11 @@
             // needed
             mResults.putString(REPORT_KEY_COVERAGE_PATH, coverageFilePath);
             // also output a more user friendly msg
+            final String currentStream = mResults.getString(
+                    Instrumentation.REPORT_KEY_STREAMRESULT);
             mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
-                String.format("Generated code coverage data to %s", coverageFilePath));
+                String.format("%s\nGenerated code coverage data to %s", currentStream,
+                coverageFilePath));
         } catch (ClassNotFoundException e) {
             reportEmmaError("Is emma jar on classpath?", e);
         } catch (SecurityException e) {
diff --git a/test-runner/android/test/InstrumentationUtils.java b/test-runner/src/android/test/InstrumentationUtils.java
similarity index 100%
rename from test-runner/android/test/InstrumentationUtils.java
rename to test-runner/src/android/test/InstrumentationUtils.java
diff --git a/test-runner/android/test/IsolatedContext.java b/test-runner/src/android/test/IsolatedContext.java
similarity index 100%
rename from test-runner/android/test/IsolatedContext.java
rename to test-runner/src/android/test/IsolatedContext.java
diff --git a/test-runner/android/test/LaunchPerformanceBase.java b/test-runner/src/android/test/LaunchPerformanceBase.java
similarity index 100%
rename from test-runner/android/test/LaunchPerformanceBase.java
rename to test-runner/src/android/test/LaunchPerformanceBase.java
diff --git a/test-runner/android/test/MoreAsserts.java b/test-runner/src/android/test/MoreAsserts.java
similarity index 100%
rename from test-runner/android/test/MoreAsserts.java
rename to test-runner/src/android/test/MoreAsserts.java
diff --git a/test-runner/android/test/NoExecTestResult.java b/test-runner/src/android/test/NoExecTestResult.java
similarity index 100%
rename from test-runner/android/test/NoExecTestResult.java
rename to test-runner/src/android/test/NoExecTestResult.java
diff --git a/test-runner/android/test/PackageInfoSources.java b/test-runner/src/android/test/PackageInfoSources.java
similarity index 100%
rename from test-runner/android/test/PackageInfoSources.java
rename to test-runner/src/android/test/PackageInfoSources.java
diff --git a/test-runner/android/test/PerformanceCollectorTestCase.java b/test-runner/src/android/test/PerformanceCollectorTestCase.java
similarity index 100%
rename from test-runner/android/test/PerformanceCollectorTestCase.java
rename to test-runner/src/android/test/PerformanceCollectorTestCase.java
diff --git a/test-runner/android/test/PerformanceTestBase.java b/test-runner/src/android/test/PerformanceTestBase.java
similarity index 100%
rename from test-runner/android/test/PerformanceTestBase.java
rename to test-runner/src/android/test/PerformanceTestBase.java
diff --git a/test-runner/android/test/ProviderTestCase.java b/test-runner/src/android/test/ProviderTestCase.java
similarity index 100%
rename from test-runner/android/test/ProviderTestCase.java
rename to test-runner/src/android/test/ProviderTestCase.java
diff --git a/test-runner/android/test/ProviderTestCase2.java b/test-runner/src/android/test/ProviderTestCase2.java
similarity index 100%
rename from test-runner/android/test/ProviderTestCase2.java
rename to test-runner/src/android/test/ProviderTestCase2.java
diff --git a/test-runner/android/test/RenamingDelegatingContext.java b/test-runner/src/android/test/RenamingDelegatingContext.java
similarity index 100%
rename from test-runner/android/test/RenamingDelegatingContext.java
rename to test-runner/src/android/test/RenamingDelegatingContext.java
diff --git a/test-runner/android/test/ServiceLocator.java b/test-runner/src/android/test/ServiceLocator.java
similarity index 100%
rename from test-runner/android/test/ServiceLocator.java
rename to test-runner/src/android/test/ServiceLocator.java
diff --git a/test-runner/android/test/ServiceTestCase.java b/test-runner/src/android/test/ServiceTestCase.java
similarity index 100%
rename from test-runner/android/test/ServiceTestCase.java
rename to test-runner/src/android/test/ServiceTestCase.java
diff --git a/test-runner/android/test/SimpleCache.java b/test-runner/src/android/test/SimpleCache.java
similarity index 100%
rename from test-runner/android/test/SimpleCache.java
rename to test-runner/src/android/test/SimpleCache.java
diff --git a/test-runner/android/test/SingleLaunchActivityTestCase.java b/test-runner/src/android/test/SingleLaunchActivityTestCase.java
similarity index 100%
rename from test-runner/android/test/SingleLaunchActivityTestCase.java
rename to test-runner/src/android/test/SingleLaunchActivityTestCase.java
diff --git a/test-runner/android/test/SyncBaseInstrumentation.java b/test-runner/src/android/test/SyncBaseInstrumentation.java
similarity index 100%
rename from test-runner/android/test/SyncBaseInstrumentation.java
rename to test-runner/src/android/test/SyncBaseInstrumentation.java
diff --git a/test-runner/android/test/TestBrowserActivity.java b/test-runner/src/android/test/TestBrowserActivity.java
similarity index 100%
rename from test-runner/android/test/TestBrowserActivity.java
rename to test-runner/src/android/test/TestBrowserActivity.java
diff --git a/test-runner/android/test/TestBrowserController.java b/test-runner/src/android/test/TestBrowserController.java
similarity index 100%
rename from test-runner/android/test/TestBrowserController.java
rename to test-runner/src/android/test/TestBrowserController.java
diff --git a/test-runner/android/test/TestBrowserControllerImpl.java b/test-runner/src/android/test/TestBrowserControllerImpl.java
similarity index 100%
rename from test-runner/android/test/TestBrowserControllerImpl.java
rename to test-runner/src/android/test/TestBrowserControllerImpl.java
diff --git a/test-runner/android/test/TestBrowserView.java b/test-runner/src/android/test/TestBrowserView.java
similarity index 100%
rename from test-runner/android/test/TestBrowserView.java
rename to test-runner/src/android/test/TestBrowserView.java
diff --git a/test-runner/android/test/TestCase.java b/test-runner/src/android/test/TestCase.java
similarity index 100%
rename from test-runner/android/test/TestCase.java
rename to test-runner/src/android/test/TestCase.java
diff --git a/test-runner/android/test/TestCaseUtil.java b/test-runner/src/android/test/TestCaseUtil.java
similarity index 100%
rename from test-runner/android/test/TestCaseUtil.java
rename to test-runner/src/android/test/TestCaseUtil.java
diff --git a/test-runner/android/test/TestListActivity.java b/test-runner/src/android/test/TestListActivity.java
similarity index 100%
rename from test-runner/android/test/TestListActivity.java
rename to test-runner/src/android/test/TestListActivity.java
diff --git a/test-runner/android/test/TestPrinter.java b/test-runner/src/android/test/TestPrinter.java
similarity index 100%
rename from test-runner/android/test/TestPrinter.java
rename to test-runner/src/android/test/TestPrinter.java
diff --git a/test-runner/android/test/TestRecorder.java b/test-runner/src/android/test/TestRecorder.java
similarity index 100%
rename from test-runner/android/test/TestRecorder.java
rename to test-runner/src/android/test/TestRecorder.java
diff --git a/test-runner/android/test/TestRunner.java b/test-runner/src/android/test/TestRunner.java
similarity index 100%
rename from test-runner/android/test/TestRunner.java
rename to test-runner/src/android/test/TestRunner.java
diff --git a/test-runner/android/test/TestRunnerView.java b/test-runner/src/android/test/TestRunnerView.java
similarity index 100%
rename from test-runner/android/test/TestRunnerView.java
rename to test-runner/src/android/test/TestRunnerView.java
diff --git a/test-runner/android/test/TestSuiteProvider.java b/test-runner/src/android/test/TestSuiteProvider.java
similarity index 100%
rename from test-runner/android/test/TestSuiteProvider.java
rename to test-runner/src/android/test/TestSuiteProvider.java
diff --git a/test-runner/android/test/TimedTest.java b/test-runner/src/android/test/TimedTest.java
similarity index 100%
rename from test-runner/android/test/TimedTest.java
rename to test-runner/src/android/test/TimedTest.java
diff --git a/test-runner/android/test/TouchUtils.java b/test-runner/src/android/test/TouchUtils.java
similarity index 100%
rename from test-runner/android/test/TouchUtils.java
rename to test-runner/src/android/test/TouchUtils.java
diff --git a/test-runner/android/test/ViewAsserts.java b/test-runner/src/android/test/ViewAsserts.java
similarity index 100%
rename from test-runner/android/test/ViewAsserts.java
rename to test-runner/src/android/test/ViewAsserts.java
diff --git a/test-runner/android/test/mock/MockApplication.java b/test-runner/src/android/test/mock/MockApplication.java
similarity index 100%
rename from test-runner/android/test/mock/MockApplication.java
rename to test-runner/src/android/test/mock/MockApplication.java
diff --git a/test-runner/android/test/mock/MockContentProvider.java b/test-runner/src/android/test/mock/MockContentProvider.java
similarity index 100%
rename from test-runner/android/test/mock/MockContentProvider.java
rename to test-runner/src/android/test/mock/MockContentProvider.java
diff --git a/test-runner/android/test/mock/MockContentResolver.java b/test-runner/src/android/test/mock/MockContentResolver.java
similarity index 100%
rename from test-runner/android/test/mock/MockContentResolver.java
rename to test-runner/src/android/test/mock/MockContentResolver.java
diff --git a/test-runner/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
similarity index 100%
rename from test-runner/android/test/mock/MockContext.java
rename to test-runner/src/android/test/mock/MockContext.java
diff --git a/test-runner/android/test/mock/MockCursor.java b/test-runner/src/android/test/mock/MockCursor.java
similarity index 100%
rename from test-runner/android/test/mock/MockCursor.java
rename to test-runner/src/android/test/mock/MockCursor.java
diff --git a/test-runner/android/test/mock/MockDialogInterface.java b/test-runner/src/android/test/mock/MockDialogInterface.java
similarity index 100%
rename from test-runner/android/test/mock/MockDialogInterface.java
rename to test-runner/src/android/test/mock/MockDialogInterface.java
diff --git a/test-runner/android/test/mock/MockIContentProvider.java b/test-runner/src/android/test/mock/MockIContentProvider.java
similarity index 100%
rename from test-runner/android/test/mock/MockIContentProvider.java
rename to test-runner/src/android/test/mock/MockIContentProvider.java
diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
similarity index 97%
rename from test-runner/android/test/mock/MockPackageManager.java
rename to test-runner/src/android/test/mock/MockPackageManager.java
index f1ba44a..2ccc9bb 100644
--- a/test-runner/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -26,6 +26,7 @@
 import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageInstallObserver;
+import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
@@ -308,6 +309,14 @@
             int flags, String installerPackageName) {
         throw new UnsupportedOperationException();
     }
+
+    /**
+     * @hide - to match hiding in superclass
+     */
+    @Override
+    public void movePackage(String packageName, IPackageMoveObserver observer, int flags) {
+        throw new UnsupportedOperationException();
+    }
     
     @Override
     public String getInstallerPackageName(String packageName) {
diff --git a/test-runner/android/test/mock/MockResources.java b/test-runner/src/android/test/mock/MockResources.java
similarity index 100%
rename from test-runner/android/test/mock/MockResources.java
rename to test-runner/src/android/test/mock/MockResources.java
diff --git a/test-runner/android/test/mock/package.html b/test-runner/src/android/test/mock/package.html
similarity index 100%
rename from test-runner/android/test/mock/package.html
rename to test-runner/src/android/test/mock/package.html
diff --git a/test-runner/android/test/suitebuilder/AssignableFrom.java b/test-runner/src/android/test/suitebuilder/AssignableFrom.java
similarity index 100%
rename from test-runner/android/test/suitebuilder/AssignableFrom.java
rename to test-runner/src/android/test/suitebuilder/AssignableFrom.java
diff --git a/test-runner/android/test/suitebuilder/InstrumentationTestSuiteBuilder.java b/test-runner/src/android/test/suitebuilder/InstrumentationTestSuiteBuilder.java
similarity index 100%
rename from test-runner/android/test/suitebuilder/InstrumentationTestSuiteBuilder.java
rename to test-runner/src/android/test/suitebuilder/InstrumentationTestSuiteBuilder.java
diff --git a/test-runner/android/test/suitebuilder/SmokeTestSuiteBuilder.java b/test-runner/src/android/test/suitebuilder/SmokeTestSuiteBuilder.java
similarity index 100%
rename from test-runner/android/test/suitebuilder/SmokeTestSuiteBuilder.java
rename to test-runner/src/android/test/suitebuilder/SmokeTestSuiteBuilder.java
diff --git a/test-runner/android/test/suitebuilder/TestGrouping.java b/test-runner/src/android/test/suitebuilder/TestGrouping.java
similarity index 100%
rename from test-runner/android/test/suitebuilder/TestGrouping.java
rename to test-runner/src/android/test/suitebuilder/TestGrouping.java
diff --git a/test-runner/android/test/suitebuilder/TestMethod.java b/test-runner/src/android/test/suitebuilder/TestMethod.java
similarity index 100%
rename from test-runner/android/test/suitebuilder/TestMethod.java
rename to test-runner/src/android/test/suitebuilder/TestMethod.java
diff --git a/test-runner/android/test/suitebuilder/TestPredicates.java b/test-runner/src/android/test/suitebuilder/TestPredicates.java
similarity index 100%
rename from test-runner/android/test/suitebuilder/TestPredicates.java
rename to test-runner/src/android/test/suitebuilder/TestPredicates.java
diff --git a/test-runner/android/test/suitebuilder/TestSuiteBuilder.java b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
similarity index 100%
rename from test-runner/android/test/suitebuilder/TestSuiteBuilder.java
rename to test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
diff --git a/test-runner/android/test/suitebuilder/UnitTestSuiteBuilder.java b/test-runner/src/android/test/suitebuilder/UnitTestSuiteBuilder.java
similarity index 100%
rename from test-runner/android/test/suitebuilder/UnitTestSuiteBuilder.java
rename to test-runner/src/android/test/suitebuilder/UnitTestSuiteBuilder.java
diff --git a/test-runner/android/test/suitebuilder/annotation/HasAnnotation.java b/test-runner/src/android/test/suitebuilder/annotation/HasAnnotation.java
similarity index 100%
rename from test-runner/android/test/suitebuilder/annotation/HasAnnotation.java
rename to test-runner/src/android/test/suitebuilder/annotation/HasAnnotation.java
diff --git a/test-runner/android/test/suitebuilder/annotation/HasClassAnnotation.java b/test-runner/src/android/test/suitebuilder/annotation/HasClassAnnotation.java
similarity index 100%
rename from test-runner/android/test/suitebuilder/annotation/HasClassAnnotation.java
rename to test-runner/src/android/test/suitebuilder/annotation/HasClassAnnotation.java
diff --git a/test-runner/android/test/suitebuilder/annotation/HasMethodAnnotation.java b/test-runner/src/android/test/suitebuilder/annotation/HasMethodAnnotation.java
similarity index 100%
rename from test-runner/android/test/suitebuilder/annotation/HasMethodAnnotation.java
rename to test-runner/src/android/test/suitebuilder/annotation/HasMethodAnnotation.java
diff --git a/test-runner/android/test/suitebuilder/annotation/package.html b/test-runner/src/android/test/suitebuilder/annotation/package.html
similarity index 100%
rename from test-runner/android/test/suitebuilder/annotation/package.html
rename to test-runner/src/android/test/suitebuilder/annotation/package.html
diff --git a/test-runner/android/test/suitebuilder/package.html b/test-runner/src/android/test/suitebuilder/package.html
similarity index 100%
rename from test-runner/android/test/suitebuilder/package.html
rename to test-runner/src/android/test/suitebuilder/package.html
diff --git a/test-runner/junit/MODULE_LICENSE_CPL b/test-runner/src/junit/MODULE_LICENSE_CPL
similarity index 100%
rename from test-runner/junit/MODULE_LICENSE_CPL
rename to test-runner/src/junit/MODULE_LICENSE_CPL
diff --git a/test-runner/junit/runner/BaseTestRunner.java b/test-runner/src/junit/runner/BaseTestRunner.java
similarity index 100%
rename from test-runner/junit/runner/BaseTestRunner.java
rename to test-runner/src/junit/runner/BaseTestRunner.java
diff --git a/test-runner/junit/runner/ClassPathTestCollector.java b/test-runner/src/junit/runner/ClassPathTestCollector.java
similarity index 100%
rename from test-runner/junit/runner/ClassPathTestCollector.java
rename to test-runner/src/junit/runner/ClassPathTestCollector.java
diff --git a/test-runner/junit/runner/FailureDetailView.java b/test-runner/src/junit/runner/FailureDetailView.java
similarity index 100%
rename from test-runner/junit/runner/FailureDetailView.java
rename to test-runner/src/junit/runner/FailureDetailView.java
diff --git a/test-runner/junit/runner/LoadingTestCollector.java b/test-runner/src/junit/runner/LoadingTestCollector.java
similarity index 100%
rename from test-runner/junit/runner/LoadingTestCollector.java
rename to test-runner/src/junit/runner/LoadingTestCollector.java
diff --git a/test-runner/junit/runner/ReloadingTestSuiteLoader.java b/test-runner/src/junit/runner/ReloadingTestSuiteLoader.java
similarity index 100%
rename from test-runner/junit/runner/ReloadingTestSuiteLoader.java
rename to test-runner/src/junit/runner/ReloadingTestSuiteLoader.java
diff --git a/test-runner/junit/runner/SimpleTestCollector.java b/test-runner/src/junit/runner/SimpleTestCollector.java
similarity index 100%
rename from test-runner/junit/runner/SimpleTestCollector.java
rename to test-runner/src/junit/runner/SimpleTestCollector.java
diff --git a/test-runner/junit/runner/Sorter.java b/test-runner/src/junit/runner/Sorter.java
similarity index 100%
rename from test-runner/junit/runner/Sorter.java
rename to test-runner/src/junit/runner/Sorter.java
diff --git a/test-runner/junit/runner/StandardTestSuiteLoader.java b/test-runner/src/junit/runner/StandardTestSuiteLoader.java
similarity index 100%
rename from test-runner/junit/runner/StandardTestSuiteLoader.java
rename to test-runner/src/junit/runner/StandardTestSuiteLoader.java
diff --git a/test-runner/junit/runner/TestCaseClassLoader.java b/test-runner/src/junit/runner/TestCaseClassLoader.java
similarity index 100%
rename from test-runner/junit/runner/TestCaseClassLoader.java
rename to test-runner/src/junit/runner/TestCaseClassLoader.java
diff --git a/test-runner/junit/runner/TestCollector.java b/test-runner/src/junit/runner/TestCollector.java
similarity index 100%
rename from test-runner/junit/runner/TestCollector.java
rename to test-runner/src/junit/runner/TestCollector.java
diff --git a/test-runner/junit/runner/TestRunListener.java b/test-runner/src/junit/runner/TestRunListener.java
similarity index 100%
rename from test-runner/junit/runner/TestRunListener.java
rename to test-runner/src/junit/runner/TestRunListener.java
diff --git a/test-runner/junit/runner/TestSuiteLoader.java b/test-runner/src/junit/runner/TestSuiteLoader.java
similarity index 100%
rename from test-runner/junit/runner/TestSuiteLoader.java
rename to test-runner/src/junit/runner/TestSuiteLoader.java
diff --git a/test-runner/junit/runner/Version.java b/test-runner/src/junit/runner/Version.java
similarity index 100%
rename from test-runner/junit/runner/Version.java
rename to test-runner/src/junit/runner/Version.java
diff --git a/test-runner/junit/runner/excluded.properties b/test-runner/src/junit/runner/excluded.properties
similarity index 100%
rename from test-runner/junit/runner/excluded.properties
rename to test-runner/src/junit/runner/excluded.properties
diff --git a/test-runner/junit/runner/logo.gif b/test-runner/src/junit/runner/logo.gif
similarity index 100%
rename from test-runner/junit/runner/logo.gif
rename to test-runner/src/junit/runner/logo.gif
Binary files differ
diff --git a/test-runner/junit/runner/package.html b/test-runner/src/junit/runner/package.html
similarity index 100%
rename from test-runner/junit/runner/package.html
rename to test-runner/src/junit/runner/package.html
diff --git a/test-runner/junit/runner/smalllogo.gif b/test-runner/src/junit/runner/smalllogo.gif
similarity index 100%
rename from test-runner/junit/runner/smalllogo.gif
rename to test-runner/src/junit/runner/smalllogo.gif
Binary files differ
diff --git a/test-runner/junit/textui/ResultPrinter.java b/test-runner/src/junit/textui/ResultPrinter.java
similarity index 100%
rename from test-runner/junit/textui/ResultPrinter.java
rename to test-runner/src/junit/textui/ResultPrinter.java
diff --git a/test-runner/junit/textui/TestRunner.java b/test-runner/src/junit/textui/TestRunner.java
similarity index 100%
rename from test-runner/junit/textui/TestRunner.java
rename to test-runner/src/junit/textui/TestRunner.java
diff --git a/test-runner/junit/textui/package.html b/test-runner/src/junit/textui/package.html
similarity index 100%
rename from test-runner/junit/textui/package.html
rename to test-runner/src/junit/textui/package.html
diff --git a/test-runner/tests/Android.mk b/test-runner/tests/Android.mk
new file mode 100644
index 0000000..d1efe7b
--- /dev/null
+++ b/test-runner/tests/Android.mk
@@ -0,0 +1,29 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := FrameworkTestRunnerTests
+
+include $(BUILD_PACKAGE)
+
diff --git a/test-runner/tests/AndroidManifest.xml b/test-runner/tests/AndroidManifest.xml
new file mode 100644
index 0000000..4f32392
--- /dev/null
+++ b/test-runner/tests/AndroidManifest.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.frameworks.testrunner.tests">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <activity android:name="android.test.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.testrunner.tests"
+        android:label="Framework testrunner tests" />
+</manifest>
diff --git a/tests/CoreTests/android/test/AndroidTestRunnerTest.java b/test-runner/tests/src/android/test/AndroidTestRunnerTest.java
similarity index 100%
rename from tests/CoreTests/android/test/AndroidTestRunnerTest.java
rename to test-runner/tests/src/android/test/AndroidTestRunnerTest.java
diff --git a/tests/CoreTests/android/test/InstrumentationTestRunnerTest.java b/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java
similarity index 100%
rename from tests/CoreTests/android/test/InstrumentationTestRunnerTest.java
rename to test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java
diff --git a/tests/CoreTests/android/test/StubTestBrowserActivity.java b/test-runner/tests/src/android/test/StubTestBrowserActivity.java
similarity index 100%
rename from tests/CoreTests/android/test/StubTestBrowserActivity.java
rename to test-runner/tests/src/android/test/StubTestBrowserActivity.java
diff --git a/tests/CoreTests/android/test/TestBrowserActivityTest.java b/test-runner/tests/src/android/test/TestBrowserActivityTest.java
similarity index 96%
rename from tests/CoreTests/android/test/TestBrowserActivityTest.java
rename to test-runner/tests/src/android/test/TestBrowserActivityTest.java
index 6afbe37..355409e 100644
--- a/tests/CoreTests/android/test/TestBrowserActivityTest.java
+++ b/test-runner/tests/src/android/test/TestBrowserActivityTest.java
@@ -215,19 +215,24 @@
     }
 
     private TestBrowserActivity createActivity() throws RemoteException {
-        return launchActivity("android.test", StubTestBrowserActivity.class, null);
+        return launchActivity(getAndroidPackageName(), StubTestBrowserActivity.class, null);
     }
 
     private Intent createIntent(TestSuite testSuite) {
         Intent intent = new Intent(Intent.ACTION_RUN);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         String className = StubTestBrowserActivity.class.getName();
-        String packageName = className.substring(0, className.lastIndexOf("."));
+        String packageName = getAndroidPackageName();
         intent.setClassName(packageName, className);
         intent.setData(Uri.parse(testSuite.getName()));
         return intent;
     }
 
+    private String getAndroidPackageName() {
+        String packageName = getInstrumentation().getTargetContext().getPackageName();
+        return packageName;
+    }
+
     private TestBrowserActivity launchTestBrowserActivity(TestSuite testSuite)
             throws RemoteException {
         getInstrumentation().setInTouchMode(false);
diff --git a/tests/CoreTests/android/test/TestBrowserControllerImplTest.java b/test-runner/tests/src/android/test/TestBrowserControllerImplTest.java
similarity index 100%
rename from tests/CoreTests/android/test/TestBrowserControllerImplTest.java
rename to test-runner/tests/src/android/test/TestBrowserControllerImplTest.java
diff --git a/tests/CoreTests/android/test/TestBrowserTests.java b/test-runner/tests/src/android/test/TestBrowserTests.java
similarity index 100%
rename from tests/CoreTests/android/test/TestBrowserTests.java
rename to test-runner/tests/src/android/test/TestBrowserTests.java
diff --git a/tests/CoreTests/android/test/TestCaseUtilTest.java b/test-runner/tests/src/android/test/TestCaseUtilTest.java
similarity index 100%
rename from tests/CoreTests/android/test/TestCaseUtilTest.java
rename to test-runner/tests/src/android/test/TestCaseUtilTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/AssignableFromTest.java b/test-runner/tests/src/android/test/suitebuilder/AssignableFromTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/AssignableFromTest.java
rename to test-runner/tests/src/android/test/suitebuilder/AssignableFromTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/InstrumentationTestSuiteBuilderTest.java b/test-runner/tests/src/android/test/suitebuilder/InstrumentationTestSuiteBuilderTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/InstrumentationTestSuiteBuilderTest.java
rename to test-runner/tests/src/android/test/suitebuilder/InstrumentationTestSuiteBuilderTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/ListTestCaseNames.java b/test-runner/tests/src/android/test/suitebuilder/ListTestCaseNames.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/ListTestCaseNames.java
rename to test-runner/tests/src/android/test/suitebuilder/ListTestCaseNames.java
diff --git a/tests/CoreTests/android/test/suitebuilder/SmokeTestSuiteBuilderTest.java b/test-runner/tests/src/android/test/suitebuilder/SmokeTestSuiteBuilderTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/SmokeTestSuiteBuilderTest.java
rename to test-runner/tests/src/android/test/suitebuilder/SmokeTestSuiteBuilderTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/TestSuiteBuilderTest.java b/test-runner/tests/src/android/test/suitebuilder/TestSuiteBuilderTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/TestSuiteBuilderTest.java
rename to test-runner/tests/src/android/test/suitebuilder/TestSuiteBuilderTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/UnitTestSuiteBuilderTest.java b/test-runner/tests/src/android/test/suitebuilder/UnitTestSuiteBuilderTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/UnitTestSuiteBuilderTest.java
rename to test-runner/tests/src/android/test/suitebuilder/UnitTestSuiteBuilderTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/annotation/HasAnnotationTest.java b/test-runner/tests/src/android/test/suitebuilder/annotation/HasAnnotationTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/annotation/HasAnnotationTest.java
rename to test-runner/tests/src/android/test/suitebuilder/annotation/HasAnnotationTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/annotation/HasClassAnnotationTest.java b/test-runner/tests/src/android/test/suitebuilder/annotation/HasClassAnnotationTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/annotation/HasClassAnnotationTest.java
rename to test-runner/tests/src/android/test/suitebuilder/annotation/HasClassAnnotationTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/annotation/HasMethodAnnotationTest.java b/test-runner/tests/src/android/test/suitebuilder/annotation/HasMethodAnnotationTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/annotation/HasMethodAnnotationTest.java
rename to test-runner/tests/src/android/test/suitebuilder/annotation/HasMethodAnnotationTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/OuterTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/OuterTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/examples/OuterTest.java
rename to test-runner/tests/src/android/test/suitebuilder/examples/OuterTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/error/ErrorTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/error/ErrorTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/examples/error/ErrorTest.java
rename to test-runner/tests/src/android/test/suitebuilder/examples/error/ErrorTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/error/FailingTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/error/FailingTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/examples/error/FailingTest.java
rename to test-runner/tests/src/android/test/suitebuilder/examples/error/FailingTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/instrumentation/InstrumentationTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/instrumentation/InstrumentationTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/examples/instrumentation/InstrumentationTest.java
rename to test-runner/tests/src/android/test/suitebuilder/examples/instrumentation/InstrumentationTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/nested/Level1Test.java b/test-runner/tests/src/android/test/suitebuilder/examples/nested/Level1Test.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/examples/nested/Level1Test.java
rename to test-runner/tests/src/android/test/suitebuilder/examples/nested/Level1Test.java
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/nested/nested/Level2Test.java b/test-runner/tests/src/android/test/suitebuilder/examples/nested/nested/Level2Test.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/examples/nested/nested/Level2Test.java
rename to test-runner/tests/src/android/test/suitebuilder/examples/nested/nested/Level2Test.java
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/simple/AnotherSimpleTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/simple/AnotherSimpleTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/examples/simple/AnotherSimpleTest.java
rename to test-runner/tests/src/android/test/suitebuilder/examples/simple/AnotherSimpleTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/simple/SimpleTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/simple/SimpleTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/examples/simple/SimpleTest.java
rename to test-runner/tests/src/android/test/suitebuilder/examples/simple/SimpleTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/smoke/NonSmokeTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/smoke/NonSmokeTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/examples/smoke/NonSmokeTest.java
rename to test-runner/tests/src/android/test/suitebuilder/examples/smoke/NonSmokeTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/smoke/SmokeTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/smoke/SmokeTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/examples/smoke/SmokeTest.java
rename to test-runner/tests/src/android/test/suitebuilder/examples/smoke/SmokeTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/subclass/SubclassTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/subclass/SubclassTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/examples/subclass/SubclassTest.java
rename to test-runner/tests/src/android/test/suitebuilder/examples/subclass/SubclassTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/subclass/SuperclassTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/subclass/SuperclassTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/examples/subclass/SuperclassTest.java
rename to test-runner/tests/src/android/test/suitebuilder/examples/subclass/SuperclassTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/suppress/PartiallySuppressedTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/suppress/PartiallySuppressedTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/examples/suppress/PartiallySuppressedTest.java
rename to test-runner/tests/src/android/test/suitebuilder/examples/suppress/PartiallySuppressedTest.java
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/suppress/SuppressedTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/suppress/SuppressedTest.java
similarity index 100%
rename from tests/CoreTests/android/test/suitebuilder/examples/suppress/SuppressedTest.java
rename to test-runner/tests/src/android/test/suitebuilder/examples/suppress/SuppressedTest.java
diff --git a/tests/AndroidTests/AndroidManifest.xml b/tests/AndroidTests/AndroidManifest.xml
index 28f1e73..e06c3a8 100644
--- a/tests/AndroidTests/AndroidManifest.xml
+++ b/tests/AndroidTests/AndroidManifest.xml
@@ -28,6 +28,7 @@
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
     <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
     <uses-permission android:name="android.permission.DELETE_PACKAGES" />
+    <uses-permission android:name="android.permission.MOVE_PACKAGE" />
     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
     <uses-permission android:name="android.permission.ASEC_ACCESS" />
     <uses-permission android:name="android.permission.ASEC_CREATE" />
diff --git a/tests/AndroidTests/res/raw/install_loc_auto b/tests/AndroidTests/res/raw/install_loc_auto
index 60dda18..d5d2739 100644
--- a/tests/AndroidTests/res/raw/install_loc_auto
+++ b/tests/AndroidTests/res/raw/install_loc_auto
Binary files differ
diff --git a/tests/AndroidTests/res/raw/install_loc_internal b/tests/AndroidTests/res/raw/install_loc_internal
index 1bc33ca..eb6279a 100644
--- a/tests/AndroidTests/res/raw/install_loc_internal
+++ b/tests/AndroidTests/res/raw/install_loc_internal
Binary files differ
diff --git a/tests/AndroidTests/res/raw/install_loc_sdcard b/tests/AndroidTests/res/raw/install_loc_sdcard
index 6604e35..c774989 100644
--- a/tests/AndroidTests/res/raw/install_loc_sdcard
+++ b/tests/AndroidTests/res/raw/install_loc_sdcard
Binary files differ
diff --git a/tests/AndroidTests/res/raw/install_loc_unspecified b/tests/AndroidTests/res/raw/install_loc_unspecified
index 88bbace..ab226c6 100644
--- a/tests/AndroidTests/res/raw/install_loc_unspecified
+++ b/tests/AndroidTests/res/raw/install_loc_unspecified
Binary files differ
diff --git a/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java b/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java
index 7569d7a..3bbb447 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java
@@ -73,11 +73,65 @@
 
         for (int i = 0; i < containers.length; i++) {
             if (containers[i].startsWith("com.android.unittests.AsecTests.")) {
-                ms.destroySecureContainer(containers[i]);
+                ms.destroySecureContainer(containers[i], true);
             }
         }
     }
 
+    private boolean containerExists(String localId) throws RemoteException {
+        IMountService ms = getMs();
+        String[] containers = ms.getSecureContainerList();
+        String fullId = "com.android.unittests.AsecTests." + localId;
+
+        for (int i = 0; i < containers.length; i++) {
+            if (containers[i].equals(fullId)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private int createContainer(String localId, int size, String key) throws RemoteException {
+        Assert.assertTrue(isMediaMounted());
+        String fullId = "com.android.unittests.AsecTests." + localId;
+
+        IMountService ms = getMs();
+        return ms.createSecureContainer(fullId, size, "fat", key, android.os.Process.myUid());
+    }
+
+    private int mountContainer(String localId, String key) throws RemoteException {
+        Assert.assertTrue(isMediaMounted());
+        String fullId = "com.android.unittests.AsecTests." + localId;
+
+        IMountService ms = getMs();
+        return ms.mountSecureContainer(fullId, key, android.os.Process.myUid());
+    }
+
+    private int renameContainer(String localId1, String localId2) throws RemoteException {
+        Assert.assertTrue(isMediaMounted());
+        String fullId1 = "com.android.unittests.AsecTests." + localId1;
+        String fullId2 = "com.android.unittests.AsecTests." + localId2;
+
+        IMountService ms = getMs();
+        return ms.renameSecureContainer(fullId1, fullId2);
+    }
+
+    private int unmountContainer(String localId, boolean force) throws RemoteException {
+        Assert.assertTrue(isMediaMounted());
+        String fullId = "com.android.unittests.AsecTests." + localId;
+
+        IMountService ms = getMs();
+        return ms.unmountSecureContainer(fullId, force);
+    }
+
+    private int destroyContainer(String localId, boolean force) throws RemoteException {
+        Assert.assertTrue(isMediaMounted());
+        String fullId = "com.android.unittests.AsecTests." + localId;
+
+        IMountService ms = getMs();
+        return ms.destroySecureContainer(fullId, force);
+    }
+
     private IMountService getMs() {
         IBinder service = ServiceManager.getService("mount");
         if (service != null) {
@@ -100,67 +154,174 @@
     }
 
     public void testCreateContainer() {
-        Assert.assertTrue(isMediaMounted());
-        IMountService ms = getMs();
         try {
-            int rc = ms.createSecureContainer("com.android.unittests.AsecTests.testCreateContainer", 4, "fat", "none", 1000);
-            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    createContainer("testCreateContainer", 4, "none"));
+            Assert.assertEquals(true, containerExists("testCreateContainer"));
+        } catch (Exception e) {
+            failStr(e);
+        }
+    }
+
+    public void testCreateMinSizeContainer() {
+        try {
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    createContainer("testCreateContainer", 1, "none"));
+            Assert.assertEquals(true, containerExists("testCreateContainer"));
+        } catch (Exception e) {
+            failStr(e);
+        }
+    }
+
+    public void testCreateZeroSizeContainer() {
+        try {
+            Assert.assertEquals(StorageResultCode.OperationFailedInternalError,
+                    createContainer("testCreateZeroContainer", 0, "none"));
+        } catch (Exception e) {
+            failStr(e);
+        }
+    }
+
+    public void testCreateDuplicateContainer() {
+        try {
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    createContainer("testCreateDupContainer", 4, "none"));
+
+            Assert.assertEquals(StorageResultCode.OperationFailedInternalError,
+                    createContainer("testCreateDupContainer", 4, "none"));
         } catch (Exception e) {
             failStr(e);
         }
     }
 
     public void testDestroyContainer() {
-        Assert.assertTrue(isMediaMounted());
-        IMountService ms = getMs();
         try {
-            int rc = ms.createSecureContainer("com.android.unittests.AsecTests.testDestroyContainer", 4, "fat", "none", 1000);
-            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
-            rc = ms.destroySecureContainer("com.android.unittests.AsecTests.testDestroyContainer");
-            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    createContainer("testDestroyContainer", 4, "none"));
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    destroyContainer("testDestroyContainer", false));
         } catch (Exception e) {
             failStr(e);
         }
     }
 
     public void testMountContainer() {
-        Assert.assertTrue(isMediaMounted());
-        IMountService ms = getMs();
         try {
-            int rc = ms.createSecureContainer(
-                    "com.android.unittests.AsecTests.testMountContainer", 4, "fat", "none", 1000);
-            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    createContainer("testMountContainer", 4, "none"));
 
-            rc = ms.unmountSecureContainer("com.android.unittests.AsecTests.testMountContainer");
-            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    unmountContainer("testMountContainer", false));
 
-            rc = ms.mountSecureContainer("com.android.unittests.AsecTests.testMountContainer", "none", 1000);
-            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    mountContainer("testMountContainer", "none"));
         } catch (Exception e) {
             failStr(e);
         }
     }
 
     public void testMountBadKey() {
-        Assert.assertTrue(isMediaMounted());
+        try {
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    createContainer("testMountBadKey", 4, "00000000000000000000000000000000"));
+
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    unmountContainer("testMountBadKey", false));
+
+            Assert.assertEquals(StorageResultCode.OperationFailedInternalError,
+                    mountContainer("testMountContainer", "000000000000000000000000000000001"));
+
+            Assert.assertEquals(StorageResultCode.OperationFailedInternalError,
+                    mountContainer("testMountContainer", "none"));
+        } catch (Exception e) {
+            failStr(e);
+        }
+    }
+
+    public void testUnmountBusyContainer() {
         IMountService ms = getMs();
         try {
-            int rc = ms.createSecureContainer(
-                    "com.android.unittests.AsecTests.testMountBadKey", 4, "fat",
-                            "00000000000000000000000000000000", 1000);
-            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    createContainer("testUnmountBusyContainer", 4, "none"));
 
-            rc = ms.unmountSecureContainer("com.android.unittests.AsecTests.testMountBadKey");
-            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+            String path = ms.getSecureContainerPath("com.android.unittests.AsecTests.testUnmountBusyContainer");
 
-            rc = ms.mountSecureContainer(
-                    "com.android.unittests.AsecTests.testMountBadKey",
-                            "00000000000000000000000000000001", 1001);
-            Assert.assertEquals(StorageResultCode.OperationFailedInternalError, rc);
+            File f = new File(path, "reference");
+            FileOutputStream fos = new FileOutputStream(f);
 
-            rc = ms.mountSecureContainer(
-                    "com.android.unittests.AsecTests.testMountBadKey", "none", 1001);
-            Assert.assertEquals(StorageResultCode.OperationFailedInternalError, rc);
+            Assert.assertEquals(StorageResultCode.OperationFailedStorageBusy,
+                    unmountContainer("testUnmountBusyContainer", false));
+
+            fos.close();
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    unmountContainer("testUnmountBusyContainer", false));
+        } catch (Exception e) {
+            failStr(e);
+        }
+    }
+
+    public void testDestroyBusyContainer() {
+        IMountService ms = getMs();
+        try {
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    createContainer("testDestroyBusyContainer", 4, "none"));
+
+            String path = ms.getSecureContainerPath("com.android.unittests.AsecTests.testDestroyBusyContainer");
+
+            File f = new File(path, "reference");
+            FileOutputStream fos = new FileOutputStream(f);
+
+            Assert.assertEquals(StorageResultCode.OperationFailedStorageBusy,
+                    destroyContainer("testDestroyBusyContainer", false));
+
+            fos.close();
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    destroyContainer("testDestroyBusyContainer", false));
+        } catch (Exception e) {
+            failStr(e);
+        }
+    }
+
+    public void testRenameContainer() {
+        try {
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    createContainer("testRenameContainer.1", 4, "none"));
+
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    unmountContainer("testRenameContainer.1", false));
+
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    renameContainer("testRenameContainer.1", "testRenameContainer.2"));
+
+            Assert.assertEquals(false, containerExists("testRenameContainer.1"));
+            Assert.assertEquals(true, containerExists("testRenameContainer.2"));
+        } catch (Exception e) {
+            failStr(e);
+        }
+    }
+
+    public void testRenameMountedContainer() {
+        try {
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    createContainer("testRenameContainer.1", 4, "none"));
+
+            Assert.assertEquals(StorageResultCode.OperationFailedStorageMounted,
+                    renameContainer("testRenameContainer.1", "testRenameContainer.2"));
+        } catch (Exception e) {
+            failStr(e);
+        }
+    }
+
+    public void testRenameToExistingContainer() {
+        try {
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    createContainer("testRenameContainer.1", 4, "none"));
+
+            Assert.assertEquals(StorageResultCode.OperationSucceeded,
+                    createContainer("testRenameContainer.2", 4, "none"));
+
+            Assert.assertEquals(StorageResultCode.OperationFailedStorageMounted,
+                    renameContainer("testRenameContainer.1", "testRenameContainer.2"));
         } catch (Exception e) {
             failStr(e);
         }
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
index 8f4d0a1..9c5c44d 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -37,6 +37,7 @@
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageInstallObserver;
 import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageMoveObserver;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
@@ -159,6 +160,7 @@
         PackageInstallObserver observer = new PackageInstallObserver();
         final boolean received = false;
         mContext.registerReceiver(receiver, receiver.filter);
+        final boolean DEBUG = true;
         try {
             // Wait on observer
             synchronized(observer) {
@@ -173,6 +175,7 @@
                         throw new Exception("Timed out waiting for packageInstalled callback");
                     }
                     if (observer.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+                        Log.i(TAG, "Failed to install with error code = " + observer.returnCode);
                         return false;
                     }
                     // Verify we received the broadcast
@@ -237,7 +240,9 @@
         File sourceFile = new File(archiveFilePath);
         DisplayMetrics metrics = new DisplayMetrics();
         metrics.setToDefaults();
-        return packageParser.parsePackage(sourceFile, archiveFilePath, metrics, 0);
+        PackageParser.Package pkg = packageParser.parsePackage(sourceFile, archiveFilePath, metrics, 0);
+        packageParser = null;
+        return pkg;
     }
 
     private void assertInstall(String pkgName, int flags) {
@@ -297,6 +302,25 @@
         return installFromRawResource("install.apk", R.raw.install, flags, cleanUp,
                 false, -1);
     }
+
+    public void clearSecureContainersForPkg(String pkgName) {
+        IMountService ms = getMs();
+        try {
+            String list[] = ms.getSecureContainerList();
+            if (list != null) {
+                for (String cid : list) {
+                    boolean delete = false;
+                    // STOPSHIP issues with rename should be fixed.
+                    if (cid.contains(pkgName) ||
+                            cid.contains("smdltmp")) {
+                        Log.i(TAG, "Destroying container " + cid);
+                        ms.destroySecureContainer(cid, true);
+                    }
+                }
+            }
+        } catch (RemoteException e) {}
+    }
+
     /*
      * Utility function that reads a apk bundled as a raw resource
      * copies it into own data directory and invokes
@@ -310,11 +334,15 @@
         PackageParser.Package pkg = parsePackage(packageURI);
         assertNotNull(pkg);
         InstallParams ip = null;
+        // Make sure the package doesn't exist
+        getPm().deletePackage(pkg.packageName, null, 0);
+        // Clean up the containers as well
+        if ((flags & PackageManager.INSTALL_EXTERNAL) != 0) {
+            clearSecureContainersForPkg(pkg.packageName);
+        }
         try {
             try {
                 if (fail) {
-                    // Make sure it doesn't exist
-                    getPm().deletePackage(pkg.packageName, null, 0);
                     assertTrue(invokeInstallPackageFail(packageURI, flags,
                             pkg.packageName, result));
                     assertNotInstalled(pkg.packageName);
@@ -716,7 +744,7 @@
         }
         try {
         String mPath = Environment.getExternalStorageDirectory().toString();
-        int ret = getMs().unmountVolume(mPath);
+        int ret = getMs().unmountVolume(mPath, false);
         return ret == StorageResultCode.OperationSucceeded;
         } catch (RemoteException e) {
             return true;
@@ -811,7 +839,7 @@
 
     public void testManifestInstallLocationSdcard() {
         installFromRawResource("install.apk", R.raw.install_loc_sdcard,
-                PackageManager.INSTALL_EXTERNAL, true, false, -1);
+                0, true, false, -1);
     }
 
     public void testManifestInstallLocationAuto() {
@@ -826,10 +854,186 @@
 
     public void testManifestInstallLocationFwdLockedSdcard() {
         installFromRawResource("install.apk", R.raw.install_loc_sdcard,
-                PackageManager.INSTALL_FORWARD_LOCK |
-                PackageManager.INSTALL_EXTERNAL, true, true,
+                PackageManager.INSTALL_FORWARD_LOCK, true, true,
                 PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION);
     }
+
+    public void xxxtestClearAllSecureContainers() {
+        IMountService ms = getMs();
+        try {
+            String list[] = ms.getSecureContainerList();
+            if (list != null) {
+                for (String cid : list) {
+                    Log.i(TAG, "Destroying container " + cid);
+                    ms.destroySecureContainer(cid, false);
+                }
+            }
+        } catch (RemoteException e) {}
+    }
+
+    class MoveReceiver extends GenericReceiver {
+        String pkgName;
+        final static int INVALID = -1;
+        final static int REMOVED = 1;
+        final static int ADDED = 2;
+        int removed = INVALID;
+
+        MoveReceiver(String pkgName) {
+            this.pkgName = pkgName;
+            filter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+            filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+            super.setFilter(filter);
+        }
+
+        public boolean notifyNow(Intent intent) {
+            String action = intent.getAction();
+            Log.i(TAG, "MoveReceiver::" + action);
+            if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
+                String[] list = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                if (list != null) {
+                    for (String pkg : list) {
+                        if (pkg.equals(pkgName)) {
+                            removed = REMOVED;
+                            break;
+                        }
+                    }
+                }
+                removed = REMOVED;
+            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
+                if (removed != REMOVED) {
+                    return false;
+                }
+                String[] list = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                if (list != null) {
+                    for (String pkg : list) {
+                        if (pkg.equals(pkgName)) {
+                            removed = ADDED;
+                            return true;
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+    }
+
+    private class PackageMoveObserver extends IPackageMoveObserver.Stub {
+        public int returnCode;
+        private boolean doneFlag = false;
+
+        public void packageMoved(String packageName, int returnCode) {
+            synchronized(this) {
+                this.returnCode = returnCode;
+                doneFlag = true;
+                notifyAll();
+            }
+        }
+
+        public boolean isDone() {
+            return doneFlag;
+        }
+    }
+
+    public boolean invokeMovePackage(String pkgName, int flags,
+            GenericReceiver receiver) throws Exception {
+        PackageMoveObserver observer = new PackageMoveObserver();
+        final boolean received = false;
+        mContext.registerReceiver(receiver, receiver.filter);
+        try {
+            // Wait on observer
+            synchronized(observer) {
+                synchronized (receiver) {
+                    getPm().movePackage(pkgName, observer, flags);
+                    long waitTime = 0;
+                    while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+                        observer.wait(WAIT_TIME_INCR);
+                        waitTime += WAIT_TIME_INCR;
+                    }
+                    if(!observer.isDone()) {
+                        throw new Exception("Timed out waiting for pkgmove callback");
+                    }
+                    if (observer.returnCode != PackageManager.MOVE_SUCCEEDED) {
+                        return false;
+                    }
+                    // Verify we received the broadcast
+                    waitTime = 0;
+                    while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+                        receiver.wait(WAIT_TIME_INCR);
+                        waitTime += WAIT_TIME_INCR;
+                    }
+                    if(!receiver.isDone()) {
+                        throw new Exception("Timed out waiting for MOVE notifications");
+                    }
+                    return receiver.received;
+                }
+            }
+        } finally {
+            mContext.unregisterReceiver(receiver);
+        }
+    }
+
+    /*
+     * Utility function that reads a apk bundled as a raw resource
+     * copies it into own data directory and invokes
+     * PackageManager api to install first and then replace it
+     * again.
+     */
+    public void moveFromRawResource(int installFlags, int moveFlags,
+            int expRetCode) {
+        // Install first
+        InstallParams ip = sampleInstallFromRawResource(installFlags, false);
+        ApplicationInfo oldAppInfo = null;
+        try {
+            oldAppInfo = getPm().getApplicationInfo(ip.pkg.packageName, 0);
+        } catch (NameNotFoundException e) {
+            failStr("Pkg hasnt been installed correctly");
+        }
+
+        // Create receiver based on expRetCode
+        MoveReceiver receiver = new MoveReceiver(ip.pkg.packageName);
+        try {
+            boolean retCode = invokeMovePackage(ip.pkg.packageName, moveFlags,
+                    receiver);
+            if (expRetCode == PackageManager.MOVE_SUCCEEDED) {
+                assertTrue(retCode);
+                ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.packageName, 0);
+                assertNotNull(info);
+                if ((moveFlags & PackageManager.MOVE_INTERNAL) != 0) {
+                    assertTrue((info.flags & ApplicationInfo.FLAG_ON_SDCARD) == 0);
+                } else if ((moveFlags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0){
+                    assertTrue((info.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0);
+                }
+            } else {
+                assertFalse(retCode);
+                ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.packageName, 0);
+                assertNotNull(info);
+                assertEquals(oldAppInfo.flags, info.flags);
+            }
+        } catch (Exception e) {
+            failStr("Failed with exception : " + e);
+        } finally {
+            cleanUpInstall(ip);
+        }
+    }
+
+    public void testMoveAppInternalToExternal() {
+        moveFromRawResource(0, PackageManager.MOVE_EXTERNAL_MEDIA,
+                PackageManager.MOVE_SUCCEEDED);
+    }
+
+    public void testMoveAppInternalToInternal() {
+        moveFromRawResource(0, PackageManager.MOVE_INTERNAL,
+                PackageManager.MOVE_FAILED_INVALID_LOCATION);
+    }
+
+    public void testMoveAppExternalToExternal() {
+        moveFromRawResource(PackageManager.INSTALL_EXTERNAL, PackageManager.MOVE_EXTERNAL_MEDIA,
+                PackageManager.MOVE_FAILED_INVALID_LOCATION);
+    }
+    public void testMoveAppExternalToInternal() {
+        moveFromRawResource(PackageManager.INSTALL_EXTERNAL, PackageManager.MOVE_INTERNAL,
+                PackageManager.MOVE_SUCCEEDED);
+    }
     /*
      * TODO's
      * check version numbers for upgrades
diff --git a/tests/CoreTests/android/AndroidManifest.xml b/tests/CoreTests/android/AndroidManifest.xml
index 98cc9e5..f02673c 100644
--- a/tests/CoreTests/android/AndroidManifest.xml
+++ b/tests/CoreTests/android/AndroidManifest.xml
@@ -34,19 +34,6 @@
     
     <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
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
index 50451e7..ce1bf8d 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
@@ -47,6 +47,7 @@
     private static final int EVENT_RELEASE_TOUCH_POINT = 16;
     private static final int EVENT_CLEAR_TOUCH_POINTS = 17;
     private static final int EVENT_CANCEL_TOUCH_POINT = 18;
+    private static final int EVENT_SET_TOUCH_MODIFIER = 19;
     
     private static final int LAYOUT_CLEAR_LIST = 20;
     private static final int LAYOUT_DISPLAY = 21;
@@ -145,6 +146,13 @@
             mEventSender.updateTouchPoint(id, x, y);
             break;
 
+        case EVENT_SET_TOUCH_MODIFIER:
+            Bundle modifierArgs = (Bundle) msg.obj;
+            String modifier = modifierArgs.getString("modifier");
+            boolean enabled = modifierArgs.getBoolean("enabled");
+            mEventSender.setTouchModifier(modifier, enabled);
+            break;
+
         case EVENT_RELEASE_TOUCH_POINT:
             mEventSender.releaseTouchPoint(msg.arg1);
             break;
@@ -320,7 +328,10 @@
     }
 
     public void setTouchModifier(String modifier, boolean enabled) {
-        // TODO(benm): Android doesn't support key modifiers on touch events yet.
+        Bundle map = new Bundle();
+        map.putString("modifier", modifier);
+        map.putBoolean("enabled", enabled);
+        obtainMessage(EVENT_SET_TOUCH_MODIFIER, map).sendToTarget();
     }
 
     public void touchMove() {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index 4d51356..ac980549 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -16,59 +16,47 @@
 
 package com.android.dumprendertree;
 
-import java.util.HashSet;
-import java.util.Hashtable;
+import java.util.Vector;
 import android.util.*;
 
 public class FileFilter {
 
+    private static final String LOGTAG = "FileFilter";
+
     public static boolean ignoreTest(String file) {
-      // treat files like directories for the time being.
-      for (int i = 0; i < ignoreTestList.length; i ++) {
-          if (file.endsWith(ignoreTestList[i])) {
-             Log.e("FileFilter", "File path in IgnoreTest: " + file); 
-             return true;
-          }
-      }
-      for (int i = 0; i < ignoreTestDirs.length; i++) {
-          if (file.endsWith(ignoreTestDirs[i])) {
-              Log.e("FileFilter", "File path in ignore list: " + file);
-              return true;
-          }
-      }
-      
-      return false;
-    }
- 
-    public static boolean ignoreResults(String file) {
-        int index = file.indexOf("fast");
-        if (index != -1) {
-            String sub = file.substring(index);
-            if (ignoreResultList.contains(sub))
+        // treat files like directories for the time being.
+        for (int i = 0; i < ignoreTestList.length; i ++) {
+            if (file.endsWith(ignoreTestList[i])) {
+                Log.v(LOGTAG, "File path in list of ignored tests: " + file);
                 return true;
+            }
+        }
+        for (int i = 0; i < ignoreTestDirs.length; i++) {
+            if (file.endsWith(ignoreTestDirs[i])) {
+                Log.v(LOGTAG, "File path in list of ignored directories: " + file);
+                return true;
+            }
+        }
+        // We should run tests for which the expected result is wrong, as there is
+        // value in checking that they don't cause crashes.
+        // TODO: Run these tests but ignore the result.
+        return ignoreResults(file);
+    }
+
+    public static boolean ignoreResults(String file) {
+        for (int i = 0; i < ignoreResultList.size(); i++) {
+            if (file.endsWith(ignoreResultList.get(i))) {
+                Log.v(LOGTAG, "File path in list of ignored results: " + file);
+                return true;
+            }
         }
         return false;
+      }
 
-    }
+    final static Vector<String> ignoreResultList = new Vector<String>();
 
-    public static String isKnownBug(String file) {
-        int index = file.indexOf("fast");
-        if (index != -1) {
-            String sub = file.substring(index);
-            // Log.e("FileFilter", "Looking for:"+sub);
-            if (bugList.containsKey(sub))
-                return bugList.get(sub);
-        }
-        return null;
-    }
-
-    final static HashSet<String> ignoreResultList = new HashSet<String>();
-    final static Hashtable<String, String> bugList = 
-        new Hashtable<String, String>();
- 
     static {
-        fillIgnoreResultSet();
-        fillBugTable();
+        fillIgnoreResultList();
     }
 
     static final String[] ignoreTestDirs = {
@@ -84,38 +72,35 @@
 
     static final String [] ignoreTestList = {
         "editing/selection/move-left-right.html",
-        "fast/events/touch/basic-multi-touch-events.html", // We do not support multi touch events.
         "fast/js/regexp-charclass-crash.html", // RegExp is too large, causing OOM
         "fast/regex/test1.html", // RegExp is exponential
         "fast/regex/slow.html", // RegExp is exponential
-        "storage/domstorage/localstorage/iframe-events.html", // Expects test to be in LayoutTests
         "storage/domstorage/localstorage/private-browsing-affects-storage.html", // No notion of private browsing.
-        "storage/domstorage/sessionstorage/iframe-events.html", // Expects test to be in LayoutTests
         "storage/domstorage/sessionstorage/private-browsing-affects-storage.html", // No notion of private browsing.
         "storage/private-browsing-readonly.html", // No notion of private browsing.
     };
 
-    static void fillIgnoreResultSet() {
+    static void fillIgnoreResultList() {
         ignoreResultList.add("fast/css/case-transform.html"); // will not fix #619707
-        ignoreResultList.add("fast/css/computed-style.html"); // different platform defaults for font and different screen size
         ignoreResultList.add("fast/dom/Element/offsetLeft-offsetTop-body-quirk.html"); // different screen size result in extra spaces in Apple compared to us
         ignoreResultList.add("fast/dom/Window/Plug-ins.html"); // need test plugin
         ignoreResultList.add("fast/dom/Window/window-properties.html"); // xslt and xpath elements missing from property list
         ignoreResultList.add("fast/dom/Window/window-screen-properties.html"); // pixel depth
         ignoreResultList.add("fast/dom/Window/window-xy-properties.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/dom/character-index-for-point.html"); // requires textInputController.characterIndexForPoint
+        ignoreResultList.add("fast/dom/attribute-namespaces-get-set.html"); // http://b/733229
         ignoreResultList.add("fast/dom/gc-9.html"); // requires xpath support
         ignoreResultList.add("fast/dom/global-constructors.html"); // requires xslt and xpath support
         ignoreResultList.add("fast/dom/object-embed-plugin-scripting.html"); // dynamic plugins not supported
         ignoreResultList.add("fast/dom/tabindex-clamp.html"); // there is extra spacing in the file due to multiple input boxes fitting on one line on Apple, ours are wrapped. Space at line ends are stripped.
         ignoreResultList.add("fast/events/anchor-image-scrolled-x-y.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/arrow-navigation.html"); // http://b/735233
         ignoreResultList.add("fast/events/capture-on-target.html"); // requires eventSender.mouseDown(),mouseUp()
         ignoreResultList.add("fast/events/dblclick-addEventListener.html"); // requires eventSender.mouseDown(),mouseUp()
         ignoreResultList.add("fast/events/drag-in-frames.html"); // requires eventSender.mouseDown(),mouseUp()
         ignoreResultList.add("fast/events/drag-outside-window.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/event-sender-mouse-click.html"); // requires eventSender.mouseDown(),mouseUp()
         ignoreResultList.add("fast/events/event-view-toString.html"); // requires eventSender.mouseDown(),mouseUp()
         ignoreResultList.add("fast/events/frame-click-focus.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/events/frame-tab-focus.html"); // http://b/734308
         ignoreResultList.add("fast/events/iframe-object-onload.html"); // there is extra spacing in the file due to multiple frame boxes fitting on one line on Apple, ours are wrapped. Space at line ends are stripped.
         ignoreResultList.add("fast/events/input-image-scrolled-x-y.html"); // requires eventSender.mouseDown(),mouseUp()
         ignoreResultList.add("fast/events/mouseclick-target-and-positioning.html"); // requires eventSender.mouseDown(),mouseUp()
@@ -123,70 +108,49 @@
         ignoreResultList.add("fast/events/mouseover-mouseout2.html"); // requires eventSender.mouseDown(),mouseUp()
         ignoreResultList.add("fast/events/mouseup-outside-button.html"); // requires eventSender.mouseDown(),mouseUp()
         ignoreResultList.add("fast/events/mouseup-outside-document.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/events/objc-event-api.html"); // eventSender.mouseDown(), mouseUp() and objc API missing
-        ignoreResultList.add("fast/events/objc-keyboard-event-creation.html"); // eventSender.mouseDown(), mouseUp() and objc API missing
         ignoreResultList.add("fast/events/onclick-list-marker.html"); // requires eventSender.mouseDown(),mouseUp()
         ignoreResultList.add("fast/events/ondragenter.html"); // requires eventSender.mouseDown(),mouseUp()
         ignoreResultList.add("fast/events/onload-webkit-before-webcore.html"); // missing space in textrun, ok as text is wrapped. ignore. #714933
+        ignoreResultList.add("fast/events/option-tab.html"); // http://b/734308
         ignoreResultList.add("fast/events/window-events-bubble.html"); // requires eventSender.mouseDown(),mouseUp()
         ignoreResultList.add("fast/events/window-events-bubble2.html"); // requires eventSender.mouseDown(),mouseUp()
         ignoreResultList.add("fast/events/window-events-capture.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/forms/attributed-strings.html"); // missing support for textInputController.makeAttributedString()
         ignoreResultList.add("fast/forms/drag-into-textarea.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/forms/focus-control-to-page.html"); // http://b/716638
+        ignoreResultList.add("fast/forms/focus2.html"); // http://b/735111
         ignoreResultList.add("fast/forms/form-data-encoding-2.html"); // charset convert. #516936 ignore, won't fix
         ignoreResultList.add("fast/forms/form-data-encoding.html"); // charset convert. #516936 ignore, won't fix
         ignoreResultList.add("fast/forms/input-appearance-maxlength.html"); // execCommand "insertText" not supported
         ignoreResultList.add("fast/forms/input-select-on-click.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/forms/input-truncate-newline.html"); // Copy&Paste commands not supported
         ignoreResultList.add("fast/forms/listbox-onchange.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/forms/listbox-selection.html"); // http://b/735116
         ignoreResultList.add("fast/forms/onselect-textarea.html"); // requires eventSender.mouseMoveTo, mouseDown & mouseUp and abs. position of mouse to select a word. ignore, won't fix #716583
         ignoreResultList.add("fast/forms/onselect-textfield.html"); // requires eventSender.mouseMoveTo, mouseDown & mouseUp and abs. position of mouse to select a word. ignore, won't fix #716583
         ignoreResultList.add("fast/forms/plaintext-mode-1.html"); // not implemented queryCommandEnabled:BackColor, Undo & Redo
         ignoreResultList.add("fast/forms/search-cancel-button-mouseup.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/forms/search-event-delay.html"); // http://b/735120
         ignoreResultList.add("fast/forms/select-empty-list.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/forms/select-type-ahead-non-latin.html"); // http://b/735244
         ignoreResultList.add("fast/forms/selected-index-assert.html"); // not capturing the console messages
         ignoreResultList.add("fast/forms/selection-functions.html"); // there is extra spacing as the text areas and input boxes fit next to each other on Apple, but are wrapped on our screen.
         ignoreResultList.add("fast/forms/textarea-appearance-wrap.html"); // Our text areas are a little thinner than Apples. Also RTL test failes
-        ignoreResultList.add("fast/forms/textarea-hard-linewrap.html"); // Our text areas are a little thinner than Apples
         ignoreResultList.add("fast/forms/textarea-initial-caret-position.html"); // Text selection done differently on our platform. When a inputbox gets focus, the entire block is selected.
         ignoreResultList.add("fast/forms/textarea-no-scroll-on-blur.html"); // Text selection done differently on our platform. When a inputbox gets focus, the entire block is selected.
         ignoreResultList.add("fast/forms/textarea-paste-newline.html"); // Copy&Paste commands not supported
         ignoreResultList.add("fast/forms/textarea-scrolled-endline-caret.html"); // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/frames/iframe-window-focus.html"); // http://b/735140
         ignoreResultList.add("fast/frames/frameElement-widthheight.html"); // screen width&height are different
         ignoreResultList.add("fast/frames/frame-js-url-clientWidth.html"); // screen width&height are different
+        ignoreResultList.add("fast/html/tab-order.html"); // http://b/719289
         ignoreResultList.add("fast/js/navigator-mimeTypes-length.html"); // dynamic plugins not supported
+        ignoreResultList.add("fast/js/string-capitalization.html"); // http://b/516936
         ignoreResultList.add("fast/loader/local-JavaScript-from-local.html"); // Requires LayoutTests to exist at /tmp/LayoutTests
         ignoreResultList.add("fast/loader/local-iFrame-source-from-local.html"); // Requires LayoutTests to exist at /tmp/LayoutTests
         ignoreResultList.add("fast/loader/opaque-base-url.html"); // extra spacing because iFrames rendered next to each other on Apple
+        ignoreResultList.add("fast/overflow/scroll-vertical-not-horizontal.html"); // http://b/735196
         ignoreResultList.add("fast/parser/script-tag-with-trailing-slash.html"); // not capturing the console messages
         ignoreResultList.add("fast/replaced/image-map.html"); // requires eventSender.mouseDown(),mouseUp()
-        ignoreResultList.add("fast/text/attributed-substring-from-range.html"); //  requires JS test API, textInputController
-        ignoreResultList.add("fast/text/attributed-substring-from-range-001.html"); //  requires JS test API, textInputController
         ignoreResultList.add("fast/text/plain-text-line-breaks.html"); // extra spacing because iFrames rendered next to each other on Apple
     }
 
-    static void fillBugTable() {
-        bugList.put("fast/forms/focus-control-to-page.html", "716638");
-        bugList.put("fast/html/tab-order.html", "719289");
-        bugList.put("fast/dom/attribute-namespaces-get-set.html", "733229");
-        bugList.put("fast/dom/set-innerHTML.html", "733823");
-        bugList.put("fast/dom/xmlhttprequest-get.html", "733846");
-        bugList.put("fast/encoding/css-charset-default.html", "733856");
-        bugList.put("fast/encoding/default-xhtml-encoding.html", "733882");
-        bugList.put("fast/encoding/meta-in-xhtml.html", "733882");
-        bugList.put("fast/events/frame-tab-focus.html", "734308");
-        bugList.put("fast/events/option-tab.html", "734308");
-        bugList.put("fast/forms/focus2.html", "735111");
-        bugList.put("fast/forms/listbox-selection.html", "735116");
-        bugList.put("fast/forms/search-event-delay.html", "735120");
-        bugList.put("fast/frames/iframe-window-focus.html", "735140");
-        bugList.put("fast/innerHTML/004.html", "733882");
-        bugList.put("fast/js/string-capitalization.html", "516936");
-        bugList.put("fast/js/string-concatenate-outofmemory.html","735152");
-        bugList.put("fast/parser/external-entities.html", "735176");
-        bugList.put("fast/overflow/scroll-vertical-not-horizontal.html", "735196");
-        bugList.put("fast/events/arrow-navigation.html", "735233");
-        bugList.put("fast/forms/select-type-ahead-non-latin.html", "735244");
-    }
-
 }
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
index 1a265e8..ef0c6c6 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
@@ -54,6 +54,9 @@
         String[] files = d.list();
         for (int i = 0; i < files.length; i++) {
             String s = dir + "/" + files[i];
+            if (s.endsWith("TEMPLATE.html")) {
+                continue;
+            }
             if (FileFilter.ignoreTest(s)) {
                 Log.v(LOGTAG, "  Ignoring: " + s);
                 continue;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 2667520..02a7046 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -716,6 +716,7 @@
         mCanOpenWindows = false;
         mEventSender.resetMouse();
         mEventSender.clearTouchPoints();
+        mEventSender.clearTouchMetaState();
         mPageFinished = false;
         mOneHundredPercentComplete = false;
         mDumpWebKitData = false;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java b/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java
index 996eaba..0c2347d 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java
@@ -207,7 +207,7 @@
 
         tp.setDownTime(SystemClock.uptimeMillis());
         MotionEvent event = MotionEvent.obtain(tp.downTime(), tp.downTime(),
-                MotionEvent.ACTION_DOWN, tp.getX(), tp.getY(), 0);
+                MotionEvent.ACTION_DOWN, tp.getX(), tp.getY(), mTouchMetaState);
         mWebView.onTouchEvent(event);
     }
 
@@ -223,7 +223,7 @@
         }
 
         MotionEvent event = MotionEvent.obtain(tp.downTime(), SystemClock.uptimeMillis(),
-                MotionEvent.ACTION_MOVE, tp.getX(), tp.getY(), 0);
+                MotionEvent.ACTION_MOVE, tp.getX(), tp.getY(), mTouchMetaState);
         mWebView.onTouchEvent(event);
 
         tp.setMoved(false);
@@ -237,7 +237,7 @@
         }
 
         MotionEvent event = MotionEvent.obtain(tp.downTime(), SystemClock.uptimeMillis(),
-                MotionEvent.ACTION_UP, tp.getX(), tp.getY(), 0);
+                MotionEvent.ACTION_UP, tp.getX(), tp.getY(), mTouchMetaState);
         mWebView.onTouchEvent(event);
 
         if (tp.isReleased()) {
@@ -253,7 +253,7 @@
 
         if (tp.cancelled()) {
             MotionEvent event = MotionEvent.obtain(tp.downTime(), SystemClock.uptimeMillis(),
-                    MotionEvent.ACTION_CANCEL, tp.getX(), tp.getY(), 0);
+                    MotionEvent.ACTION_CANCEL, tp.getX(), tp.getY(), mTouchMetaState);
             mWebView.onTouchEvent(event);
         }
     }
@@ -285,8 +285,20 @@
     }
 
     public void setTouchModifier(String modifier, boolean enabled) {
-        // TODO(benm): This needs implementing when Android supports sending key modifiers
-        // in touch events.
+        int mask = 0;
+        if ("alt".equals(modifier.toLowerCase())) {
+            mask = KeyEvent.META_ALT_ON;
+        } else if ("shift".equals(modifier.toLowerCase())) {
+            mask = KeyEvent.META_SHIFT_ON;
+        } else if ("ctrl".equals(modifier.toLowerCase())) {
+            mask = KeyEvent.META_SYM_ON;
+        }
+
+        if (enabled) {
+            mTouchMetaState |= mask;
+        } else {
+            mTouchMetaState &= ~mask;
+        }
     }
 
     public void releaseTouchPoint(int id) {
@@ -302,6 +314,10 @@
         mTouchPoints.clear();
     }
 
+    public void clearTouchMetaState() {
+        mTouchMetaState = 0;
+    }
+
     private int contentsToWindowX(int x) {
         return (int) (x * mWebView.getScale()) - mWebView.getScrollX();
     }
@@ -352,4 +368,5 @@
     };
 
     private Vector<TouchPoint> mTouchPoints;
+    private int mTouchMetaState;
 }
diff --git a/tests/backup/Android.mk b/tests/backup/Android.mk
index 0813c35..498ec40 100644
--- a/tests/backup/Android.mk
+++ b/tests/backup/Android.mk
@@ -23,6 +23,7 @@
  
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := backup_helper_test
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 LOCAL_SHARED_LIBRARIES := libutils
 
 include $(BUILD_EXECUTABLE)
@@ -33,6 +34,8 @@
 
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
 LOCAL_PACKAGE_NAME := BackupTest
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 663a33a..69b2207 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -938,17 +938,17 @@
     uint8_t mask = 0;
     uint8_t value = 0;
     if (strcmp(name, kWildcardName) == 0) {
-        mask = out->MASK_KEYSHIDDEN;
-        value = out->KEYSHIDDEN_ANY;
+        mask = ResTable_config::MASK_KEYSHIDDEN;
+        value = ResTable_config::KEYSHIDDEN_ANY;
     } else if (strcmp(name, "keysexposed") == 0) {
-        mask = out->MASK_KEYSHIDDEN;
-        value = out->KEYSHIDDEN_NO;
+        mask = ResTable_config::MASK_KEYSHIDDEN;
+        value = ResTable_config::KEYSHIDDEN_NO;
     } else if (strcmp(name, "keyshidden") == 0) {
-        mask = out->MASK_KEYSHIDDEN;
-        value = out->KEYSHIDDEN_YES;
+        mask = ResTable_config::MASK_KEYSHIDDEN;
+        value = ResTable_config::KEYSHIDDEN_YES;
     } else if (strcmp(name, "keyssoft") == 0) {
-        mask = out->MASK_KEYSHIDDEN;
-        value = out->KEYSHIDDEN_SOFT;
+        mask = ResTable_config::MASK_KEYSHIDDEN;
+        value = ResTable_config::KEYSHIDDEN_SOFT;
     }
 
     if (mask != 0) {
@@ -985,14 +985,14 @@
     uint8_t mask = 0;
     uint8_t value = 0;
     if (strcmp(name, kWildcardName) == 0) {
-        mask = out->MASK_NAVHIDDEN;
-        value = out->NAVHIDDEN_ANY;
+        mask = ResTable_config::MASK_NAVHIDDEN;
+        value = ResTable_config::NAVHIDDEN_ANY;
     } else if (strcmp(name, "navexposed") == 0) {
-        mask = out->MASK_NAVHIDDEN;
-        value = out->NAVHIDDEN_NO;
+        mask = ResTable_config::MASK_NAVHIDDEN;
+        value = ResTable_config::NAVHIDDEN_NO;
     } else if (strcmp(name, "navhidden") == 0) {
-        mask = out->MASK_NAVHIDDEN;
-        value = out->NAVHIDDEN_YES;
+        mask = ResTable_config::MASK_NAVHIDDEN;
+        value = ResTable_config::NAVHIDDEN_YES;
     }
 
     if (mask != 0) {
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index a389bfb..0b531c2 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -382,7 +382,7 @@
         }
         attr.createIfNeeded(outTable);
         if (!attr.hasErrors) {
-            char buf[10];
+            char buf[11];
             sprintf(buf, "%d", l10n_required);
             err = outTable->addBag(attr.sourcePos, myPackage, attr16, attr.ident,
                     String16(""), String16("^l10n"), String16(buf), NULL, NULL);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 990498f..41d9f9d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -30,6 +30,7 @@
 import com.android.tools.layoutlib.create.MethodAdapter;
 import com.android.tools.layoutlib.create.OverrideMethod;
 
+import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Rect;
@@ -1133,7 +1134,7 @@
         }
 
         @SuppressWarnings("unused")
-        public void resized(int arg0, int arg1, Rect arg2, Rect arg3, boolean arg4)
+        public void resized(int arg0, int arg1, Rect arg2, Rect arg3, boolean arg4, Configuration arg5)
                 throws RemoteException {
             // pass for now.
         }