Merge "LayoutLib: move asserts around." into honeycomb
diff --git a/api/11.xml b/api/11.xml
index 43bb440..e2f8025 100644
--- a/api/11.xml
+++ b/api/11.xml
@@ -61129,17 +61129,6 @@
  visibility="public"
 >
 </method>
-<method name="getGL"
- return="javax.microedition.khronos.opengles.GL"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="getHeight"
  return="int"
  abstract="false"
diff --git a/api/current.xml b/api/current.xml
index 57a76de..344d6b4 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -1255,17 +1255,6 @@
  visibility="public"
 >
 </field>
-<field name="WRITE_MEDIA_STORAGE"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.permission.WRITE_MEDIA_STORAGE&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="WRITE_SECURE_SETTINGS"
  type="java.lang.String"
  transient="false"
@@ -58409,6 +58398,17 @@
  visibility="public"
 >
 </method>
+<method name="isEnabled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <field name="applicationInfo"
  type="android.content.pm.ApplicationInfo"
  transient="false"
@@ -78255,17 +78255,6 @@
  visibility="public"
 >
 </method>
-<method name="getGL"
- return="javax.microedition.khronos.opengles.GL"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="deprecated"
- visibility="protected"
->
-</method>
 <method name="getHeight"
  return="int"
  abstract="false"
@@ -136934,6 +136923,19 @@
  deprecated="not deprecated"
  visibility="protected"
 >
+<parameter name="result" type="Result">
+</parameter>
+</method>
+<method name="onCancelled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
 </method>
 <method name="onPostExecute"
  return="void"
@@ -166353,8 +166355,6 @@
 </parameter>
 <parameter name="mips" type="android.renderscript.Allocation.MipmapControl">
 </parameter>
-<parameter name="layout" type="android.renderscript.Allocation.CubemapLayout">
-</parameter>
 <parameter name="usage" type="int">
 </parameter>
 </method>
@@ -166372,8 +166372,6 @@
 </parameter>
 <parameter name="b" type="android.graphics.Bitmap">
 </parameter>
-<parameter name="layout" type="android.renderscript.Allocation.CubemapLayout">
-</parameter>
 </method>
 <method name="createFromBitmap"
  return="android.renderscript.Allocation"
@@ -166633,39 +166631,6 @@
 >
 </field>
 </class>
-<class name="Allocation.CubemapLayout"
- extends="java.lang.Enum"
- abstract="false"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-<method name="valueOf"
- return="android.renderscript.Allocation.CubemapLayout"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="name" type="java.lang.String">
-</parameter>
-</method>
-<method name="values"
- return="android.renderscript.Allocation.CubemapLayout[]"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-</class>
 <class name="Allocation.MipmapControl"
  extends="java.lang.Enum"
  abstract="false"
@@ -198616,6 +198581,17 @@
 <exception name="IOException" type="java.io.IOException">
 </exception>
 </method>
+<method name="isLenient"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="nextBoolean"
  return="boolean"
  abstract="false"
@@ -198746,21 +198722,6 @@
 <exception name="IOException" type="java.io.IOException">
 </exception>
 </method>
-<method name="syntaxError"
- return="java.io.IOException"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="message" type="java.lang.String">
-</parameter>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-</method>
 </class>
 <class name="JsonToken"
  extends="java.lang.Enum"
@@ -198893,6 +198854,17 @@
 <exception name="IOException" type="java.io.IOException">
 </exception>
 </method>
+<method name="isLenient"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="name"
  return="android.util.JsonWriter"
  abstract="false"
@@ -198934,6 +198906,19 @@
 <parameter name="indent" type="java.lang.String">
 </parameter>
 </method>
+<method name="setLenient"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="lenient" type="boolean">
+</parameter>
+</method>
 <method name="value"
  return="android.util.JsonWriter"
  abstract="false"
@@ -198994,6 +198979,21 @@
 <exception name="IOException" type="java.io.IOException">
 </exception>
 </method>
+<method name="value"
+ return="android.util.JsonWriter"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="java.lang.Number">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
 </class>
 <class name="Log"
  extends="java.lang.Object"
@@ -199373,6 +199373,25 @@
 </parameter>
 </method>
 </class>
+<class name="MalformedJsonException"
+ extends="java.io.IOException"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="MalformedJsonException"
+ type="android.util.MalformedJsonException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="message" type="java.lang.String">
+</parameter>
+</constructor>
+</class>
 <class name="MonthDisplayHelper"
  extends="java.lang.Object"
  abstract="false"
@@ -258003,7 +258022,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="t" type="T">
+<parameter name="arg0" type="T">
 </parameter>
 </method>
 </interface>
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 8b292c9..0bce748 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -237,43 +237,7 @@
     private BroadcastReceiver mConnectivityIntentReceiver =
             new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
-            NetworkInfo networkInfo =
-                    intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
-            NetworkInfo.State state = (networkInfo == null ? NetworkInfo.State.UNKNOWN :
-                    networkInfo.getState());
-            if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                Log.v(TAG, "received connectivity action.  network info: " + networkInfo);
-            }
-
-            final boolean wasConnected = mDataConnectionIsConnected;
-            // only pay attention to the CONNECTED and DISCONNECTED states.
-            // if connected, we are connected.
-            // if disconnected, we may not be connected.  in some cases, we may be connected on
-            // a different network.
-            // e.g., if switching from GPRS to WiFi, we may receive the CONNECTED to WiFi and
-            // DISCONNECTED for GPRS in any order.  if we receive the CONNECTED first, and then
-            // a DISCONNECTED, we want to make sure we set mDataConnectionIsConnected to true
-            // since we still have a WiFi connection.
-            switch (state) {
-                case CONNECTED:
-                    mDataConnectionIsConnected = true;
-                    break;
-                case DISCONNECTED:
-                    mDataConnectionIsConnected = !intent.getBooleanExtra(
-                            ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
-                    break;
-                default:
-                    // ignore the rest of the states -- leave our boolean alone.
-            }
-            if (mDataConnectionIsConnected) {
-                if (!wasConnected) {
-                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                        Log.v(TAG, "Reconnection detected: clearing all backoffs");
-                    }
-                    mSyncStorageEngine.clearAllBackoffs();
-                }
-                sendCheckAlarmsMessage();
-            }
+            sendCheckAlarmsMessage();
         }
     };
 
@@ -1409,8 +1373,12 @@
         public void handleMessage(Message msg) {
             long earliestFuturePollTime = Long.MAX_VALUE;
             long nextPendingSyncTime = Long.MAX_VALUE;
+            // Setting the value here instead of a method because we want the dumpsys logs
+            // to have the most recent value used.
             try {
                 waitUntilReadyToRun();
+                NetworkInfo info = getConnectivityManager().getActiveNetworkInfo();
+                mDataConnectionIsConnected = (info != null) && info.isConnected();
                 mSyncManagerWakeLock.acquire();
                 // Always do this first so that we be sure that any periodic syncs that
                 // are ready to run have been converted into pending syncs. This allows the
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index f16c4ef..2812477 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -98,6 +98,13 @@
         }
         return name;
     }
+
+    /**
+     * Return whether this component and its enclosing application are enabled.
+     */
+    public boolean isEnabled() {
+        return enabled && applicationInfo.enabled;
+    }
     
     /**
      * Return the icon resource identifier to use for this component.  If
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index 5e96928..c76cc6c 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -131,6 +131,10 @@
             long retValue = native_1x1_long();
             mDatabase.logTimeStat(mSql, timeStart);
             return retValue;
+        } catch (SQLiteDoneException e) {
+            throw new SQLiteDoneException(
+                    "expected 1 row from this query but query returned no data. check the query: " +
+                    mSql);
         } finally {
             releaseAndUnlock();
         }
@@ -150,6 +154,10 @@
             String retValue = native_1x1_string();
             mDatabase.logTimeStat(mSql, timeStart);
             return retValue;
+        } catch (SQLiteDoneException e) {
+            throw new SQLiteDoneException(
+                    "expected 1 row from this query but query returned no data. check the query: " +
+                    mSql);
         } finally {
             releaseAndUnlock();
         }
@@ -172,6 +180,10 @@
         } catch (IOException ex) {
             Log.e(TAG, "simpleQueryForBlobFileDescriptor() failed", ex);
             return null;
+        } catch (SQLiteDoneException e) {
+            throw new SQLiteDoneException(
+                    "expected 1 row from this query but query returned no data. check the query: " +
+                    mSql);
         } finally {
             releaseAndUnlock();
         }
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 46a29a9..9f7e31c 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -26,6 +26,7 @@
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -115,11 +116,11 @@
  * <h2>Cancelling a task</h2>
  * <p>A task can be cancelled at any time by invoking {@link #cancel(boolean)}. Invoking
  * this method will cause subsequent calls to {@link #isCancelled()} to return true.
- * After invoking this method, {@link #onCancelled()}, instead of {@link #onPostExecute(Object)}
- * will be invoked after {@link #doInBackground(Object[])} returns. To ensure that
- * a task is cancelled as quickly as possible, you should always check the return
- * value of {@link #isCancelled()} periodically from {@link #doInBackground(Object[])},
- * if possible (inside a loop for instance.)</p>
+ * After invoking this method, {@link #onCancelled(Object)}, instead of
+ * {@link #onPostExecute(Object)} will be invoked after {@link #doInBackground(Object[])}
+ * returns. To ensure that a task is cancelled as quickly as possible, you should always
+ * check the return value of {@link #isCancelled()} periodically from
+ * {@link #doInBackground(Object[])}, if possible (inside a loop for instance.)</p>
  *
  * <h2>Threading rules</h2>
  * <p>There are a few threading rules that must be followed for this class to
@@ -173,6 +174,8 @@
     private final FutureTask<Result> mFuture;
 
     private volatile Status mStatus = Status.PENDING;
+    
+    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
 
     /**
      * Indicates the current status of the task. Each status will be set only once
@@ -204,15 +207,10 @@
     public AsyncTask() {
         mWorker = new WorkerRunnable<Params, Result>() {
             public Result call() throws Exception {
+                mTaskInvoked.set(true);
+
                 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-
-                Result result = doInBackground(mParams);
-
-                Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
-                        new AsyncTaskResult<Result>(AsyncTask.this, result));
-                message.sendToTarget();
-
-                return result;
+                return postResult(doInBackground(mParams));
             }
         };
 
@@ -220,14 +218,16 @@
             @Override
             protected void done() {
                 try {
-                    get();
+                    final Result result = get();
+
+                    postResultIfNotInvoked(result);
                 } catch (InterruptedException e) {
                     android.util.Log.w(LOG_TAG, e);
                 } catch (ExecutionException e) {
                     throw new RuntimeException("An error occured while executing doInBackground()",
                             e.getCause());
                 } catch (CancellationException e) {
-                    // Taken care of in the WorkerRunnable
+                    postResultIfNotInvoked(null);
                 } catch (Throwable t) {
                     throw new RuntimeException("An error occured while executing "
                             + "doInBackground()", t);
@@ -236,6 +236,20 @@
         };
     }
 
+    private void postResultIfNotInvoked(Result result) {
+        final boolean wasTaskInvoked = mTaskInvoked.get();
+        if (!wasTaskInvoked) {
+            postResult(result);
+        }
+    }
+
+    private Result postResult(Result result) {
+        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
+                new AsyncTaskResult<Result>(this, result));
+        message.sendToTarget();
+        return result;
+    }
+
     /**
      * Returns the current status of this task.
      *
@@ -282,7 +296,7 @@
      *
      * @see #onPreExecute
      * @see #doInBackground
-     * @see #onCancelled() 
+     * @see #onCancelled(Object) 
      */
     @SuppressWarnings({"UnusedDeclaration"})
     protected void onPostExecute(Result result) {
@@ -302,9 +316,33 @@
     }
 
     /**
-     * Runs on the UI thread after {@link #cancel(boolean)} is invoked and
-     * {@link #doInBackground(Object[])} has finished.
+     * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
+     * {@link #doInBackground(Object[])} has finished.</p>
+     * 
+     * <p>The default implementation simply invokes {@link #onCancelled()} and
+     * ignores the result. If you write your own implementation, do not call
+     * <code>super.onCancelled(result)</code>.</p>
      *
+     * @param result The result, if any, computed in
+     *               {@link #doInBackground(Object[])}, can be null
+     * 
+     * @see #cancel(boolean)
+     * @see #isCancelled()
+     */
+    @SuppressWarnings({"UnusedParameters"})
+    protected void onCancelled(Result result) {
+        onCancelled();
+    }    
+    
+    /**
+     * <p>Applications should preferably override {@link #onCancelled(Object)}.
+     * This method is invoked by the default implementation of
+     * {@link #onCancelled(Object)}.</p>
+     * 
+     * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
+     * {@link #doInBackground(Object[])} has finished.</p>
+     *
+     * @see #onCancelled(Object) 
      * @see #cancel(boolean)
      * @see #isCancelled()
      */
@@ -335,7 +373,7 @@
      * whether the thread executing this task should be interrupted in
      * an attempt to stop the task.</p>
      * 
-     * <p>Calling this method will result in {@link #onCancelled()} being
+     * <p>Calling this method will result in {@link #onCancelled(Object)} being
      * invoked on the UI thread after {@link #doInBackground(Object[])}
      * returns. Calling this method guarantees that {@link #onPostExecute(Object)}
      * is never invoked. After invoking this method, you should check the
@@ -352,7 +390,7 @@
      *         <tt>true</tt> otherwise
      *
      * @see #isCancelled()
-     * @see #onCancelled()
+     * @see #onCancelled(Object)
      */
     public final boolean cancel(boolean mayInterruptIfRunning) {
         return mFuture.cancel(mayInterruptIfRunning);
@@ -452,7 +490,7 @@
 
     private void finish(Result result) {
         if (isCancelled()) {
-            onCancelled();
+            onCancelled(result);
         } else {
             onPostExecute(result);
         }
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index d1ca0c9..ee091f0 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -3430,12 +3430,6 @@
      * <th colspan='4'>PhoneLookup</th>
      * </tr>
      * <tr>
-     * <td>long</td>
-     * <td>{@link #_ID}</td>
-     * <td>read-only</td>
-     * <td>Data row ID.</td>
-     * </tr>
-     * <tr>
      * <td>String</td>
      * <td>{@link #NUMBER}</td>
      * <td>read-only</td>
@@ -3462,6 +3456,12 @@
      * <th colspan='4'>Join with {@link Contacts}</th>
      * </tr>
      * <tr>
+     * <td>long</td>
+     * <td>{@link #_ID}</td>
+     * <td>read-only</td>
+     * <td>Contact ID.</td>
+     * </tr>
+     * <tr>
      * <td>String</td>
      * <td>{@link #LOOKUP_KEY}</td>
      * <td>read-only</td>
diff --git a/core/java/android/util/JsonReader.java b/core/java/android/util/JsonReader.java
index 8025545..8f44895 100644
--- a/core/java/android/util/JsonReader.java
+++ b/core/java/android/util/JsonReader.java
@@ -16,6 +16,7 @@
 
 package android.util;
 
+import java.io.EOFException;
 import java.io.IOException;
 import java.io.Reader;
 import java.io.Closeable;
@@ -249,6 +250,13 @@
     }
 
     /**
+     * Returns true if this parser is liberal in what it accepts.
+     */
+    public boolean isLenient() {
+        return lenient;
+    }
+
+    /**
      * Consumes the next token from the JSON stream and asserts that it is the
      * beginning of a new array.
      */
@@ -311,7 +319,7 @@
             case EMPTY_DOCUMENT:
                 replaceTop(JsonScope.NONEMPTY_DOCUMENT);
                 JsonToken firstToken = nextValue();
-                if (token != JsonToken.BEGIN_ARRAY && token != JsonToken.BEGIN_OBJECT) {
+                if (!lenient && token != JsonToken.BEGIN_ARRAY && token != JsonToken.BEGIN_OBJECT) {
                     throw new IOException(
                             "Expected JSON document to start with '[' or '{' but was " + token);
                 }
@@ -327,7 +335,15 @@
             case NONEMPTY_OBJECT:
                 return nextInObject(false);
             case NONEMPTY_DOCUMENT:
-                return token = JsonToken.END_DOCUMENT;
+                try {
+                    JsonToken token = nextValue();
+                    if (lenient) {
+                        return token;
+                    }
+                    throw syntaxError("Expected EOF");
+                } catch (EOFException e) {
+                    return token = JsonToken.END_DOCUMENT; // TODO: avoid throwing here?
+                }
             case CLOSED:
                 throw new IllegalStateException("JsonReader is closed");
             default:
@@ -758,7 +774,7 @@
             }
         }
 
-        throw syntaxError("End of input");
+        throw new EOFException("End of input");
     }
 
     private void checkLenient() throws IOException {
@@ -1030,8 +1046,6 @@
      * form -12.34e+56. Fractional and exponential parts are optional. Leading
      * zeroes are not allowed in the value or exponential part, but are allowed
      * in the fraction.
-     *
-     * <p>This has a side effect of setting isInteger.
      */
     private JsonToken decodeNumber(char[] chars, int offset, int length) {
         int i = offset;
@@ -1085,8 +1099,8 @@
      * Throws a new IO exception with the given message and a context snippet
      * with this reader's content.
      */
-    public IOException syntaxError(String message) throws IOException {
-        throw new JsonSyntaxException(message + " near " + getSnippet());
+    private IOException syntaxError(String message) throws IOException {
+        throw new MalformedJsonException(message + " near " + getSnippet());
     }
 
     private CharSequence getSnippet() {
@@ -1097,10 +1111,4 @@
         snippet.append(buffer, pos, afterPos);
         return snippet;
     }
-
-    private static class JsonSyntaxException extends IOException {
-        private JsonSyntaxException(String s) {
-            super(s);
-        }
-    }
 }
diff --git a/core/java/android/util/JsonWriter.java b/core/java/android/util/JsonWriter.java
index 89cad79..47e84c5 100644
--- a/core/java/android/util/JsonWriter.java
+++ b/core/java/android/util/JsonWriter.java
@@ -138,6 +138,8 @@
      */
     private String separator = ":";
 
+    private boolean lenient;
+
     /**
      * Creates a new instance that writes a JSON-encoded stream to {@code out}.
      * For best performance, ensure {@link Writer} is buffered; wrapping in
@@ -169,6 +171,29 @@
     }
 
     /**
+     * Configure this writer to relax its syntax rules. By default, this writer
+     * only emits well-formed JSON as specified by <a
+     * href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>. Setting the writer
+     * to lenient permits the following:
+     * <ul>
+     *   <li>Top-level values of any type. With strict writing, the top-level
+     *       value must be an object or an array.
+     *   <li>Numbers may be {@link Double#isNaN() NaNs} or {@link
+     *       Double#isInfinite() infinities}.
+     * </ul>
+     */
+    public void setLenient(boolean lenient) {
+        this.lenient = lenient;
+    }
+
+    /**
+     * Returns true if this writer has relaxed syntax rules.
+     */
+    public boolean isLenient() {
+        return lenient;
+    }
+
+    /**
      * Begins encoding a new array. Each call to this method must be paired with
      * a call to {@link #endArray}.
      *
@@ -306,11 +331,11 @@
      * Encodes {@code value}.
      *
      * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
-     *     {@link Double#isInfinite() infinities}.
+     *     {@link Double#isInfinite() infinities} unless this writer is lenient.
      * @return this writer.
      */
     public JsonWriter value(double value) throws IOException {
-        if (Double.isNaN(value) || Double.isInfinite(value)) {
+        if (!lenient && (Double.isNaN(value) || Double.isInfinite(value))) {
             throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
         }
         beforeValue(false);
@@ -330,6 +355,28 @@
     }
 
     /**
+     * Encodes {@code value}.
+     *
+     * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
+     *     {@link Double#isInfinite() infinities} unless this writer is lenient.
+     * @return this writer.
+     */
+    public JsonWriter value(Number value) throws IOException {
+        if (value == null) {
+            return nullValue();
+        }
+
+        String string = value.toString();
+        if (!lenient &&
+                (string.equals("-Infinity") || string.equals("Infinity") || string.equals("NaN"))) {
+            throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
+        }
+        beforeValue(false);
+        out.append(string);
+        return this;
+    }
+
+    /**
      * Ensures all buffered data is written to the underlying {@link Writer}
      * and flushes that writer.
      */
@@ -364,7 +411,6 @@
             switch (c) {
                 case '"':
                 case '\\':
-                case '/':
                     out.write('\\');
                     out.write(c);
                     break;
@@ -439,7 +485,7 @@
     private void beforeValue(boolean root) throws IOException {
         switch (peek()) {
             case EMPTY_DOCUMENT: // first in document
-                if (!root) {
+                if (!lenient && !root) {
                     throw new IllegalStateException(
                             "JSON must start with an array or an object.");
                 }
diff --git a/core/java/android/util/MalformedJsonException.java b/core/java/android/util/MalformedJsonException.java
new file mode 100644
index 0000000..63c19ff
--- /dev/null
+++ b/core/java/android/util/MalformedJsonException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 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.util;
+
+import java.io.IOException;
+
+/**
+ * Thrown when a reader encounters malformed JSON. Some syntax errors can be
+ * ignored by calling {@link JsonReader#setLenient(boolean)}.
+ */
+public final class MalformedJsonException extends IOException {
+    private static final long serialVersionUID = 1L;
+
+    public MalformedJsonException(String message) {
+        super(message);
+    }
+}
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 4c2f0b4..1313fcc 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -204,11 +204,6 @@
             case KeyEvent.KEYCODE_DPAD_RIGHT:
             case KeyEvent.KEYCODE_DPAD_UP:
             case KeyEvent.KEYCODE_DPAD_DOWN:
-                if (!mWebView.nativeCursorMatchesFocus()) {
-                    return down ? mWebView.onKeyDown(keyCode, event) : mWebView
-                            .onKeyUp(keyCode, event);
-
-                }
                 isArrowKey = true;
                 break;
         }
@@ -258,10 +253,6 @@
             if (isPopupShowing()) {
                 return super.dispatchKeyEvent(event);
             }
-            if (!mWebView.nativeCursorMatchesFocus()) {
-                return down ? mWebView.onKeyDown(keyCode, event) : mWebView
-                        .onKeyUp(keyCode, event);
-            }
             // Center key should be passed to a potential onClick
             if (!down) {
                 mWebView.centerKeyPressOnTextField();
@@ -753,12 +744,7 @@
         if (event.getAction() != MotionEvent.ACTION_MOVE) {
             return false;
         }
-        // If the Cursor is not on the text input, webview should handle the
-        // trackball
-        if (!mWebView.nativeCursorMatchesFocus()) {
-            return mWebView.onTrackballEvent(event);
-        }
-        Spannable text = (Spannable) getText();
+        Spannable text = getText();
         MovementMethod move = getMovementMethod();
         if (move != null && getLayout() != null &&
             move.onTrackballEvent(this, text, event)) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 61f0bce..e8283a6 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -56,6 +56,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.os.SystemClock;
 import android.provider.Settings;
 import android.speech.tts.TextToSpeech;
 import android.text.Selection;
@@ -2961,12 +2962,12 @@
      * @return boolean True if the find dialog is shown, false otherwise.
      */
     public boolean showFindDialog(String text, boolean showIme) {
-        mFindCallback = new FindActionModeCallback(mContext);
-        if (startActionMode(mFindCallback) == null) {
+        FindActionModeCallback callback = new FindActionModeCallback(mContext);
+        if (startActionMode(callback) == null) {
             // Could not start the action mode, so end Find on page
-            mFindCallback = null;
             return false;
         }
+        mFindCallback = callback;
         setFindIsUp(true);
         mFindCallback.setWebView(this);
         if (showIme) {
@@ -4564,14 +4565,6 @@
             return true;
         }
 
-        if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
-                || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
-            if (!nativePageShouldHandleShiftAndArrows() && !nativeCursorWantsKeyEvents()
-                    && !mSelectingText) {
-                setUpSelect();
-            }
-        }
-
         if (keyCode == KeyEvent.KEYCODE_PAGE_UP) {
             if (event.hasNoModifiers()) {
                 pageUp(false);
@@ -4662,12 +4655,6 @@
             if (!wantsKeyEvents) return false;
         }
 
-        if (keyCode != KeyEvent.KEYCODE_SHIFT_LEFT
-                && keyCode != KeyEvent.KEYCODE_SHIFT_RIGHT) {
-            // turn off copy select if a shift-key combo is pressed
-            selectionDone();
-        }
-
         if (getSettings().getNavDump()) {
             switch (keyCode) {
                 case KeyEvent.KEYCODE_4:
@@ -4766,14 +4753,6 @@
             return true;
         }
 
-        if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT
-                || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) {
-            if (!nativePageShouldHandleShiftAndArrows() && copySelection()) {
-                selectionDone();
-                return true;
-            }
-        }
-
         if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
                 && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) {
             if (nativePageShouldHandleShiftAndArrows()) {
@@ -5234,7 +5213,8 @@
         // Textfields, plugins, and contentEditable nodes need to receive the
         // shift up key even if another key was released while the shift key
         // was held down.
-        if (!inEditingMode() && (mNativeClass == 0
+        boolean inEditingMode = inEditingMode();
+        if (!inEditingMode && (mNativeClass == 0
                 || !nativePageShouldHandleShiftAndArrows())) {
             if (event.getAction() == KeyEvent.ACTION_DOWN) {
                 mGotKeyDown = true;
@@ -5251,7 +5231,13 @@
         }
 
         if (dispatch) {
-            return super.dispatchKeyEvent(event);
+            if (inEditingMode) {
+                // Ensure that the WebTextView gets the event, even if it does
+                // not currently have a bounds.
+                return mWebTextView.dispatchKeyEvent(event);
+            } else {
+                return super.dispatchKeyEvent(event);
+            }
         } else {
             // We didn't dispatch, so let something else handle the key
             return false;
@@ -5344,17 +5330,10 @@
                 + " numPointers=" + ev.getPointerCount());
         }
 
-        int action = ev.getAction();
-        float x = ev.getX();
-        float y = ev.getY();
-        long eventTime = ev.getEventTime();
-
-        // mDeferMultitouch is a hack for layout tests, where it is used to
-        // force passing multi-touch events to webkit.
-        // FIXME: always pass multi-touch events to webkit and remove everything
-        // related to mDeferMultitouch.
-        if (ev.getPointerCount() > 1 &&
-                (mDeferMultitouch || mZoomManager.isZoomScaleFixed())) {
+        // Always pass multi-touch event to WebKit first.
+        // If WebKit doesn't consume it and set preventDefault to true,
+        // WebView's private handler will handle it.
+        if (ev.getPointerCount() > 1) {
             if (DebugFlags.WEB_VIEW) {
                 Log.v(LOGTAG, "passing " + ev.getPointerCount() + " points to webkit");
             }
@@ -5362,59 +5341,15 @@
             return true;
         }
 
-        final ScaleGestureDetector detector =
-                mZoomManager.getMultiTouchGestureDetector();
+        return handleTouchEventCommon(ev);
+    }
 
-        if (mZoomManager.supportsMultiTouchZoom() && ev.getPointerCount() > 1) {
-            if (!detector.isInProgress() &&
-                    ev.getActionMasked() != MotionEvent.ACTION_POINTER_DOWN) {
-                // Insert a fake pointer down event in order to start
-                // the zoom scale detector.
-                MotionEvent temp = MotionEvent.obtain(ev);
-                // Clear the original event and set it to
-                // ACTION_POINTER_DOWN.
-                try {
-                    temp.setAction(temp.getAction() &
-                            ~MotionEvent.ACTION_MASK |
-                            MotionEvent.ACTION_POINTER_DOWN);
-                    detector.onTouchEvent(temp);
-                } finally {
-                    temp.recycle();
-                }
-            }
+    private boolean handleTouchEventCommon(MotionEvent ev) {
+        int action = ev.getAction();
+        float x = ev.getX();
+        float y = ev.getY();
+        long eventTime = ev.getEventTime();
 
-            detector.onTouchEvent(ev);
-
-            if (detector.isInProgress()) {
-                mLastTouchTime = eventTime;
-                cancelLongPress();
-                mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
-                if (!mZoomManager.supportsPanDuringZoom()) {
-                    return true;
-                }
-                mTouchMode = TOUCH_DRAG_MODE;
-                if (mVelocityTracker == null) {
-                    mVelocityTracker = VelocityTracker.obtain();
-                }
-            }
-
-            x = detector.getFocusX();
-            y = detector.getFocusY();
-            action = ev.getAction() & MotionEvent.ACTION_MASK;
-            if (action == MotionEvent.ACTION_POINTER_DOWN) {
-                cancelTouch();
-                action = MotionEvent.ACTION_DOWN;
-            } else if (action == MotionEvent.ACTION_POINTER_UP) {
-                // set mLastTouchX/Y to the remaining point
-                mLastTouchX = x;
-                mLastTouchY = y;
-            } else if (action == MotionEvent.ACTION_MOVE) {
-                // negative x or y indicate it is on the edge, skip it.
-                if (x < 0 || y < 0) {
-                    return true;
-                }
-            }
-        }
 
         // Due to the touch screen edge effect, a touch closer to the edge
         // always snapped to the edge. As getViewWidth() can be different from
@@ -5627,22 +5562,6 @@
                         break;
                     }
 
-                    // Only lock dragging to one axis if we don't have a scale in progress.
-                    // Scaling implies free-roaming movement. Note this is only ever a question
-                    // if mZoomManager.supportsPanDuringZoom() is true.
-                    if (detector != null && !detector.isInProgress()) {
-                        // if it starts nearly horizontal or vertical, enforce it
-                        int ax = Math.abs(deltaX);
-                        int ay = Math.abs(deltaY);
-                        if (ax > MAX_SLOPE_FOR_DIAG * ay) {
-                            mSnapScrollMode = SNAP_X;
-                            mSnapPositive = deltaX > 0;
-                        } else if (ay > MAX_SLOPE_FOR_DIAG * ax) {
-                            mSnapScrollMode = SNAP_Y;
-                            mSnapPositive = deltaY > 0;
-                        }
-                    }
-
                     mTouchMode = TOUCH_DRAG_MODE;
                     mLastTouchX = x;
                     mLastTouchY = y;
@@ -5899,13 +5818,82 @@
             ted.mPoints[c] = new Point(x, y);
         }
         ted.mMetaState = ev.getMetaState();
-        ted.mReprocess = mDeferTouchProcess;
+        ted.mReprocess = true;
+        ted.mMotionEvent = MotionEvent.obtain(ev);
         mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
         cancelLongPress();
         mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
         mPreventDefault = PREVENT_DEFAULT_IGNORE;
     }
 
+    private boolean handleMultiTouchInWebView(MotionEvent ev) {
+        if (DebugFlags.WEB_VIEW) {
+            Log.v(LOGTAG, "multi-touch: " + ev + " at " + ev.getEventTime()
+                + " mTouchMode=" + mTouchMode
+                + " numPointers=" + ev.getPointerCount()
+                + " scrolloffset=(" + mScrollX + "," + mScrollY + ")");
+        }
+
+        final ScaleGestureDetector detector =
+            mZoomManager.getMultiTouchGestureDetector();
+        int action = ev.getAction();
+        float x = ev.getX();
+        float y = ev.getY();
+        long eventTime = ev.getEventTime();
+
+        if (!detector.isInProgress() &&
+            ev.getActionMasked() != MotionEvent.ACTION_POINTER_DOWN) {
+            // Insert a fake pointer down event in order to start
+            // the zoom scale detector.
+            MotionEvent temp = MotionEvent.obtain(ev);
+            // Clear the original event and set it to
+            // ACTION_POINTER_DOWN.
+            try {
+                temp.setAction(temp.getAction() &
+                ~MotionEvent.ACTION_MASK |
+                MotionEvent.ACTION_POINTER_DOWN);
+                detector.onTouchEvent(temp);
+            } finally {
+                temp.recycle();
+            }
+        }
+
+        detector.onTouchEvent(ev);
+
+        if (detector.isInProgress()) {
+            if (DebugFlags.WEB_VIEW) {
+                Log.v(LOGTAG, "detector is in progress");
+            }
+            mLastTouchTime = eventTime;
+            cancelLongPress();
+            mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
+            if (!mZoomManager.supportsPanDuringZoom()) {
+                return false;
+            }
+            mTouchMode = TOUCH_DRAG_MODE;
+            if (mVelocityTracker == null) {
+                mVelocityTracker = VelocityTracker.obtain();
+            }
+        }
+
+        action = ev.getAction() & MotionEvent.ACTION_MASK;
+        if (action == MotionEvent.ACTION_POINTER_DOWN) {
+            cancelTouch();
+            action = MotionEvent.ACTION_DOWN;
+        } else if (action == MotionEvent.ACTION_POINTER_UP) {
+            // set mLastTouchX/Y to the remaining point
+            mLastTouchX = x;
+            mLastTouchY = y;
+        } else if (action == MotionEvent.ACTION_MOVE) {
+            // negative x or y indicate it is on the edge, skip it.
+            if (x < 0 || y < 0) {
+                return false;
+            }
+        }
+
+        return handleTouchEventCommon(ev);
+    }
+
     private void cancelWebCoreTouchEvent(int x, int y, boolean removeEvents) {
         if (shouldForwardTouchEvent()) {
             if (removeEvents) {
@@ -7278,6 +7266,13 @@
                         // prevent default is not called in WebCore, so the
                         // message needs to be reprocessed in UI
                         TouchEventData ted = (TouchEventData) msg.obj;
+
+                        if (ted.mPoints.length > 1) {  // for multi-touch.
+                            handleMultiTouchInWebView(ted.mMotionEvent);
+                            break;
+                        }
+
+                        // Following is for single touch.
                         switch (ted.mAction) {
                             case MotionEvent.ACTION_DOWN:
                                 mLastDeferTouchX = contentToViewX(ted.mPoints[0].x)
@@ -8103,7 +8098,6 @@
     private native int      nativeCursorFramePointer();
     private native Rect     nativeCursorNodeBounds();
     private native int nativeCursorNodePointer();
-    /* package */ native boolean nativeCursorMatchesFocus();
     private native boolean  nativeCursorIntersects(Rect visibleRect);
     private native boolean  nativeCursorIsAnchor();
     private native boolean  nativeCursorIsTextInput();
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index a482b74..c874160 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -33,6 +33,7 @@
 import android.util.Log;
 import android.util.SparseBooleanArray;
 import android.view.KeyEvent;
+import android.view.MotionEvent;
 import android.view.SurfaceView;
 import android.view.View;
 import android.webkit.DeviceMotionService;
@@ -830,6 +831,7 @@
         Point[] mPoints;
         int mMetaState;
         boolean mReprocess;
+        MotionEvent mMotionEvent;
     }
 
     static class GeolocationPermissionsData {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index b85670c..bccde8d 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -4810,7 +4810,10 @@
             if (mFiltered && mPopup != null && mPopup.isShowing()) {
                 if (event.getAction() == KeyEvent.ACTION_DOWN
                         && event.getRepeatCount() == 0) {
-                    getKeyDispatcherState().startTracking(event, this);
+                    KeyEvent.DispatcherState state = getKeyDispatcherState();
+                    if (state != null) {
+                        state.startTracking(event, this);
+                    }
                     handled = true;
                 } else if (event.getAction() == KeyEvent.ACTION_UP
                         && event.isTracking() && !event.isCanceled()) {
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index ee037cd..4d8d21f 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -607,10 +607,16 @@
             // special case for the back key, we do not even try to send it
             // to the drop down list but instead, consume it immediately
             if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
-                getKeyDispatcherState().startTracking(event, this);
+                KeyEvent.DispatcherState state = getKeyDispatcherState();
+                if (state != null) {
+                    state.startTracking(event, this);
+                }
                 return true;
             } else if (event.getAction() == KeyEvent.ACTION_UP) {
-                getKeyDispatcherState().handleUpEvent(event);
+                KeyEvent.DispatcherState state = getKeyDispatcherState();
+                if (state != null) {
+                    state.handleUpEvent(event);
+                }
                 if (event.isTracking() && !event.isCanceled()) {
                     dismissDropDown();
                     return true;
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 3bba816..444a163d 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -915,10 +915,16 @@
             // to the drop down list but instead, consume it immediately
             final View anchorView = mDropDownAnchorView;
             if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
-                anchorView.getKeyDispatcherState().startTracking(event, this);
+                KeyEvent.DispatcherState state = anchorView.getKeyDispatcherState();
+                if (state != null) {
+                    state.startTracking(event, this);
+                }
                 return true;
             } else if (event.getAction() == KeyEvent.ACTION_UP) {
-                anchorView.getKeyDispatcherState().handleUpEvent(event);
+                KeyEvent.DispatcherState state = anchorView.getKeyDispatcherState();
+                if (state != null) {
+                    state.handleUpEvent(event);
+                }
                 if (event.isTracking() && !event.isCanceled()) {
                     dismiss();
                     return true;
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 5a5b6f4..79d6a81 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1468,12 +1468,17 @@
             if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
                 if (event.getAction() == KeyEvent.ACTION_DOWN
                         && event.getRepeatCount() == 0) {
-                    getKeyDispatcherState().startTracking(event, this);
+                    KeyEvent.DispatcherState state = getKeyDispatcherState();
+                    if (state != null) {
+                        state.startTracking(event, this);
+                    }
                     return true;
-                } else if (event.getAction() == KeyEvent.ACTION_UP
-                        && getKeyDispatcherState().isTracking(event) && !event.isCanceled()) {
-                    dismiss();
-                    return true;
+                } else if (event.getAction() == KeyEvent.ACTION_UP) {
+                    KeyEvent.DispatcherState state = getKeyDispatcherState();
+                    if (state != null && state.isTracking(event) && !event.isCanceled()) {
+                        dismiss();
+                        return true;
+                    }
                 }
                 return super.dispatchKeyEvent(event);
             } else {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index cc5be00..7675e0c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4780,7 +4780,6 @@
         }
 
         hideControllers();
-        stopSelectionActionMode();
 
         switch (keyCode) {
             case KeyEvent.KEYCODE_DPAD_CENTER:
@@ -5119,6 +5118,7 @@
         if (mInputMethodState != null) {
             mInputMethodState.mExtracting = req;
         }
+        // This stops a possible text selection mode. Maybe not intended.
         hideControllers();
     }
     
@@ -6781,7 +6781,7 @@
         sendOnTextChanged(buffer, start, before, after);
         onTextChanged(buffer, start, before, after);
 
-        // Hide the controller if the amount of content changed
+        // Hide the controllers if the amount of content changed
         if (before != after) {
             hideControllers();
         }
@@ -8207,9 +8207,12 @@
             selectCurrentWord();
         }
 
-        final InputMethodManager imm = (InputMethodManager)
-                getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
-        imm.showSoftInput(this, 0, null);
+        if (!mTextIsSelectable) {
+            // Show the IME, except when selection non editable text.
+            final InputMethodManager imm = (InputMethodManager)
+                    getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+            imm.showSoftInput(this, 0, null);
+        }
 
         ActionMode.Callback actionModeCallback = new SelectionActionModeCallback();
         mSelectionActionMode = startActionMode(actionModeCallback);
@@ -8233,6 +8236,7 @@
 
     private void stopSelectionActionMode() {
         if (mSelectionActionMode != null) {
+            // This will hide the mSelectionModifierCursorController
             mSelectionActionMode.finish();
         }
     }
@@ -8356,8 +8360,12 @@
             if (mCustomSelectionActionModeCallback != null) {
                 mCustomSelectionActionModeCallback.onDestroyActionMode(mode);
             }
-            Selection.setSelection((Spannable) mText, getSelectionStart());
-            hideSelectionModifierCursorController();
+            Selection.setSelection((Spannable) mText, getSelectionEnd());
+
+            if (mSelectionModifierCursorController != null) {
+                mSelectionModifierCursorController.hide();
+            }
+
             mSelectionActionMode = null;
         }
     }
@@ -9173,16 +9181,12 @@
         }
     }
 
-    private void hideSelectionModifierCursorController() {
-        // No need to create the controller to hide it.
-        if (mSelectionModifierCursorController != null) {
-            mSelectionModifierCursorController.hide();
-        }
-    }
-    
+    /**
+     * Hides the insertion controller and stops text selection mode, hiding the selection controller
+     */
     private void hideControllers() {
         hideInsertionPointCursorController();
-        hideSelectionModifierCursorController();
+        stopSelectionActionMode();
     }
 
     /**
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 9381675..463902f 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -139,6 +139,10 @@
         mReserveOverflow = reserveOverflow;
     }
     
+    public View getOverflowButton() {
+        return mOverflowButton;
+    }
+
     @Override
     protected LayoutParams generateDefaultLayoutParams() {
         LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index fe41f52..b93fac4 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -68,6 +68,10 @@
         }
     }
 
+    public void setAnchorView(View anchor) {
+        mAnchorView = new WeakReference<View>(anchor);
+    }
+
     public void show() {
         if (!tryShow()) {
             throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
diff --git a/core/jni/com_android_internal_os_ZygoteInit.cpp b/core/jni/com_android_internal_os_ZygoteInit.cpp
index ada4dd3..52e8f42 100644
--- a/core/jni/com_android_internal_os_ZygoteInit.cpp
+++ b/core/jni/com_android_internal_os_ZygoteInit.cpp
@@ -45,14 +45,10 @@
 static jint com_android_internal_os_ZygoteInit_setreuid(
     JNIEnv* env, jobject clazz, jint ruid, jint euid)
 {
-    int err;
-
-    errno = 0;
-    err = setreuid(ruid, euid);
-
-    //LOGI("setreuid(%d,%d) err %d errno %d", ruid, euid, err, errno);
-
-    return errno;
+    if (setreuid(ruid, euid) < 0) {
+        return errno;
+    }
+    return 0;
 }
 
 /*
@@ -62,14 +58,10 @@
 static jint com_android_internal_os_ZygoteInit_setregid(
     JNIEnv* env, jobject clazz, jint rgid, jint egid)
 {
-    int err;
-
-    errno = 0;
-    err = setregid(rgid, egid);
-
-    //LOGI("setregid(%d,%d) err %d errno %d", rgid, egid, err, errno);
-
-    return errno;
+    if (setregid(rgid, egid) < 0) {
+        return errno;
+    }
+    return 0;
 }
 
 /*
@@ -79,13 +71,10 @@
 static jint com_android_internal_os_ZygoteInit_setpgid(
     JNIEnv* env, jobject clazz, jint pid, jint pgid)
 {
-    int err;
-
-    errno = 0;
-
-    err = setpgid(pid, pgid);
-
-    return errno;
+    if (setpgid(pid, pgid) < 0) {
+        return errno;
+    }
+    return 0;
 }
 
 /*
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1d43442..67adc28 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -540,7 +540,8 @@
         android:description="@string/permdesc_sdcardWrite"
         android:protectionLevel="dangerous" />
 
-    <!-- Allows an application to write to internal media storage -->
+    <!-- Allows an application to write to internal media storage
+         @hide  -->
     <permission android:name="android.permission.WRITE_MEDIA_STORAGE"
         android:permissionGroup="android.permission-group.STORAGE"
         android:label="@string/permlab_mediaStorageWrite"
diff --git a/core/tests/coretests/src/android/util/JsonReaderTest.java b/core/tests/coretests/src/android/util/JsonReaderTest.java
index 216a772..b5c2c27 100644
--- a/core/tests/coretests/src/android/util/JsonReaderTest.java
+++ b/core/tests/coretests/src/android/util/JsonReaderTest.java
@@ -16,11 +16,10 @@
 
 package android.util;
 
-import java.util.Arrays;
-import junit.framework.TestCase;
-
 import java.io.IOException;
 import java.io.StringReader;
+import java.util.Arrays;
+import junit.framework.TestCase;
 
 public final class JsonReaderTest extends TestCase {
 
@@ -677,7 +676,7 @@
         try {
             reader.nextString();
             fail();
-        } catch (IOException expected) {
+        } catch (MalformedJsonException expected) {
         }
     }
 
@@ -811,4 +810,50 @@
         reader.nextNull();
         reader.endArray();
     }
+
+    public void testStrictMultipleTopLevelValues() throws IOException {
+        JsonReader reader = new JsonReader(new StringReader("[] []"));
+        reader.beginArray();
+        reader.endArray();
+        try {
+            reader.peek();
+            fail();
+        } catch (IOException expected) {
+        }
+    }
+
+    public void testLenientMultipleTopLevelValues() throws IOException {
+        JsonReader reader = new JsonReader(new StringReader("[] true {}"));
+        reader.setLenient(true);
+        reader.beginArray();
+        reader.endArray();
+        assertEquals(true, reader.nextBoolean());
+        reader.beginObject();
+        reader.endObject();
+        assertEquals(JsonToken.END_DOCUMENT, reader.peek());
+    }
+
+    public void testStrictTopLevelValueType() {
+        JsonReader reader = new JsonReader(new StringReader("true"));
+        try {
+            reader.nextBoolean();
+            fail();
+        } catch (IOException expected) {
+        }
+    }
+
+    public void testLenientTopLevelValueType() throws IOException {
+        JsonReader reader = new JsonReader(new StringReader("true"));
+        reader.setLenient(true);
+        assertEquals(true, reader.nextBoolean());
+    }
+
+    public void testStrictNonExecutePrefix() {
+        JsonReader reader = new JsonReader(new StringReader(")]}'\n []"));
+        try {
+            reader.beginArray();
+            fail();
+        } catch (IOException expected) {
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/util/JsonWriterTest.java b/core/tests/coretests/src/android/util/JsonWriterTest.java
index fa84023..b29e2fd 100644
--- a/core/tests/coretests/src/android/util/JsonWriterTest.java
+++ b/core/tests/coretests/src/android/util/JsonWriterTest.java
@@ -16,10 +16,11 @@
 
 package android.util;
 
-import junit.framework.TestCase;
-
 import java.io.IOException;
 import java.io.StringWriter;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import junit.framework.TestCase;
 
 public final class JsonWriterTest extends TestCase {
 
@@ -119,7 +120,7 @@
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
         jsonWriter.beginObject();
         jsonWriter.name("a");
-        jsonWriter.value(null);
+        jsonWriter.value((String) null);
         jsonWriter.endObject();
         assertEquals("{\"a\":null}", stringWriter.toString());
     }
@@ -145,6 +146,27 @@
         }
     }
 
+    public void testNonFiniteBoxedDoubles() throws IOException {
+        StringWriter stringWriter = new StringWriter();
+        JsonWriter jsonWriter = new JsonWriter(stringWriter);
+        jsonWriter.beginArray();
+        try {
+            jsonWriter.value(new Double(Double.NaN));
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+        try {
+            jsonWriter.value(new Double(Double.NEGATIVE_INFINITY));
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+        try {
+            jsonWriter.value(new Double(Double.POSITIVE_INFINITY));
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
     public void testDoubles() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
@@ -189,6 +211,22 @@
                 + "9223372036854775807]", stringWriter.toString());
     }
 
+    public void testNumbers() throws IOException {
+        StringWriter stringWriter = new StringWriter();
+        JsonWriter jsonWriter = new JsonWriter(stringWriter);
+        jsonWriter.beginArray();
+        jsonWriter.value(new BigInteger("0"));
+        jsonWriter.value(new BigInteger("9223372036854775808"));
+        jsonWriter.value(new BigInteger("-9223372036854775809"));
+        jsonWriter.value(new BigDecimal("3.141592653589793238462643383"));
+        jsonWriter.endArray();
+        jsonWriter.close();
+        assertEquals("[0,"
+                + "9223372036854775808,"
+                + "-9223372036854775809,"
+                + "3.141592653589793238462643383]", stringWriter.toString());
+    }
+
     public void testBooleans() throws IOException {
         StringWriter stringWriter = new StringWriter();
         JsonWriter jsonWriter = new JsonWriter(stringWriter);
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 66c6d81..184620b 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -85,8 +85,12 @@
 
         @Override
         protected void finalize() throws Throwable {
-            if (mNativeCanvas != 0) {
-                finalizer(mNativeCanvas);
+            try {
+                if (mNativeCanvas != 0) {
+                    finalizer(mNativeCanvas);
+                }
+            } finally {
+                super.finalize();
             }
         }
     }
@@ -137,6 +141,8 @@
      * Returns null.
      * 
      * @deprecated This method is not supported and should not be invoked.
+     * 
+     * @hide
      */
     @Deprecated
     protected GL getGL() {
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 53962e1..7a47c3b 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -53,19 +53,6 @@
     public static final int USAGE_GRAPHICS_CONSTANTS = 0x0008;
 
 
-    public enum CubemapLayout {
-        VERTICAL_FACE_LIST (0),
-        HORIZONTAL_FACE_LIST (1),
-        VERTICAL_CROSS (2),
-        HORIZONTAL_CROSS (3);
-
-        int mID;
-        CubemapLayout(int id) {
-            mID = id;
-        }
-    }
-
-
     public enum MipmapControl {
         MIPMAP_NONE(0),
         MIPMAP_FULL(1),
@@ -416,33 +403,41 @@
                                 USAGE_GRAPHICS_TEXTURE);
     }
 
+    /**
+    * Creates a cubemap allocation from a bitmap containing the
+    * horizontal list of cube faces. Each individual face must be
+    * the same size and power of 2
+    *
+    * @param rs
+    * @param b bitmap with cubemap faces layed out in the following
+    *          format: right, left, top, bottom, front, back
+    * @param mips specifies desired mipmap behaviour for the cubemap
+    * @param usage bitfield specifying how the cubemap is utilized
+    *
+    **/
     static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b,
                                                      MipmapControl mips,
-                                                     CubemapLayout layout,
                                                      int usage) {
         rs.validate();
 
         int height = b.getHeight();
         int width = b.getWidth();
 
-        if (layout != CubemapLayout.VERTICAL_FACE_LIST) {
-            throw new RSIllegalArgumentException("Only vertical face list supported");
-        }
-        if (height % 6 != 0) {
+        if (width % 6 != 0) {
             throw new RSIllegalArgumentException("Cubemap height must be multiple of 6");
         }
-        if (height / 6 != width) {
+        if (width / 6 != height) {
             throw new RSIllegalArgumentException("Only square cobe map faces supported");
         }
-        boolean isPow2 = (width & (width - 1)) == 0;
+        boolean isPow2 = (height & (height - 1)) == 0;
         if (!isPow2) {
             throw new RSIllegalArgumentException("Only power of 2 cube faces supported");
         }
 
         Element e = elementFromBitmap(rs, b);
         Type.Builder tb = new Type.Builder(rs, e);
-        tb.setX(width);
-        tb.setY(width);
+        tb.setX(height);
+        tb.setY(height);
         tb.setFaces(true);
         tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL);
         Type t = tb.create();
@@ -454,10 +449,9 @@
         return new Allocation(id, rs, t, usage);
     }
 
-    static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b,
-                                                     CubemapLayout layout) {
+    static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b) {
         return createCubemapFromBitmap(rs, b, MipmapControl.MIPMAP_NONE,
-                                       layout, USAGE_GRAPHICS_TEXTURE);
+                                       USAGE_GRAPHICS_TEXTURE);
     }
 
     static public Allocation createFromBitmapResource(RenderScript rs,
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index ff92e08..cbc15d8 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -113,8 +113,11 @@
     int mBufferCount;
 
     // mCurrentTexture is the buffer slot index of the buffer that is currently
-    // bound to the OpenGL texture. A value of INVALID_BUFFER_SLOT, indicating
-    // that no buffer is currently bound to the texture.
+    // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
+    // indicating that no buffer slot is currently bound to the texture. Note,
+    // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean
+    // that no buffer is bound to the texture. A call to setBufferCount will
+    // reset mCurrentTexture to INVALID_BUFFER_SLOT.
     int mCurrentTexture;
 
     // mLastQueued is the buffer slot index of the most recently enqueued buffer.
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index b3815c4..4599d70 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -101,6 +101,8 @@
 
     List<sp<AMessage> > mDeferredQueue;
 
+    bool mSentFormat;
+
     status_t allocateBuffersOnPort(OMX_U32 portIndex);
     status_t freeBuffersOnPort(OMX_U32 portIndex);
     status_t freeBuffer(OMX_U32 portIndex, size_t i);
@@ -145,6 +147,8 @@
     void deferMessage(const sp<AMessage> &msg);
     void processDeferredMessages();
 
+    void sendFormatChange();
+
     DISALLOW_EVIL_CONSTRUCTORS(ACodec);
 };
 
diff --git a/include/media/stagefright/foundation/AMessage.h b/include/media/stagefright/foundation/AMessage.h
index 91ec60c..72dc730 100644
--- a/include/media/stagefright/foundation/AMessage.h
+++ b/include/media/stagefright/foundation/AMessage.h
@@ -52,6 +52,10 @@
     void setObject(const char *name, const sp<RefBase> &obj);
     void setMessage(const char *name, const sp<AMessage> &obj);
 
+    void setRect(
+            const char *name,
+            int32_t left, int32_t top, int32_t right, int32_t bottom);
+
     bool findInt32(const char *name, int32_t *value) const;
     bool findInt64(const char *name, int64_t *value) const;
     bool findSize(const char *name, size_t *value) const;
@@ -62,6 +66,10 @@
     bool findObject(const char *name, sp<RefBase> *obj) const;
     bool findMessage(const char *name, sp<AMessage> *obj) const;
 
+    bool findRect(
+            const char *name,
+            int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const;
+
     void post(int64_t delayUs = 0);
 
     // Performs a deep-copy of "this", contained messages are in turn "dup'ed".
@@ -85,11 +93,16 @@
         kTypeString,
         kTypeObject,
         kTypeMessage,
+        kTypeRect,
     };
 
     uint32_t mWhat;
     ALooper::handler_id mTarget;
 
+    struct Rect {
+        int32_t mLeft, mTop, mRight, mBottom;
+    };
+
     struct Item {
         union {
             int32_t int32Value;
@@ -100,6 +113,7 @@
             void *ptrValue;
             RefBase *refValue;
             AString *stringValue;
+            Rect rectValue;
         } u;
         const char *mName;
         Type mType;
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 9579996..11a48d9 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -15,6 +15,7 @@
  */
 
 #define LOG_TAG "SurfaceTexture"
+//#define LOG_NDEBUG 0
 
 #define GL_GLEXT_PROTOTYPES
 #define EGL_EGLEXT_PROTOTYPES
@@ -36,21 +37,32 @@
 SurfaceTexture::SurfaceTexture(GLuint tex) :
     mBufferCount(MIN_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT),
     mLastQueued(INVALID_BUFFER_SLOT), mTexName(tex) {
+    LOGV("SurfaceTexture::SurfaceTexture");
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+        mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+        mSlots[i].mOwnedByClient = false;
+    }
 }
 
 SurfaceTexture::~SurfaceTexture() {
+    LOGV("SurfaceTexture::~SurfaceTexture");
     freeAllBuffers();
 }
 
 status_t SurfaceTexture::setBufferCount(int bufferCount) {
+    LOGV("SurfaceTexture::setBufferCount");
     Mutex::Autolock lock(mMutex);
     freeAllBuffers();
     mBufferCount = bufferCount;
+    mCurrentTexture = INVALID_BUFFER_SLOT;
+    mLastQueued = INVALID_BUFFER_SLOT;
     return OK;
 }
 
 sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf,
         uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
+    LOGV("SurfaceTexture::requestBuffer");
     Mutex::Autolock lock(mMutex);
     if (buf < 0 || mBufferCount <= buf) {
         LOGE("requestBuffer: slot index out of range [0, %d]: %d",
@@ -75,6 +87,7 @@
 }
 
 status_t SurfaceTexture::dequeueBuffer(int *buf) {
+    LOGV("SurfaceTexture::dequeueBuffer");
     Mutex::Autolock lock(mMutex);
     int found = INVALID_BUFFER_SLOT;
     for (int i = 0; i < mBufferCount; i++) {
@@ -92,6 +105,7 @@
 }
 
 status_t SurfaceTexture::queueBuffer(int buf) {
+    LOGV("SurfaceTexture::queueBuffer");
     Mutex::Autolock lock(mMutex);
     if (buf < 0 || mBufferCount <= buf) {
         LOGE("queueBuffer: slot index out of range [0, %d]: %d",
@@ -111,6 +125,7 @@
 }
 
 void SurfaceTexture::cancelBuffer(int buf) {
+    LOGV("SurfaceTexture::cancelBuffer");
     Mutex::Autolock lock(mMutex);
     if (buf < 0 || mBufferCount <= buf) {
         LOGE("cancelBuffer: slot index out of range [0, %d]: %d", mBufferCount,
@@ -124,18 +139,21 @@
 }
 
 status_t SurfaceTexture::setCrop(const Rect& reg) {
+    LOGV("SurfaceTexture::setCrop");
     Mutex::Autolock lock(mMutex);
     // XXX: How should we handle crops?
     return OK;
 }
 
 status_t SurfaceTexture::setTransform(uint32_t transform) {
+    LOGV("SurfaceTexture::setTransform");
     Mutex::Autolock lock(mMutex);
     // XXX: How should we handle transforms?
     return OK;
 }
 
 status_t SurfaceTexture::updateTexImage() {
+    LOGV("SurfaceTexture::updateTexImage");
     Mutex::Autolock lock(mMutex);
 
     // We always bind the texture even if we don't update its contents.
diff --git a/libs/rs/java/Samples/res/drawable/cubemap_test.png b/libs/rs/java/Samples/res/drawable/cubemap_test.png
index 75ad0a4..baf35d0 100644
--- a/libs/rs/java/Samples/res/drawable/cubemap_test.png
+++ b/libs/rs/java/Samples/res/drawable/cubemap_test.png
Binary files differ
diff --git a/libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java b/libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java
index 5430a13..1afcee3 100644
--- a/libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java
+++ b/libs/rs/java/Samples/src/com/android/samples/RsBenchRS.java
@@ -22,7 +22,6 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.renderscript.*;
-import android.renderscript.Allocation.CubemapLayout;
 import android.renderscript.Allocation.MipmapControl;
 import android.renderscript.Program.TextureType;
 import android.renderscript.ProgramStore.DepthFunc;
@@ -318,8 +317,7 @@
         mTexTransparent = loadTextureARGB(R.drawable.leaf);
         mTexChecker = loadTextureRGB(R.drawable.checker);
         Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.cubemap_test);
-        mTexCube = Allocation.createCubemapFromBitmap(mRS, b,
-                                                      Allocation.CubemapLayout.VERTICAL_FACE_LIST);
+        mTexCube = Allocation.createCubemapFromBitmap(mRS, b);
 
         mScript.set_gTexTorus(mTexTorus);
         mScript.set_gTexOpaque(mTexOpaque);
diff --git a/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java b/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java
index cac105a..87840a7 100644
--- a/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java
+++ b/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesRS.java
@@ -22,7 +22,6 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.renderscript.*;
-import android.renderscript.Allocation.CubemapLayout;
 import android.renderscript.Font.Style;
 import android.renderscript.Program.TextureType;
 import android.renderscript.ProgramStore.DepthFunc;
@@ -308,8 +307,7 @@
         mTexTransparent = loadTextureARGB(R.drawable.leaf);
         mTexChecker = loadTextureRGB(R.drawable.checker);
         Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.cubemap_test);
-        mTexCube = Allocation.createCubemapFromBitmap(mRS, b,
-                                                      Allocation.CubemapLayout.VERTICAL_FACE_LIST);
+        mTexCube = Allocation.createCubemapFromBitmap(mRS, b);
 
         mScript.set_gTexTorus(mTexTorus);
         mScript.set_gTexOpaque(mTexOpaque);
diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
index a50321e..fc3a065 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
+++ b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java
@@ -66,6 +66,7 @@
 
         unitTests.add(new UT_primitives(this, mRes, mCtx));
         unitTests.add(new UT_rsdebug(this, mRes, mCtx));
+        unitTests.add(new UT_rstime(this, mRes, mCtx));
         unitTests.add(new UT_rstypes(this, mRes, mCtx));
         unitTests.add(new UT_fp_mad(this, mRes, mCtx));
         /*
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_rstime.java b/libs/rs/java/tests/src/com/android/rs/test/UT_rstime.java
new file mode 100644
index 0000000..f302e1a
--- /dev/null
+++ b/libs/rs/java/tests/src/com/android/rs/test/UT_rstime.java
@@ -0,0 +1,40 @@
+/*
+ * 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.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_rstime extends UnitTest {
+    private Resources mRes;
+
+    protected UT_rstime(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "rsTime", ctx);
+        mRes = res;
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        ScriptC_rstime s = new ScriptC_rstime(pRS, mRes, R.raw.rstime);
+        pRS.setMessageHandler(mRsMessage);
+        s.invoke_test_rstime(0, 0);
+        pRS.finish();
+        waitForMessage();
+        pRS.destroy();
+    }
+}
diff --git a/libs/rs/java/tests/src/com/android/rs/test/rstime.rs b/libs/rs/java/tests/src/com/android/rs/test/rstime.rs
new file mode 100644
index 0000000..5e3e078
--- /dev/null
+++ b/libs/rs/java/tests/src/com/android/rs/test/rstime.rs
@@ -0,0 +1,52 @@
+#include "shared.rsh"
+
+static bool basic_test(uint32_t index) {
+    bool failed = false;
+
+    rs_time_t curTime = rsTime(0);
+    rs_tm tm;
+    rsDebug("curTime", curTime);
+
+    rsLocaltime(&tm, &curTime);
+
+    rsDebug("tm.tm_sec", tm.tm_sec);
+    rsDebug("tm.tm_min", tm.tm_min);
+    rsDebug("tm.tm_hour", tm.tm_hour);
+    rsDebug("tm.tm_mday", tm.tm_mday);
+    rsDebug("tm.tm_mon", tm.tm_mon);
+    rsDebug("tm.tm_year", tm.tm_year);
+    rsDebug("tm.tm_wday", tm.tm_wday);
+    rsDebug("tm.tm_yday", tm.tm_yday);
+    rsDebug("tm.tm_isdst", tm.tm_isdst);
+
+    // Test a specific time (only valid for PST localtime)
+    curTime = 1294438893;
+    rsLocaltime(&tm, &curTime);
+
+    _RS_ASSERT(tm.tm_sec == 33);
+    _RS_ASSERT(tm.tm_min == 21);
+    _RS_ASSERT(tm.tm_hour == 14);
+    _RS_ASSERT(tm.tm_mday == 7);
+    _RS_ASSERT(tm.tm_mon == 0);
+    _RS_ASSERT(tm.tm_year == 111);
+    _RS_ASSERT(tm.tm_wday == 5);
+    _RS_ASSERT(tm.tm_yday == 6);
+    _RS_ASSERT(tm.tm_isdst == 0);
+
+    return failed;
+}
+
+void test_rstime(uint32_t index, int test_num) {
+    bool failed = false;
+    failed |= basic_test(index);
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+        rsDebug("rstime_test FAILED", -1);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+        rsDebug("rstime_test PASSED", 0);
+    }
+}
+
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index 3608e43..673ade2 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -831,16 +831,21 @@
         return NULL;
     }
 
+    uint32_t faceSize = t->getDimX();
+    uint32_t strideBytes = faceSize * 6 * t->getElementSizeBytes();
+    uint32_t copySize = faceSize * t->getElementSizeBytes();
+
     uint8_t *sourcePtr = (uint8_t*)data;
     for (uint32_t face = 0; face < 6; face ++) {
         Adapter2D faceAdapter(rsc, texAlloc);
         faceAdapter.setFace(face);
 
-        size_t cpySize = t->getDimX() * t->getDimX() * t->getElementSizeBytes();
-        memcpy(faceAdapter.getElement(0, 0), sourcePtr, cpySize);
+        for (uint32_t dI = 0; dI < faceSize; dI ++) {
+            memcpy(faceAdapter.getElement(0, dI), sourcePtr + strideBytes * dI, copySize);
+        }
 
         // Move the data pointer to the next cube face
-        sourcePtr += cpySize;
+        sourcePtr += copySize;
 
         if (mips == RS_ALLOCATION_MIPMAP_FULL) {
             Adapter2D adapt(rsc, texAlloc);
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 6a065b2..c5ee7ee 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -44,6 +44,7 @@
 uint32_t Context::gThreadTLSKeyCount = 0;
 uint32_t Context::gGLContextCount = 0;
 pthread_mutex_t Context::gInitMutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t Context::gLibMutex = PTHREAD_MUTEX_INITIALIZER;
 
 static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
     if (returnVal != EGL_TRUE) {
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 3c402c4..df275bc 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -75,6 +75,8 @@
     static uint32_t gThreadTLSKeyCount;
     static uint32_t gGLContextCount;
     static pthread_mutex_t gInitMutex;
+    // Library mutex (for providing thread-safe calls from the runtime)
+    static pthread_mutex_t gLibMutex;
 
     struct ScriptTLSStruct {
         Context * mContext;
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index f61b983..0b21669 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -100,70 +100,24 @@
 // Time routines
 //////////////////////////////////////////////////////////////////////////////
 
-static int32_t SC_second() {
+static time_t SC_time(time_t *timer) {
     GET_TLS();
-
-    time_t rawtime;
-    time(&rawtime);
-
-    struct tm *timeinfo;
-    timeinfo = localtime(&rawtime);
-    return timeinfo->tm_sec;
+    return time(timer);
 }
 
-static int32_t SC_minute() {
+static tm* SC_localtime(tm *local, time_t *timer) {
     GET_TLS();
+    if (!local) {
+      return NULL;
+    }
 
-    time_t rawtime;
-    time(&rawtime);
-
-    struct tm *timeinfo;
-    timeinfo = localtime(&rawtime);
-    return timeinfo->tm_min;
-}
-
-static int32_t SC_hour() {
-    GET_TLS();
-
-    time_t rawtime;
-    time(&rawtime);
-
-    struct tm *timeinfo;
-    timeinfo = localtime(&rawtime);
-    return timeinfo->tm_hour;
-}
-
-static int32_t SC_day() {
-    GET_TLS();
-
-    time_t rawtime;
-    time(&rawtime);
-
-    struct tm *timeinfo;
-    timeinfo = localtime(&rawtime);
-    return timeinfo->tm_mday;
-}
-
-static int32_t SC_month() {
-    GET_TLS();
-
-    time_t rawtime;
-    time(&rawtime);
-
-    struct tm *timeinfo;
-    timeinfo = localtime(&rawtime);
-    return timeinfo->tm_mon;
-}
-
-static int32_t SC_year() {
-    GET_TLS();
-
-    time_t rawtime;
-    time(&rawtime);
-
-    struct tm *timeinfo;
-    timeinfo = localtime(&rawtime);
-    return timeinfo->tm_year;
+    // The native localtime function is not thread-safe, so we
+    // have to apply locking for proper behavior in RenderScript.
+    pthread_mutex_lock(&rsc->gLibMutex);
+    tm *tmp = localtime(timer);
+    memcpy(local, tmp, sizeof(*tmp));
+    pthread_mutex_unlock(&rsc->gLibMutex);
+    return local;
 }
 
 static int64_t SC_uptimeMillis() {
@@ -498,12 +452,8 @@
     { "_Z6rsFracf", (void *)&SC_frac, true },
 
     // time
-    { "_Z8rsSecondv", (void *)&SC_second, true },
-    { "_Z8rsMinutev", (void *)&SC_minute, true },
-    { "_Z6rsHourv", (void *)&SC_hour, true },
-    { "_Z5rsDayv", (void *)&SC_day, true },
-    { "_Z7rsMonthv", (void *)&SC_month, true },
-    { "_Z6rsYearv", (void *)&SC_year, true },
+    { "_Z6rsTimePi", (void *)&SC_time, true },
+    { "_Z11rsLocaltimeP5rs_tmPKi", (void *)&SC_localtime, true },
     { "_Z14rsUptimeMillisv", (void*)&SC_uptimeMillis, true },
     { "_Z13rsUptimeNanosv", (void*)&SC_uptimeNanos, true },
     { "_Z7rsGetDtv", (void*)&SC_getDt, false },
diff --git a/libs/rs/scriptc/rs_math.rsh b/libs/rs/scriptc/rs_math.rsh
index d059997..a74c0e0 100644
--- a/libs/rs/scriptc/rs_math.rsh
+++ b/libs/rs/scriptc/rs_math.rsh
@@ -118,32 +118,6 @@
 extern float __attribute__((overloadable))
     rsFrac(float);
 
-// time
-extern int32_t __attribute__((overloadable))
-    rsSecond(void);
-extern int32_t __attribute__((overloadable))
-    rsMinute(void);
-extern int32_t __attribute__((overloadable))
-    rsHour(void);
-extern int32_t __attribute__((overloadable))
-    rsDay(void);
-extern int32_t __attribute__((overloadable))
-    rsMonth(void);
-extern int32_t __attribute__((overloadable))
-    rsYear(void);
-
-// Return the current system clock in milliseconds
-extern int64_t __attribute__((overloadable))
-    rsUptimeMillis(void);
-
-// Return the current system clock in nanoseconds
-extern int64_t __attribute__((overloadable))
-    rsUptimeNanos(void);
-
-// Return the time in seconds since function was last called in this script.
-extern float __attribute__((overloadable))
-    rsGetDt(void);
-
 // Send a message back to the client.  Will not block and returns true
 // if the message was sendable and false if the fifo was full.
 // A message ID is required.  Data payload is optional.
diff --git a/libs/rs/scriptc/rs_time.rsh b/libs/rs/scriptc/rs_time.rsh
new file mode 100644
index 0000000..f1abed63
--- /dev/null
+++ b/libs/rs/scriptc/rs_time.rsh
@@ -0,0 +1,36 @@
+#ifndef __RS_TIME_RSH__
+#define __RS_TIME_RSH__
+
+typedef int rs_time_t;
+
+typedef struct {
+    int tm_sec;
+    int tm_min;
+    int tm_hour;
+    int tm_mday;
+    int tm_mon;
+    int tm_year;
+    int tm_wday;
+    int tm_yday;
+    int tm_isdst;
+} rs_tm;
+
+extern rs_time_t __attribute__((overloadable))
+    rsTime(rs_time_t *timer);
+
+extern rs_tm * __attribute__((overloadable))
+    rsLocaltime(rs_tm *local, const rs_time_t *timer);
+
+// Return the current system clock in milliseconds
+extern int64_t __attribute__((overloadable))
+    rsUptimeMillis(void);
+
+// Return the current system clock in nanoseconds
+extern int64_t __attribute__((overloadable))
+    rsUptimeNanos(void);
+
+// Return the time in seconds since function was last called in this script.
+extern float __attribute__((overloadable))
+    rsGetDt(void);
+
+#endif
diff --git a/media/libmediaplayerservice/nuplayer/DecoderWrapper.cpp b/media/libmediaplayerservice/nuplayer/DecoderWrapper.cpp
index 4d4cd8d..802d1fb 100644
--- a/media/libmediaplayerservice/nuplayer/DecoderWrapper.cpp
+++ b/media/libmediaplayerservice/nuplayer/DecoderWrapper.cpp
@@ -309,6 +309,18 @@
 
         realNotify->setInt32("width", width);
         realNotify->setInt32("height", height);
+
+        int32_t cropLeft, cropTop, cropRight, cropBottom;
+        if (!meta->findRect(
+                    kKeyCropRect,
+                    &cropLeft, &cropTop, &cropRight, &cropBottom)) {
+            cropLeft = 0;
+            cropTop = 0;
+            cropRight = width - 1;
+            cropBottom = height - 1;
+        }
+
+        realNotify->setRect("crop", cropLeft, cropTop, cropRight, cropBottom);
     }
 
     notify->post();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index e1b371e..7f534c0 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -271,22 +271,43 @@
 
                 finishFlushIfPossible();
             } else if (what == ACodec::kWhatOutputFormatChanged) {
-                CHECK(audio);
+                if (audio) {
+                    int32_t numChannels;
+                    CHECK(codecRequest->findInt32("channel-count", &numChannels));
 
-                int32_t numChannels;
-                CHECK(codecRequest->findInt32("channel-count", &numChannels));
+                    int32_t sampleRate;
+                    CHECK(codecRequest->findInt32("sample-rate", &sampleRate));
 
-                int32_t sampleRate;
-                CHECK(codecRequest->findInt32("sample-rate", &sampleRate));
+                    LOGV("Audio output format changed to %d Hz, %d channels",
+                         sampleRate, numChannels);
 
-                LOGV("Audio output format changed to %d Hz, %d channels",
-                     sampleRate, numChannels);
+                    mAudioSink->close();
+                    CHECK_EQ(mAudioSink->open(sampleRate, numChannels), (status_t)OK);
+                    mAudioSink->start();
 
-                mAudioSink->close();
-                CHECK_EQ(mAudioSink->open(sampleRate, numChannels), (status_t)OK);
-                mAudioSink->start();
+                    mRenderer->signalAudioSinkChanged();
+                } else {
+                    // video
 
-                mRenderer->signalAudioSinkChanged();
+                    int32_t width, height;
+                    CHECK(codecRequest->findInt32("width", &width));
+                    CHECK(codecRequest->findInt32("height", &height));
+
+                    int32_t cropLeft, cropTop, cropRight, cropBottom;
+                    CHECK(codecRequest->findRect(
+                                "crop",
+                                &cropLeft, &cropTop, &cropRight, &cropBottom));
+
+                    LOGV("Video output format changed to %d x %d "
+                         "(crop: %d, %d, %d, %d)",
+                         width, height,
+                         cropLeft, cropTop, cropRight, cropBottom);
+
+                    notifyListener(
+                            MEDIA_SET_VIDEO_SIZE,
+                            cropRight - cropLeft + 1,
+                            cropBottom - cropTop + 1);
+                }
             } else if (what == ACodec::kWhatShutdownCompleted) {
                 LOGV("%s shutdown completed", audio ? "audio" : "video");
                 if (audio) {
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 39e0c51..dfb4e00 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -299,7 +299,8 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 ACodec::ACodec()
-    : mNode(NULL) {
+    : mNode(NULL),
+      mSentFormat(false) {
     mUninitializedState = new UninitializedState(this);
     mLoadedToIdleState = new LoadedToIdleState(this);
     mIdleToExecutingState = new IdleToExecutingState(this);
@@ -980,6 +981,103 @@
     }
 }
 
+void ACodec::sendFormatChange() {
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatOutputFormatChanged);
+
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+    def.nPortIndex = kPortIndexOutput;
+
+    CHECK_EQ(mOMX->getParameter(
+                mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)),
+             (status_t)OK);
+
+    CHECK_EQ((int)def.eDir, (int)OMX_DirOutput);
+
+    switch (def.eDomain) {
+        case OMX_PortDomainVideo:
+        {
+            OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
+
+            notify->setString("mime", MEDIA_MIMETYPE_VIDEO_RAW);
+            notify->setInt32("width", videoDef->nFrameWidth);
+            notify->setInt32("height", videoDef->nFrameHeight);
+
+            OMX_CONFIG_RECTTYPE rect;
+            InitOMXParams(&rect);
+            rect.nPortIndex = kPortIndexOutput;
+
+            if (mOMX->getConfig(
+                        mNode, OMX_IndexConfigCommonOutputCrop,
+                        &rect, sizeof(rect)) != OK) {
+                rect.nLeft = 0;
+                rect.nTop = 0;
+                rect.nWidth = videoDef->nFrameWidth;
+                rect.nHeight = videoDef->nFrameHeight;
+            }
+
+            CHECK_GE(rect.nLeft, 0);
+            CHECK_GE(rect.nTop, 0);
+            CHECK_GE(rect.nWidth, 0u);
+            CHECK_GE(rect.nHeight, 0u);
+            CHECK_LE(rect.nLeft + rect.nWidth - 1, videoDef->nFrameWidth);
+            CHECK_LE(rect.nTop + rect.nHeight - 1, videoDef->nFrameHeight);
+
+            notify->setRect(
+                    "crop",
+                    rect.nLeft,
+                    rect.nTop,
+                    rect.nLeft + rect.nWidth - 1,
+                    rect.nTop + rect.nHeight - 1);
+
+            if (mNativeWindow != NULL) {
+                android_native_rect_t crop;
+                crop.left = rect.nLeft;
+                crop.top = rect.nTop;
+                crop.right = rect.nLeft + rect.nWidth - 1;
+                crop.bottom = rect.nTop + rect.nHeight - 1;
+
+                CHECK_EQ(0, native_window_set_crop(
+                            mNativeWindow.get(), &crop));
+            }
+            break;
+        }
+
+        case OMX_PortDomainAudio:
+        {
+            OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio;
+            CHECK_EQ((int)audioDef->eEncoding, (int)OMX_AUDIO_CodingPCM);
+
+            OMX_AUDIO_PARAM_PCMMODETYPE params;
+            InitOMXParams(&params);
+            params.nPortIndex = kPortIndexOutput;
+
+            CHECK_EQ(mOMX->getParameter(
+                        mNode, OMX_IndexParamAudioPcm,
+                        &params, sizeof(params)),
+                     (status_t)OK);
+
+            CHECK(params.nChannels == 1 || params.bInterleaved);
+            CHECK_EQ(params.nBitPerSample, 16u);
+            CHECK_EQ((int)params.eNumData, (int)OMX_NumericalDataSigned);
+            CHECK_EQ((int)params.ePCMMode, (int)OMX_AUDIO_PCMModeLinear);
+
+            notify->setString("mime", MEDIA_MIMETYPE_AUDIO_RAW);
+            notify->setInt32("channel-count", params.nChannels);
+            notify->setInt32("sample-rate", params.nSamplingRate);
+            break;
+        }
+
+        default:
+            TRESPASS();
+    }
+
+    notify->post();
+
+    mSentFormat = true;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 ACodec::BaseState::BaseState(ACodec *codec, const sp<AState> &parentState)
@@ -1305,6 +1403,10 @@
                     info->mStatus = BufferInfo::OWNED_BY_COMPONENT;
                 }
             } else {
+                if (!mCodec->mSentFormat) {
+                    mCodec->sendFormatChange();
+                }
+
                 if (mCodec->mNativeWindow == NULL) {
                     info->mData->setRange(rangeOffset, rangeLength);
                 }
@@ -1717,7 +1819,7 @@
         {
             CHECK_EQ(data1, (OMX_U32)kPortIndexOutput);
 
-            if (data2 == OMX_IndexParamPortDefinition) {
+            if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
                 CHECK_EQ(mCodec->mOMX->sendCommand(
                             mCodec->mNode,
                             OMX_CommandPortDisable, kPortIndexOutput),
@@ -1729,6 +1831,8 @@
                 }
 
                 mCodec->changeState(mCodec->mOutputPortSettingsChangedState);
+            } else if (data2 == OMX_IndexConfigCommonOutputCrop) {
+                mCodec->mSentFormat = false;
             } else {
                 LOGV("[%s] OMX_EventPortSettingsChanged 0x%08lx",
                      mCodec->mComponentName.c_str(), data2);
@@ -1816,6 +1920,8 @@
             } else if (data1 == (OMX_U32)OMX_CommandPortEnable) {
                 CHECK_EQ(data2, (OMX_U32)kPortIndexOutput);
 
+                mCodec->mSentFormat = false;
+
                 LOGV("[%s] Output port now reenabled.",
                         mCodec->mComponentName.c_str());
 
@@ -1869,6 +1975,8 @@
 
 void ACodec::ExecutingToIdleState::stateEntered() {
     LOGV("[%s] Now Executing->Idle", mCodec->mComponentName.c_str());
+
+    mCodec->mSentFormat = false;
 }
 
 bool ACodec::ExecutingToIdleState::onOMXEvent(
diff --git a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp b/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp
index 0f08f6e..38778fb 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp
@@ -132,7 +132,10 @@
     }
 
     MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle);
-    CHECK_EQ(mode, actualMode);
+    if (mode != actualMode) {
+        PVCleanUpVideoDecoder(mHandle);
+        return UNKNOWN_ERROR;
+    }
 
     PVSetPostProcType((VideoDecControls *) mHandle, 0);
 
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index 0e40acc..b592c3f 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -171,6 +171,18 @@
     item->u.refValue = obj.get();
 }
 
+void AMessage::setRect(
+        const char *name,
+        int32_t left, int32_t top, int32_t right, int32_t bottom) {
+    Item *item = allocateItem(name);
+    item->mType = kTypeRect;
+
+    item->u.rectValue.mLeft = left;
+    item->u.rectValue.mTop = top;
+    item->u.rectValue.mRight = right;
+    item->u.rectValue.mBottom = bottom;
+}
+
 bool AMessage::findString(const char *name, AString *value) const {
     const Item *item = findItem(name, kTypeString);
     if (item) {
@@ -198,6 +210,22 @@
     return false;
 }
 
+bool AMessage::findRect(
+        const char *name,
+        int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const {
+    const Item *item = findItem(name, kTypeRect);
+    if (item == NULL) {
+        return false;
+    }
+
+    *left = item->u.rectValue.mLeft;
+    *top = item->u.rectValue.mTop;
+    *right = item->u.rectValue.mRight;
+    *bottom = item->u.rectValue.mBottom;
+
+    return true;
+}
+
 void AMessage::post(int64_t delayUs) {
     extern ALooperRoster gLooperRoster;
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 2fcd04e..38eed50 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -26,9 +26,11 @@
 import com.android.internal.view.BaseSurfaceHolder;
 import com.android.internal.view.RootViewSurfaceTaker;
 import com.android.internal.view.StandaloneActionMode;
+import com.android.internal.view.menu.ActionMenuView;
 import com.android.internal.view.menu.ContextMenuBuilder;
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.view.menu.MenuDialogHelper;
+import com.android.internal.view.menu.MenuItemImpl;
 import com.android.internal.view.menu.MenuPopupHelper;
 import com.android.internal.view.menu.MenuView;
 import com.android.internal.view.menu.SubMenuBuilder;
@@ -881,12 +883,16 @@
             // The window manager will give us a valid window token
             new MenuDialogHelper(subMenu).show(null);
         } else if (hasFeature(FEATURE_ACTION_BAR)) {
-            mActionButtonPopup = new ActionButtonSubmenu(getContext(), subMenu);
-            mActionButtonPopup.show();
-            Callback cb = getCallback();
-            if (cb != null) {
-                cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu);
-            }
+            mDecor.post(new Runnable() {
+                public void run() {
+                    mActionButtonPopup = new ActionButtonSubmenu(getContext(), subMenu);
+                    mActionButtonPopup.show();
+                    Callback cb = getCallback();
+                    if (cb != null) {
+                        cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu);
+                    }
+                }
+            });
         }
 
         return true;
@@ -3009,6 +3015,20 @@
         public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu) {
             super(context, subMenu);
             mSubMenu = subMenu;
+
+            MenuBuilder parentMenu = subMenu.getRootMenu();
+            MenuItemImpl item = (MenuItemImpl) subMenu.getItem();
+            if (!item.isActionButton()) {
+                // Give a reasonable anchor to nested submenus.
+                ActionMenuView amv = (ActionMenuView) parentMenu.getMenuView(
+                        MenuBuilder.TYPE_ACTION_BUTTON, null);
+
+                View anchor = amv.getOverflowButton();
+                if (anchor == null) {
+                    anchor = amv;
+                }
+                setAnchorView(anchor);
+            }
         }
 
         @Override
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index ae408fc..22dd804 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -144,6 +144,7 @@
         // update the provider list.
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         filter.addDataScheme("package");
         mContext.registerReceiver(mBroadcastReceiver, filter);
@@ -643,6 +644,12 @@
     }
 
     boolean addProviderLocked(ResolveInfo ri) {
+        if ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+            return false;
+        }
+        if (!ri.activityInfo.isEnabled()) {
+            return false;
+        }
         Provider p = parseProviderInfoXml(new ComponentName(ri.activityInfo.packageName,
                     ri.activityInfo.name), ri);
         if (p != null) {
@@ -1160,6 +1167,7 @@
                 }
             } else {
                 boolean added = false;
+                boolean changed = false;
                 String pkgList[] = null;
                 if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
@@ -1178,14 +1186,16 @@
                     }
                     pkgList = new String[] { pkgName };
                     added = Intent.ACTION_PACKAGE_ADDED.equals(action);
+                    changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
                 }
                 if (pkgList == null || pkgList.length == 0) {
                     return;
                 }
-                if (added) {
+                if (added || changed) {
                     synchronized (mAppWidgetIds) {
                         Bundle extras = intent.getExtras();
-                        if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
+                        if (changed || (extras != null &&
+                                    extras.getBoolean(Intent.EXTRA_REPLACING, false))) {
                             for (String pkgName : pkgList) {
                                 // The package was just upgraded
                                 updateProvidersForPackageLocked(pkgName);
diff --git a/tests/CoreTests/android/core/HeapTest.java b/tests/CoreTests/android/core/HeapTest.java
index 6116f5e..98cb28a 100644
--- a/tests/CoreTests/android/core/HeapTest.java
+++ b/tests/CoreTests/android/core/HeapTest.java
@@ -540,94 +540,4 @@
             objSize = (objSize * 4) / 5;
         }
     }
-
-    // TODO: flaky test
-    //@SmallTest
-    public void testExternalOomeLarge() {
-        /* Just shy of the typical max heap size so that it will actually
-         * try to allocate it instead of short-circuiting.
-         */
-        final int HUGE_SIZE = (16 * 1024 * 1024 - 32);
-
-        assertFalse(VMRuntime.getRuntime().trackExternalAllocation(HUGE_SIZE));
-    }
-
-    /**
-     * "Allocates" external memory in progressively smaller chunks until there's
-     * only roughly 16 bytes left.
-     *
-     * @return the number of bytes allocated
-     */
-    private long allocateMaxExternal() {
-        final VMRuntime runtime = VMRuntime.getRuntime();
-        final int SIXTEEN_MB = (16 * 1024 * 1024);
-        final int MIN_SIZE = 16;
-        long totalAllocated = 0;
-        boolean success;
-
-        success = false;
-        try {
-            /* "Allocate" progressively smaller chunks to "fill up" the entire heap.
-             */
-            int objSize = 1 * 1024 * 1024;
-            while (objSize >= MIN_SIZE) {
-                boolean sawFailure = false;
-                for (int i = 0; i < SIXTEEN_MB / objSize; i++) {
-                    if (runtime.trackExternalAllocation(objSize)) {
-                        totalAllocated += objSize;
-                    } else {
-                        sawFailure = true;
-                        break;
-                    }
-                }
-
-                if (!sawFailure) {
-                    throw new RuntimeException("Test failed: " +
-                            "no failure while filling heap");
-                }
-
-                objSize = (objSize * 4) / 5;
-            }
-            success = true;
-        } finally {
-            if (!success) {
-                runtime.trackExternalFree(totalAllocated);
-                totalAllocated = 0;
-            }
-        }
-        return totalAllocated;
-    }
-
-    public void xxtest00ExternalOomeSmall() {
-        VMRuntime.getRuntime().trackExternalFree(allocateMaxExternal());
-    }
-
-    /**
-     * Allocates as much external memory as possible, then allocates from the heap
-     * until an OOME is caught.
-     *
-     * It's nice to run this test while the real heap is small, hence the '00' in its
-     * name to force it to run before testOomeSmall().
-     */
-    public void xxtest00CombinedOomeSmall() {
-        long totalAllocated = 0;
-        boolean sawEx = false;
-        try {
-            totalAllocated = allocateMaxExternal();
-            LinkedList<Object> list = new LinkedList<Object>();
-            try {
-                while (true) {
-                    list.add((Object)new byte[8192]);
-                }
-                /*NOTREACHED*/
-            } catch (OutOfMemoryError oom) {
-                sawEx = true;
-            }
-        } finally {
-            VMRuntime.getRuntime().trackExternalFree(totalAllocated);
-        }
-        assertTrue(sawEx);
-    }
-
-    //TODO: test external alloc debugging/inspection
 }
diff --git a/tests/StatusBar/AndroidManifest.xml b/tests/StatusBar/AndroidManifest.xml
index ddb756b..81442bf 100644
--- a/tests/StatusBar/AndroidManifest.xml
+++ b/tests/StatusBar/AndroidManifest.xml
@@ -5,6 +5,7 @@
     <uses-permission android:name="android.permission.STATUS_BAR" />
     <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
     <uses-permission android:name="android.permission.VIBRATE" />
+    <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
 
     <application>
         <activity android:name="StatusBarTest" android:label="_StatusBar">
diff --git a/tests/StatusBar/src/com/android/statusbartest/PowerTest.java b/tests/StatusBar/src/com/android/statusbartest/PowerTest.java
index 92d5bee..31a1cf5a 100644
--- a/tests/StatusBar/src/com/android/statusbartest/PowerTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/PowerTest.java
@@ -26,6 +26,8 @@
 import android.os.IPowerManager;
 import android.widget.ListView;
 import android.content.Intent;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.StatusBarManager;
@@ -66,6 +68,24 @@
         return mTests;
     }
     private Test[] mTests = new Test[] {
+        new Test("Enable settings widget") {
+            public void run() {
+                PackageManager pm = getPackageManager();
+                pm.setComponentEnabledSetting(new ComponentName("com.android.settings",
+                            "com.android.settings.widget.SettingsAppWidgetProvider"),
+                        PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
+
+            }
+        },
+        new Test("Disable settings widget") {
+            public void run() {
+                PackageManager pm = getPackageManager();
+                pm.setComponentEnabledSetting(new ComponentName("com.android.settings",
+                            "com.android.settings.widget.SettingsAppWidgetProvider"),
+                        PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
+
+            }
+        },
         new Test("Enable proximity") {
             public void run() {
                 mProx.acquire();