Merge "For performance, return large objects by reference"
diff --git a/Android.mk b/Android.mk
index ace7b7c..5acfb86 100644
--- a/Android.mk
+++ b/Android.mk
@@ -94,7 +94,7 @@
 	core/java/android/bluetooth/IBluetoothHealthCallback.aidl \
 	core/java/android/bluetooth/IBluetoothPbap.aidl \
 	core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \
-	core/java/android/content/ICancelationSignal.aidl \
+	core/java/android/content/ICancellationSignal.aidl \
 	core/java/android/content/IClipboard.aidl \
 	core/java/android/content/IContentService.aidl \
 	core/java/android/content/IIntentReceiver.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index fb334fc..d74d7b1 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -117,6 +117,8 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/fonts/DroidSans*)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/content)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/android/content)
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/api/current.txt b/api/current.txt
index 0b2ecea..37b0328 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2288,7 +2288,8 @@
     method public long getStagger(int);
     method public long getStartDelay(int);
     method public java.util.List<android.animation.LayoutTransition.TransitionListener> getTransitionListeners();
-    method public void hideChild(android.view.ViewGroup, android.view.View);
+    method public deprecated void hideChild(android.view.ViewGroup, android.view.View);
+    method public void hideChild(android.view.ViewGroup, android.view.View, int);
     method public boolean isChangingLayout();
     method public boolean isRunning();
     method public void removeChild(android.view.ViewGroup, android.view.View);
@@ -2300,7 +2301,8 @@
     method public void setInterpolator(int, android.animation.TimeInterpolator);
     method public void setStagger(int, long);
     method public void setStartDelay(int, long);
-    method public void showChild(android.view.ViewGroup, android.view.View);
+    method public deprecated void showChild(android.view.ViewGroup, android.view.View);
+    method public void showChild(android.view.ViewGroup, android.view.View, int);
     field public static final int APPEARING = 2; // 0x2
     field public static final int CHANGE_APPEARING = 0; // 0x0
     field public static final int CHANGE_DISAPPEARING = 1; // 0x1
@@ -2400,6 +2402,16 @@
 
 }
 
+package android.annotation {
+
+  public abstract class SuppressLint implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class TargetApi implements java.lang.annotation.Annotation {
+  }
+
+}
+
 package android.app {
 
   public abstract class ActionBar {
@@ -4658,10 +4670,9 @@
 
   public abstract class AsyncTaskLoader extends android.content.Loader {
     ctor public AsyncTaskLoader(android.content.Context);
-    method public boolean cancelLoad();
-    method protected boolean isLoadInBackgroundCanceled();
+    method public void cancelLoadInBackground();
+    method public boolean isLoadInBackgroundCanceled();
     method public abstract D loadInBackground();
-    method protected void onCancelLoadInBackground();
     method public void onCanceled(D);
     method protected D onLoadInBackground();
     method public void setUpdateThrottle(long);
@@ -4703,15 +4714,15 @@
     method public final void setResultExtras(android.os.Bundle);
   }
 
-  public final class CancelationSignal {
-    ctor public CancelationSignal();
+  public final class CancellationSignal {
+    ctor public CancellationSignal();
     method public void cancel();
     method public boolean isCanceled();
-    method public void setOnCancelListener(android.content.CancelationSignal.OnCancelListener);
+    method public void setOnCancelListener(android.content.CancellationSignal.OnCancelListener);
     method public void throwIfCanceled();
   }
 
-  public static abstract interface CancelationSignal.OnCancelListener {
+  public static abstract interface CancellationSignal.OnCancelListener {
     method public abstract void onCancel();
   }
 
@@ -4834,7 +4845,7 @@
     method public android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
     method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
-    method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.content.CancelationSignal);
+    method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.content.CancellationSignal);
     method protected final void setPathPermissions(android.content.pm.PathPermission[]);
     method protected final void setReadPermission(java.lang.String);
     method protected final void setWritePermission(java.lang.String);
@@ -4858,7 +4869,7 @@
     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException, android.os.RemoteException;
     method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException, android.os.RemoteException;
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
-    method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.content.CancelationSignal) throws android.os.RemoteException;
+    method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.content.CancellationSignal) throws android.os.RemoteException;
     method public boolean release();
     method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
   }
@@ -4945,7 +4956,7 @@
     method public final java.io.OutputStream openOutputStream(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
     method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
     method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
-    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.content.CancelationSignal);
+    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.content.CancellationSignal);
     method public final void registerContentObserver(android.net.Uri, boolean, android.database.ContentObserver);
     method public static void removePeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle);
     method public static void removeStatusChangeListener(java.lang.Object);
@@ -5628,6 +5639,7 @@
     field public static final int FLAG_GRANT_READ_URI_PERMISSION = 1; // 0x1
     field public static final int FLAG_GRANT_WRITE_URI_PERMISSION = 2; // 0x2
     field public static final int FLAG_INCLUDE_STOPPED_PACKAGES = 32; // 0x20
+    field public static final int FLAG_RECEIVER_FOREGROUND = 268435456; // 0x10000000
     field public static final int FLAG_RECEIVER_REGISTERED_ONLY = 1073741824; // 0x40000000
     field public static final int FLAG_RECEIVER_REPLACE_PENDING = 536870912; // 0x20000000
     field public static final java.lang.String METADATA_DOCK_HOME = "android.dock_home";
@@ -5752,7 +5764,9 @@
   public class Loader {
     ctor public Loader(android.content.Context);
     method public void abandon();
+    method public boolean cancelLoad();
     method public java.lang.String dataToString(D);
+    method public void deliverCancellation();
     method public void deliverResult(D);
     method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
     method public void forceLoad();
@@ -5762,23 +5776,30 @@
     method public boolean isReset();
     method public boolean isStarted();
     method protected void onAbandon();
+    method protected boolean onCancelLoad();
     method public void onContentChanged();
     method protected void onForceLoad();
     method protected void onReset();
     method protected void onStartLoading();
     method protected void onStopLoading();
     method public void registerListener(int, android.content.Loader.OnLoadCompleteListener<D>);
+    method public void registerOnLoadCanceledListener(android.content.Loader.OnLoadCanceledListener<D>);
     method public void reset();
     method public final void startLoading();
     method public void stopLoading();
     method public boolean takeContentChanged();
     method public void unregisterListener(android.content.Loader.OnLoadCompleteListener<D>);
+    method public void unregisterOnLoadCanceledListener(android.content.Loader.OnLoadCanceledListener<D>);
   }
 
   public final class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
     ctor public Loader.ForceLoadContentObserver();
   }
 
+  public static abstract interface Loader.OnLoadCanceledListener {
+    method public abstract void onLoadCanceled(android.content.Loader<D>);
+  }
+
   public static abstract interface Loader.OnLoadCompleteListener {
     method public abstract void onLoadComplete(android.content.Loader<D>, D);
   }
@@ -7247,15 +7268,15 @@
     method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory);
     method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
     method public android.database.Cursor query(boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public android.database.Cursor query(boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String, android.content.CancelationSignal);
+    method public android.database.Cursor query(boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String, android.content.CancellationSignal);
     method public android.database.Cursor query(java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String);
     method public android.database.Cursor query(java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String);
     method public android.database.Cursor queryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public android.database.Cursor queryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String, android.content.CancelationSignal);
+    method public android.database.Cursor queryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String, android.content.CancellationSignal);
     method public android.database.Cursor rawQuery(java.lang.String, java.lang.String[]);
-    method public android.database.Cursor rawQuery(java.lang.String, java.lang.String[], android.content.CancelationSignal);
+    method public android.database.Cursor rawQuery(java.lang.String, java.lang.String[], android.content.CancellationSignal);
     method public android.database.Cursor rawQueryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, java.lang.String, java.lang.String[], java.lang.String);
-    method public android.database.Cursor rawQueryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, java.lang.String, java.lang.String[], java.lang.String, android.content.CancelationSignal);
+    method public android.database.Cursor rawQueryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, java.lang.String, java.lang.String[], java.lang.String, android.content.CancellationSignal);
     method public static int releaseMemory();
     method public long replace(java.lang.String, java.lang.String, android.content.ContentValues);
     method public long replaceOrThrow(java.lang.String, java.lang.String, android.content.ContentValues) throws android.database.SQLException;
@@ -7377,7 +7398,7 @@
     method public java.lang.String getTables();
     method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String);
     method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String, android.content.CancelationSignal);
+    method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String, android.content.CancellationSignal);
     method public void setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory);
     method public void setDistinct(boolean);
     method public void setProjectionMap(java.util.Map<java.lang.String, java.lang.String>);
@@ -9081,14 +9102,17 @@
     ctor public GradientDrawable(android.graphics.drawable.GradientDrawable.Orientation, int[]);
     method public void draw(android.graphics.Canvas);
     method public int getOpacity();
+    method public android.graphics.drawable.GradientDrawable.Orientation getOrientation();
     method public void setAlpha(int);
     method public void setColor(int);
     method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setColors(int[]);
     method public void setCornerRadii(float[]);
     method public void setCornerRadius(float);
     method public void setGradientCenter(float, float);
     method public void setGradientRadius(float);
     method public void setGradientType(int);
+    method public void setOrientation(android.graphics.drawable.GradientDrawable.Orientation);
     method public void setShape(int);
     method public void setSize(int, int);
     method public void setStroke(int, int);
@@ -10902,11 +10926,12 @@
   }
 
   public final class MediaRecorder.OutputFormat {
+    field public static final int AAC_ADTS = 6; // 0x6
     field public static final int AMR_NB = 3; // 0x3
     field public static final int AMR_WB = 4; // 0x4
     field public static final int DEFAULT = 0; // 0x0
     field public static final int MPEG_4 = 2; // 0x2
-    field public static final int RAW_AMR = 3; // 0x3
+    field public static final deprecated int RAW_AMR = 3; // 0x3
     field public static final int THREE_GPP = 1; // 0x1
   }
 
@@ -11615,7 +11640,7 @@
     method public void setNetworkPreference(int);
     method public int startUsingNetworkFeature(int, java.lang.String);
     method public int stopUsingNetworkFeature(int, java.lang.String);
-    field public static final java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
+    field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
     field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
     field public static final int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
     field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
@@ -17481,6 +17506,7 @@
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String DATA_ROAMING = "data_roaming";
     field public static final java.lang.String DEFAULT_INPUT_METHOD = "default_input_method";
+    field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
     field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned";
     field public static final java.lang.String ENABLED_ACCESSIBILITY_SERVICES = "enabled_accessibility_services";
     field public static final java.lang.String ENABLED_INPUT_METHODS = "enabled_input_methods";
@@ -17559,6 +17585,7 @@
     field public static final java.lang.String ALARM_ALERT = "alarm_alert";
     field public static final java.lang.String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
     field public static final deprecated java.lang.String ANDROID_ID = "android_id";
+    field public static final java.lang.String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
     field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
     field public static final java.lang.String AUTO_TIME = "auto_time";
     field public static final java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
@@ -23826,6 +23853,9 @@
     method public android.view.ViewPropertyAnimator translationXBy(float);
     method public android.view.ViewPropertyAnimator translationY(float);
     method public android.view.ViewPropertyAnimator translationYBy(float);
+    method public android.view.ViewPropertyAnimator withEndAction(java.lang.Runnable);
+    method public android.view.ViewPropertyAnimator withLayer();
+    method public android.view.ViewPropertyAnimator withStartAction(java.lang.Runnable);
     method public android.view.ViewPropertyAnimator x(float);
     method public android.view.ViewPropertyAnimator xBy(float);
     method public android.view.ViewPropertyAnimator y(float);
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 83c881a..16dc517 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -122,7 +122,7 @@
     dump_file("NETWORK DEV INFO", "/proc/net/dev");
     dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
     dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
-    run_command("QTAGUID STATS INFO", 10, "su", "root", "cat", "/proc/net/xt_qtaguid/stats", NULL);
+    dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
 
     dump_file("NETWORK ROUTES", "/proc/net/route");
     dump_file("NETWORK ROUTES IPV6", "/proc/net/ipv6_route");
@@ -334,7 +334,7 @@
         }
 
         /* switch to non-root user and group */
-        gid_t groups[] = { AID_LOG, AID_SDCARD_RW, AID_MOUNT, AID_INET };
+        gid_t groups[] = { AID_LOG, AID_SDCARD_RW, AID_MOUNT, AID_INET, AID_NET_BW_STATS };
         if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
             ALOGE("Unable to setgroups, aborting: %s\n", strerror(errno));
             return -1;
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 211be52..a463a62 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -17,8 +17,10 @@
 package android.accessibilityservice;
 
 import android.app.Service;
+import android.content.Context;
 import android.content.Intent;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
@@ -218,10 +220,17 @@
 
     private static final String LOG_TAG = "AccessibilityService";
 
-    private AccessibilityServiceInfo mInfo;
+    interface Callbacks {
+        public void onAccessibilityEvent(AccessibilityEvent event);
+        public void onInterrupt();
+        public void onServiceConnected();
+        public void onSetConnectionId(int connectionId);
+    }
 
     private int mConnectionId;
 
+    private AccessibilityServiceInfo mInfo;
+
     /**
      * Callback for {@link android.view.accessibility.AccessibilityEvent}s.
      *
@@ -282,27 +291,49 @@
      */
     @Override
     public final IBinder onBind(Intent intent) {
-        return new IEventListenerWrapper(this);
+        return new IEventListenerWrapper(this, getMainLooper(), new Callbacks() {
+            @Override
+            public void onServiceConnected() {
+                AccessibilityService.this.onServiceConnected();
+            }
+
+            @Override
+            public void onInterrupt() {
+                AccessibilityService.this.onInterrupt();
+            }
+
+            @Override
+            public void onAccessibilityEvent(AccessibilityEvent event) {
+                AccessibilityService.this.onAccessibilityEvent(event);
+            }
+
+            @Override
+            public void onSetConnectionId( int connectionId) {
+                mConnectionId = connectionId;
+            }
+        });
     }
 
     /**
      * Implements the internal {@link IEventListener} interface to convert
      * incoming calls to it back to calls on an {@link AccessibilityService}.
      */
-    class IEventListenerWrapper extends IEventListener.Stub
+    static class IEventListenerWrapper extends IEventListener.Stub
             implements HandlerCaller.Callback {
 
+        static final int NO_ID = -1;
+
         private static final int DO_SET_SET_CONNECTION = 10;
         private static final int DO_ON_INTERRUPT = 20;
         private static final int DO_ON_ACCESSIBILITY_EVENT = 30;
 
         private final HandlerCaller mCaller;
 
-        private final AccessibilityService mTarget;
+        private final Callbacks mCallback;
 
-        public IEventListenerWrapper(AccessibilityService context) {
-            mTarget = context;
-            mCaller = new HandlerCaller(context, this);
+        public IEventListenerWrapper(Context context, Looper looper, Callbacks callback) {
+            mCallback = callback;
+            mCaller = new HandlerCaller(context, looper, this);
         }
 
         public void setConnection(IAccessibilityServiceConnection connection, int connectionId) {
@@ -326,12 +357,13 @@
                 case DO_ON_ACCESSIBILITY_EVENT :
                     AccessibilityEvent event = (AccessibilityEvent) message.obj;
                     if (event != null) {
-                        mTarget.onAccessibilityEvent(event);
+                        AccessibilityInteractionClient.getInstance().onAccessibilityEvent(event);
+                        mCallback.onAccessibilityEvent(event);
                         event.recycle();
                     }
                     return;
                 case DO_ON_INTERRUPT :
-                    mTarget.onInterrupt();
+                    mCallback.onInterrupt();
                     return;
                 case DO_SET_SET_CONNECTION :
                     final int connectionId = message.arg1;
@@ -340,12 +372,11 @@
                     if (connection != null) {
                         AccessibilityInteractionClient.getInstance().addConnection(connectionId,
                                 connection);
-                        mConnectionId = connectionId;
-                        mTarget.onServiceConnected();
+                        mCallback.onSetConnectionId(connectionId);
+                        mCallback.onServiceConnected();
                     } else {
                         AccessibilityInteractionClient.getInstance().removeConnection(connectionId);
-                        mConnectionId = AccessibilityInteractionClient.NO_ID;
-                        // TODO: Do we need a onServiceDisconnected callback?
+                        mCallback.onSetConnectionId(AccessibilityInteractionClient.NO_ID);
                     }
                     return;
                 default :
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index e53b313..c9468eb 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -32,8 +32,13 @@
     /**
      * Finds an {@link AccessibilityNodeInfo} by accessibility id.
      *
-     * @param accessibilityWindowId A unique window id.
-     * @param accessibilityNodeId A unique view id or virtual descendant id.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+     *     to start from the root.
      * @param interactionId The id of the interaction for matching with the callback result.
      * @param callback Callback which to receive the result.
      * @param threadId The id of the calling thread.
@@ -46,57 +51,58 @@
     /**
      * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
      * insensitive containment. The search is performed in the window whose
-     * id is specified and starts from the View whose accessibility id is
+     * id is specified and starts from the node whose accessibility id is
      * specified.
      *
-     * @param text The searched text.
-     * @param accessibilityWindowId A unique window id.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
      * @param accessibilityNodeId A unique view id or virtual descendant id from
-     *        where to start the search. Use {@link android.view.View#NO_ID} to start from the root.
-     * @param interactionId The id of the interaction for matching with the callback result.
-     * @param callback Callback which to receive the result.
-     * @param threadId The id of the calling thread.
-     * @return The current window scale, where zero means a failure.
-     */
-    float findAccessibilityNodeInfosByText(String text, int accessibilityWindowId,
-        long accessibilityNodeId, int interractionId,
-        IAccessibilityInteractionConnectionCallback callback, long threadId);
-
-    /**
-     * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
-     * insensitive containment. The search is performed in the currently
-     * active window and start from the root View in the window.
-     *
+     *     where to start the search. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+     *     to start from the root.
      * @param text The searched text.
-     * @param accessibilityId The id of the view from which to start searching.
-     *        Use {@link android.view.View#NO_ID} to start from the root.
      * @param interactionId The id of the interaction for matching with the callback result.
      * @param callback Callback which to receive the result.
      * @param threadId The id of the calling thread.
      * @return The current window scale, where zero means a failure.
      */
-    float findAccessibilityNodeInfosByTextInActiveWindow(String text,
-        int interactionId, IAccessibilityInteractionConnectionCallback callback,
+    float findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId,
+        String text, int interactionId, IAccessibilityInteractionConnectionCallback callback,
         long threadId);
 
     /**
-     * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed
-     * in the currently active window and starts from the root View in the window.
+     * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed in
+     * the window whose id is specified and starts from the node whose accessibility
+     * id is specified.
      *
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+     *     to start from the root.
      * @param id The id of the node.
      * @param interactionId The id of the interaction for matching with the callback result.
      * @param callback Callback which to receive the result.
      * @param threadId The id of the calling thread.
      * @return The current window scale, where zero means a failure.
      */
-    float findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId, int interactionId,
-        IAccessibilityInteractionConnectionCallback callback, long threadId);
+    float findAccessibilityNodeInfoByViewId(int accessibilityWindowId, long accessibilityNodeId,
+        int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback,
+        long threadId);
 
     /**
      * Performs an accessibility action on an {@link AccessibilityNodeInfo}.
      *
-     * @param accessibilityWindowId The id of the window.
-     * @param accessibilityNodeId A unique view id or virtual descendant id.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+     *     to start from the root.
      * @param action The action to perform.
      * @param interactionId The id of the interaction for matching with the callback result.
      * @param callback Callback which to receive the result.
diff --git a/core/java/android/accessibilityservice/UiTestAutomationBridge.java b/core/java/android/accessibilityservice/UiTestAutomationBridge.java
new file mode 100644
index 0000000..9d48efc
--- /dev/null
+++ b/core/java/android/accessibilityservice/UiTestAutomationBridge.java
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2012 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.accessibilityservice;
+
+import android.accessibilityservice.AccessibilityService.Callbacks;
+import android.accessibilityservice.AccessibilityService.IEventListenerWrapper;
+import android.content.Context;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityInteractionClient;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.IAccessibilityManager;
+
+import com.android.internal.util.Predicate;
+
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * This class represents a bridge that can be used for UI test
+ * automation. It is responsible for connecting to the system,
+ * keeping track of the last accessibility event, and exposing
+ * window content querying APIs. This class is designed to be
+ * used from both an Android application and a Java program
+ * run from the shell.
+ *
+ * @hide
+ */
+public class UiTestAutomationBridge {
+
+    private static final String LOG_TAG = UiTestAutomationBridge.class.getSimpleName();
+
+    public static final int ACTIVE_WINDOW_ID = -1;
+
+    public static final long ROOT_NODE_ID = -1;
+
+    private static final int TIMEOUT_REGISTER_SERVICE = 5000;
+
+    private final Object mLock = new Object();
+
+    private volatile int mConnectionId = AccessibilityInteractionClient.NO_ID;
+
+    private IEventListenerWrapper mListener;
+
+    private AccessibilityEvent mLastEvent;
+
+    private volatile boolean mWaitingForEventDelivery;
+
+    private volatile boolean mUnprocessedEventAvailable;
+
+    /**
+     * Gets the last received {@link AccessibilityEvent}.
+     *
+     * @return The event.
+     */
+    public AccessibilityEvent getLastAccessibilityEvent() {
+        return mLastEvent; 
+    }
+
+    /**
+     * Callback for receiving an {@link AccessibilityEvent}.
+     *
+     * <strong>Note:</strong> This method is <strong>NOT</strong>
+     * executed on the application main thread. The client are
+     * responsible for proper synchronization.
+     *
+     * @param event The received event.
+     */
+    public void onAccessibilityEvent(AccessibilityEvent event) {
+        /* hook - do nothing */
+    }
+
+    /**
+     * Callback for requests to stop feedback.
+     *
+     * <strong>Note:</strong> This method is <strong>NOT</strong>
+     * executed on the application main thread. The client are
+     * responsible for proper synchronization.
+     */
+    public void onInterrupt() {
+        /* hook - do nothing */
+    }
+
+    /**
+     * Connects this service.
+     *
+     * @throws IllegalStateException If already connected.
+     */
+    public void connect() {
+        if (isConnected()) {
+            throw new IllegalStateException("Already connected.");
+        }
+
+        // Serialize binder calls to a handler on a dedicated thread
+        // different from the main since we expose APIs that block
+        // the main thread waiting for a result the deliver of which
+        // on the main thread will prevent that thread from waking up.
+        // The serialization is needed also to ensure that events are
+        // examined in delivery order. Otherwise, a fair locking
+        // is needed for making sure the binder calls are interleaved
+        // with check for the expected event and also to make sure the
+        // binder threads are allowed to proceed in the received order.
+        HandlerThread handlerThread = new HandlerThread("UiTestAutomationBridge");
+        handlerThread.start();
+        Looper looper = handlerThread.getLooper();
+
+        mListener = new IEventListenerWrapper(null, looper, new Callbacks() {
+            @Override
+            public void onServiceConnected() {
+                /* do nothing */
+            }
+
+            @Override
+            public void onInterrupt() {
+                UiTestAutomationBridge.this.onInterrupt();  
+            }
+
+            @Override
+            public void onAccessibilityEvent(AccessibilityEvent event) {
+                synchronized (mLock) {
+                    while (true) {
+                        if (!mWaitingForEventDelivery) {
+                            break;
+                        }
+                        if (!mUnprocessedEventAvailable) {
+                            mUnprocessedEventAvailable = true;
+                            mLastEvent = AccessibilityEvent.obtain(event);
+                            mLock.notifyAll();
+                            break;
+                        }
+                        try {
+                            mLock.wait();
+                        } catch (InterruptedException ie) {
+                            /* ignore */
+                        }
+                    }
+                }
+                UiTestAutomationBridge.this.onAccessibilityEvent(event);
+            }
+
+            @Override
+            public void onSetConnectionId(int connectionId) {
+                synchronized (mLock) {
+                    mConnectionId = connectionId;
+                    mLock.notifyAll();
+                }
+            }
+        });
+
+        final IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
+                ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
+
+        final AccessibilityServiceInfo info = new AccessibilityServiceInfo();
+        info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
+        info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
+
+        try {
+            manager.registerUiTestAutomationService(mListener, info);
+        } catch (RemoteException re) {
+            throw new IllegalStateException("Cound not register UiAutomationService.", re);
+        }
+
+        synchronized (mLock) {
+            final long startTimeMillis = SystemClock.uptimeMillis();
+            while (true) {
+                if (isConnected()) {
+                    return;
+                }
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                final long remainingTimeMillis = TIMEOUT_REGISTER_SERVICE - elapsedTimeMillis;
+                if (remainingTimeMillis <= 0) {
+                    throw new IllegalStateException("Cound not register UiAutomationService.");
+                }
+                try {
+                    mLock.wait(remainingTimeMillis);
+                } catch (InterruptedException ie) {
+                    /* ignore */
+                }
+            }
+        }
+    }
+
+    /**
+     * Disconnects this service.
+     *
+     * @throws IllegalStateException If already disconnected.
+     */
+    public void disconnect() {
+        if (!isConnected()) {
+            throw new IllegalStateException("Already disconnected.");
+        }
+
+        IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
+              ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
+
+        try {
+            manager.unregisterUiTestAutomationService(mListener);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error while unregistering UiTestAutomationService", re);
+        }
+    }
+
+    /**
+     * Gets whether this service is connected.
+     *
+     * @return True if connected.
+     */
+    public boolean isConnected() {
+        return (mConnectionId != AccessibilityInteractionClient.NO_ID);
+    }
+
+    /**
+     * Executes a command and waits for a specific accessibility event type up
+     * to a given timeout.
+     *
+     * @param command The command to execute before starting to wait for the event.
+     * @param predicate Predicate for recognizing the awaited event.
+     * @param timeoutMillis The max wait time in milliseconds.
+     */
+    public AccessibilityEvent executeCommandAndWaitForAccessibilityEvent(Runnable command,
+            Predicate<AccessibilityEvent> predicate, long timeoutMillis)
+            throws TimeoutException, Exception {
+        synchronized (mLock) {
+            // Prepare to wait for an event.
+            mWaitingForEventDelivery = true;
+            mUnprocessedEventAvailable = false;
+            if (mLastEvent != null) {
+                mLastEvent.recycle();
+                mLastEvent = null;
+            }
+            // Execute the command.
+            command.run();
+            // Wait for the event.
+            final long startTimeMillis = SystemClock.uptimeMillis();
+            while (true) {
+                // If the expected event is received, that's it.
+                if ((mUnprocessedEventAvailable && predicate.apply(mLastEvent))) {
+                    mWaitingForEventDelivery = false;
+                    mUnprocessedEventAvailable = false;
+                    mLock.notifyAll();
+                    return mLastEvent;
+                }
+                // Ask for another event.
+                mWaitingForEventDelivery = true;
+                mUnprocessedEventAvailable = false;
+                mLock.notifyAll();
+                // Check if timed out and if not wait.
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                final long remainingTimeMillis = timeoutMillis - elapsedTimeMillis;
+                if (remainingTimeMillis <= 0) {
+                    mWaitingForEventDelivery = false;
+                    mUnprocessedEventAvailable = false;
+                    mLock.notifyAll();
+                    throw new TimeoutException("Expacted event not received within: "
+                            + timeoutMillis + " ms.");
+                }
+                try {
+                    mLock.wait(remainingTimeMillis);
+                } catch (InterruptedException ie) {
+                    /* ignore */
+                }
+            }
+        }
+    }
+
+    /**
+     * Finds an {@link AccessibilityNodeInfo} by accessibility id in the active
+     * window. The search is performed from the root node.
+     *
+     * @param accessibilityNodeId A unique view id or virtual descendant id for
+     *     which to search.
+     * @return The current window scale, where zero means a failure.
+     */
+    public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityIdInActiveWindow(
+            long accessibilityNodeId) {
+        return findAccessibilityNodeInfoByAccessibilityId(ACTIVE_WINDOW_ID, accessibilityNodeId);
+    }
+
+    /**
+     * Finds an {@link AccessibilityNodeInfo} by accessibility id.
+     *
+     * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id or virtual descendant id for
+     *     which to search.
+     * @return The current window scale, where zero means a failure.
+     */
+    public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(
+            int accessibilityWindowId, long accessibilityNodeId) {
+        // Cache the id to avoid locking
+        final int connectionId = mConnectionId;
+        ensureValidConnection(connectionId);
+        return AccessibilityInteractionClient.getInstance()
+                .findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
+                        accessibilityWindowId, accessibilityNodeId);
+    }
+
+    /**
+     * Finds an {@link AccessibilityNodeInfo} by View id in the active
+     * window. The search is performed from the root node.
+     *
+     * @return The current window scale, where zero means a failure.
+     */
+    public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId) {
+        return findAccessibilityNodeInfoByViewId(ACTIVE_WINDOW_ID, ROOT_NODE_ID, viewId);
+    }
+
+    /**
+     * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed in
+     * the window whose id is specified and starts from the node whose accessibility
+     * id is specified.
+     *
+     * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use {@link #ROOT_NODE_ID} to start from the root.
+     * @return The current window scale, where zero means a failure.
+     */
+    public AccessibilityNodeInfo findAccessibilityNodeInfoByViewId(int accessibilityWindowId,
+            long accessibilityNodeId, int viewId) {
+        // Cache the id to avoid locking
+        final int connectionId = mConnectionId;
+        ensureValidConnection(connectionId);
+        return AccessibilityInteractionClient.getInstance()
+                .findAccessibilityNodeInfoByViewId(connectionId, accessibilityWindowId,
+                        accessibilityNodeId, viewId);
+    }
+
+    /**
+     * Finds {@link AccessibilityNodeInfo}s by View text in the active
+     * window. The search is performed from the root node.
+     *
+     * @param text The searched text.
+     * @return The current window scale, where zero means a failure.
+     */
+    public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByTextInActiveWindow(String text) {
+        return findAccessibilityNodeInfosByText(ACTIVE_WINDOW_ID, ROOT_NODE_ID, text);
+    }
+
+    /**
+     * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
+     * insensitive containment. The search is performed in the window whose
+     * id is specified and starts from the node whose accessibility id is
+     * specified.
+     *
+     * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use {@link #ROOT_NODE_ID} to start from the root.
+     * @param text The searched text.
+     * @return The current window scale, where zero means a failure.
+     */
+    public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(int accessibilityWindowId,
+            long accessibilityNodeId, String text) {
+        // Cache the id to avoid locking
+        final int connectionId = mConnectionId;
+        ensureValidConnection(connectionId);
+        return AccessibilityInteractionClient.getInstance()
+                .findAccessibilityNodeInfosByText(connectionId, accessibilityWindowId,
+                        accessibilityNodeId, text);
+    }
+
+    /**
+     * Performs an accessibility action on an {@link AccessibilityNodeInfo}
+     * in the active window.
+     *
+     * @param accessibilityNodeId A unique node id (accessibility and virtual descendant id).
+     * @param action The action to perform.
+     * @return Whether the action was performed.
+     */
+    public boolean performAccessibilityActionInActiveWindow(long accessibilityNodeId, int action) {
+        return performAccessibilityAction(ACTIVE_WINDOW_ID, accessibilityNodeId, action);
+    }
+
+    /**
+     * Performs an accessibility action on an {@link AccessibilityNodeInfo}.
+     *
+     * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique node id (accessibility and virtual descendant id).
+     * @param action The action to perform.
+     * @return Whether the action was performed.
+     */
+    public boolean performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId,
+            int action) {
+        // Cache the id to avoid locking
+        final int connectionId = mConnectionId;
+        ensureValidConnection(connectionId);
+        return AccessibilityInteractionClient.getInstance().performAccessibilityAction(connectionId,
+                accessibilityWindowId, accessibilityNodeId, action);
+    }
+
+    private void ensureValidConnection(int connectionId) {
+        if (connectionId == AccessibilityInteractionClient.NO_ID) {
+            throw new IllegalStateException("UiAutomationService not connected."
+                    + " Did you call #register()?");
+        }
+    }
+}
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index 894f428..634e4d8 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -960,17 +960,17 @@
         if (anim instanceof ObjectAnimator) {
             ((ObjectAnimator) anim).setCurrentPlayTime(0);
         }
-        if (mListeners != null) {
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator anim) {
-                    currentAppearingAnimations.remove(child);
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator anim) {
+                currentAppearingAnimations.remove(child);
+                if (mListeners != null) {
                     for (TransitionListener listener : mListeners) {
                         listener.endTransition(LayoutTransition.this, parent, child, APPEARING);
                     }
                 }
-            });
-        }
+            }
+        });
         currentAppearingAnimations.put(child, anim);
         anim.start();
     }
@@ -998,17 +998,19 @@
         anim.setStartDelay(mDisappearingDelay);
         anim.setDuration(mDisappearingDuration);
         anim.setTarget(child);
-        if (mListeners != null) {
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator anim) {
-                    currentDisappearingAnimations.remove(child);
+        final float preAnimAlpha = child.getAlpha();
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator anim) {
+                currentDisappearingAnimations.remove(child);
+                child.setAlpha(preAnimAlpha);
+                if (mListeners != null) {
                     for (TransitionListener listener : mListeners) {
                         listener.endTransition(LayoutTransition.this, parent, child, DISAPPEARING);
                     }
                 }
-            });
-        }
+            }
+        });
         if (anim instanceof ObjectAnimator) {
             ((ObjectAnimator) anim).setCurrentPlayTime(0);
         }
@@ -1024,18 +1026,25 @@
      *
      * @param parent The ViewGroup to which the View is being added.
      * @param child The View being added to the ViewGroup.
+     * @param changesLayout Whether the removal will cause changes in the layout of other views
+     * in the container. INVISIBLE views becoming VISIBLE will not cause changes and thus will not
+     * affect CHANGE_APPEARING or CHANGE_DISAPPEARING animations.
      */
-    public void addChild(ViewGroup parent, View child) {
+    private void addChild(ViewGroup parent, View child, boolean changesLayout) {
         // Want disappearing animations to finish up before proceeding
         cancel(DISAPPEARING);
-        // Also, cancel changing animations so that we start fresh ones from current locations
-        cancel(CHANGE_APPEARING);
+        if (changesLayout) {
+            // Also, cancel changing animations so that we start fresh ones from current locations
+            cancel(CHANGE_APPEARING);
+        }
         if (mListeners != null) {
             for (TransitionListener listener : mListeners) {
                 listener.startTransition(this, parent, child, APPEARING);
             }
         }
-        runChangeTransition(parent, child, APPEARING);
+        if (changesLayout) {
+            runChangeTransition(parent, child, APPEARING);
+        }
         runAppearingTransition(parent, child);
     }
 
@@ -1048,8 +1057,31 @@
      * @param parent The ViewGroup to which the View is being added.
      * @param child The View being added to the ViewGroup.
      */
+    public void addChild(ViewGroup parent, View child) {
+        addChild(parent, child, true);
+    }
+
+    /**
+     * @deprecated Use {@link #showChild(android.view.ViewGroup, android.view.View, int)}.
+     */
+    @Deprecated
     public void showChild(ViewGroup parent, View child) {
-        addChild(parent, child);
+        addChild(parent, child, true);
+    }
+
+    /**
+     * This method is called by ViewGroup when a child view is about to be made visible in the
+     * container. This callback starts the process of a transition; we grab the starting
+     * values, listen for changes to all of the children of the container, and start appropriate
+     * animations.
+     *
+     * @param parent The ViewGroup in which the View is being made visible.
+     * @param child The View being made visible.
+     * @param oldVisibility The previous visibility value of the child View, either
+     * {@link View#GONE} or {@link View#INVISIBLE}.
+     */
+    public void showChild(ViewGroup parent, View child, int oldVisibility) {
+        addChild(parent, child, oldVisibility == View.GONE);
     }
 
     /**
@@ -1060,18 +1092,25 @@
      *
      * @param parent The ViewGroup from which the View is being removed.
      * @param child The View being removed from the ViewGroup.
+     * @param changesLayout Whether the removal will cause changes in the layout of other views
+     * in the container. Views becoming INVISIBLE will not cause changes and thus will not
+     * affect CHANGE_APPEARING or CHANGE_DISAPPEARING animations.
      */
-    public void removeChild(ViewGroup parent, View child) {
+    private void removeChild(ViewGroup parent, View child, boolean changesLayout) {
         // Want appearing animations to finish up before proceeding
         cancel(APPEARING);
-        // Also, cancel changing animations so that we start fresh ones from current locations
-        cancel(CHANGE_DISAPPEARING);
+        if (changesLayout) {
+            // Also, cancel changing animations so that we start fresh ones from current locations
+            cancel(CHANGE_DISAPPEARING);
+        }
         if (mListeners != null) {
             for (TransitionListener listener : mListeners) {
                 listener.startTransition(this, parent, child, DISAPPEARING);
             }
         }
-        runChangeTransition(parent, child, DISAPPEARING);
+        if (changesLayout) {
+            runChangeTransition(parent, child, DISAPPEARING);
+        }
         runDisappearingTransition(parent, child);
     }
 
@@ -1084,8 +1123,31 @@
      * @param parent The ViewGroup from which the View is being removed.
      * @param child The View being removed from the ViewGroup.
      */
+    public void removeChild(ViewGroup parent, View child) {
+        removeChild(parent, child, true);
+    }
+
+    /**
+     * @deprecated Use {@link #hideChild(android.view.ViewGroup, android.view.View, int)}.
+     */
+    @Deprecated
     public void hideChild(ViewGroup parent, View child) {
-        removeChild(parent, child);
+        removeChild(parent, child, true);
+    }
+
+    /**
+     * This method is called by ViewGroup when a child view is about to be hidden in
+     * container. This callback starts the process of a transition; we grab the starting
+     * values, listen for changes to all of the children of the container, and start appropriate
+     * animations.
+     *
+     * @param parent The parent ViewGroup of the View being hidden.
+     * @param child The View being hidden.
+     * @param newVisibility The new visibility value of the child View, either
+     * {@link View#GONE} or {@link View#INVISIBLE}.
+     */
+    public void hideChild(ViewGroup parent, View child, int newVisibility) {
+        removeChild(parent, child, newVisibility == View.GONE);
     }
 
     /**
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index c7a129e..cc1efb9 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -19,6 +19,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.SystemProperties;
 import android.util.AndroidRuntimeException;
 import android.view.Choreographer;
 import android.view.animation.AccelerateDecelerateInterpolator;
@@ -52,6 +53,7 @@
     /**
      * Internal constants
      */
+    private static float sDurationScale = 1.0f;
 
     /**
      * Messages sent to timing handler: START is sent when an animation first begins.
@@ -158,10 +160,12 @@
     //
 
     // How long the animation should last in ms
-    private long mDuration = 300;
+    private long mDuration = (long)(300 * sDurationScale);
+    private long mUnscaledDuration = 300;
 
     // The amount of time in ms to delay starting the animation after start() is called
     private long mStartDelay = 0;
+    private long mUnscaledStartDelay = 0;
 
     // The number of times the animation will repeat. The default is 0, which means the animation
     // will play only once
@@ -217,6 +221,14 @@
      */
     public static final int INFINITE = -1;
 
+
+    /**
+     * @hide
+     */
+    public static void setDurationScale(float durationScale) {
+        sDurationScale = durationScale;
+    }
+
     /**
      * Creates a new ValueAnimator object. This default constructor is primarily for
      * use internally; the factory methods which take parameters are more generally
@@ -453,7 +465,8 @@
             throw new IllegalArgumentException("Animators cannot have negative duration: " +
                     duration);
         }
-        mDuration = duration;
+        mUnscaledDuration = duration;
+        mDuration = (long)(duration * sDurationScale);
         return this;
     }
 
@@ -463,7 +476,7 @@
      * @return The length of the animation, in milliseconds.
      */
     public long getDuration() {
-        return mDuration;
+        return mUnscaledDuration;
     }
 
     /**
@@ -658,7 +671,7 @@
      * @return the number of milliseconds to delay running the animation
      */
     public long getStartDelay() {
-        return mStartDelay;
+        return mUnscaledStartDelay;
     }
 
     /**
@@ -668,7 +681,8 @@
      * @param startDelay The amount of the delay, in milliseconds
      */
     public void setStartDelay(long startDelay) {
-        this.mStartDelay = startDelay;
+        this.mStartDelay = (long)(startDelay * sDurationScale);
+        mUnscaledStartDelay = startDelay;
     }
 
     /**
diff --git a/core/java/android/annotation/SuppressLint.java b/core/java/android/annotation/SuppressLint.java
new file mode 100644
index 0000000..2d3456b
--- /dev/null
+++ b/core/java/android/annotation/SuppressLint.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 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.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Indicates that Lint should ignore the specified warnings for the annotated element. */
+@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
+@Retention(RetentionPolicy.CLASS)
+public @interface SuppressLint {
+    /**
+     * The set of warnings (identified by the lint issue id) that should be
+     * ignored by lint. It is not an error to specify an unrecognized name.
+     */
+    String[] value();
+}
diff --git a/core/java/android/annotation/TargetApi.java b/core/java/android/annotation/TargetApi.java
new file mode 100644
index 0000000..ea17890
--- /dev/null
+++ b/core/java/android/annotation/TargetApi.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012 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.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Indicates that Lint should treat this type as targeting a given API level, no matter what the
+    project target is. */
+@Target({TYPE, METHOD, CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface TargetApi {
+    /**
+     * This sets the target api level for the type..
+     */
+    int value();
+}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9807b89..3c5f53a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4413,7 +4413,7 @@
         });
     }
 
-    public static final ActivityThread systemMain() {
+    public static ActivityThread systemMain() {
         HardwareRenderer.disable(true);
         ActivityThread thread = new ActivityThread();
         thread.attach(true);
@@ -4454,6 +4454,8 @@
         ActivityThread thread = new ActivityThread();
         thread.attach(false);
 
+        AsyncTask.init();
+
         if (false) {
             Looper.myLooper().setMessageLogging(new
                     LogPrinter(Log.DEBUG, "ActivityThread"));
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index d83d2e6..ff71ee7 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.content.Loader;
+import android.content.Loader.OnLoadCanceledListener;
 import android.os.Bundle;
 import android.util.DebugUtils;
 import android.util.Log;
@@ -219,7 +220,8 @@
     
     boolean mCreatingLoader;
 
-    final class LoaderInfo implements Loader.OnLoadCompleteListener<Object> {
+    final class LoaderInfo implements Loader.OnLoadCompleteListener<Object>,
+            Loader.OnLoadCanceledListener<Object> {
         final int mId;
         final Bundle mArgs;
         LoaderManager.LoaderCallbacks<Object> mCallbacks;
@@ -271,6 +273,7 @@
                 }
                 if (!mListenerRegistered) {
                     mLoader.registerListener(mId, this);
+                    mLoader.registerOnLoadCanceledListener(this);
                     mListenerRegistered = true;
                 }
                 mLoader.startLoading();
@@ -329,11 +332,21 @@
                     // Let the loader know we're done with it
                     mListenerRegistered = false;
                     mLoader.unregisterListener(this);
+                    mLoader.unregisterOnLoadCanceledListener(this);
                     mLoader.stopLoading();
                 }
             }
         }
-        
+
+        void cancel() {
+            if (DEBUG) Log.v(TAG, "  Canceling: " + this);
+            if (mStarted && mLoader != null && mListenerRegistered) {
+                if (!mLoader.cancelLoad()) {
+                    onLoadCanceled(mLoader);
+                }
+            }
+        }
+
         void destroy() {
             if (DEBUG) Log.v(TAG, "  Destroying: " + this);
             mDestroyed = true;
@@ -361,6 +374,7 @@
                 if (mListenerRegistered) {
                     mListenerRegistered = false;
                     mLoader.unregisterListener(this);
+                    mLoader.unregisterOnLoadCanceledListener(this);
                 }
                 mLoader.reset();
             }
@@ -368,8 +382,38 @@
                 mPendingLoader.destroy();
             }
         }
-        
-        @Override public void onLoadComplete(Loader<Object> loader, Object data) {
+
+        @Override
+        public void onLoadCanceled(Loader<Object> loader) {
+            if (DEBUG) Log.v(TAG, "onLoadCanceled: " + this);
+
+            if (mDestroyed) {
+                if (DEBUG) Log.v(TAG, "  Ignoring load canceled -- destroyed");
+                return;
+            }
+
+            if (mLoaders.get(mId) != this) {
+                // This cancellation message is not coming from the current active loader.
+                // We don't care about it.
+                if (DEBUG) Log.v(TAG, "  Ignoring load canceled -- not active");
+                return;
+            }
+
+            LoaderInfo pending = mPendingLoader;
+            if (pending != null) {
+                // There is a new request pending and we were just
+                // waiting for the old one to cancel or complete before starting
+                // it.  So now it is time, switch over to the new loader.
+                if (DEBUG) Log.v(TAG, "  Switching to pending loader: " + pending);
+                mPendingLoader = null;
+                mLoaders.put(mId, null);
+                destroy();
+                installLoader(pending);
+            }
+        }
+
+        @Override
+        public void onLoadComplete(Loader<Object> loader, Object data) {
             if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
             
             if (mDestroyed) {
@@ -632,7 +676,9 @@
                     } else {
                         // Now we have three active loaders... we'll queue
                         // up this request to be processed once one of the other loaders
-                        // finishes.
+                        // finishes or is canceled.
+                        if (DEBUG) Log.v(TAG, "  Current loader is running; attempting to cancel");
+                        info.cancel();
                         if (info.mPendingLoader != null) {
                             if (DEBUG) Log.v(TAG, "  Removing pending loader: " + info.mPendingLoader);
                             info.mPendingLoader.destroy();
diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java
index 944ca6b..da51952 100644
--- a/core/java/android/content/AsyncTaskLoader.java
+++ b/core/java/android/content/AsyncTaskLoader.java
@@ -53,19 +53,33 @@
     static final boolean DEBUG = false;
 
     final class LoadTask extends AsyncTask<Void, Void, D> implements Runnable {
+        private final CountDownLatch mDone = new CountDownLatch(1);
 
-        D result;
+        // Set to true to indicate that the task has been posted to a handler for
+        // execution at a later time.  Used to throttle updates.
         boolean waiting;
 
-        private CountDownLatch done = new CountDownLatch(1);
-
         /* Runs on a worker thread */
         @Override
         protected D doInBackground(Void... params) {
             if (DEBUG) Slog.v(TAG, this + " >>> doInBackground");
-            result = AsyncTaskLoader.this.onLoadInBackground();
-            if (DEBUG) Slog.v(TAG, this + "  <<< doInBackground");
-            return result;
+            try {
+                D data = AsyncTaskLoader.this.onLoadInBackground();
+                if (DEBUG) Slog.v(TAG, this + "  <<< doInBackground");
+                return data;
+            } catch (OperationCanceledException ex) {
+                if (!isCancelled()) {
+                    // onLoadInBackground threw a canceled exception spuriously.
+                    // This is problematic because it means that the LoaderManager did not
+                    // cancel the Loader itself and still expects to receive a result.
+                    // Additionally, the Loader's own state will not have been updated to
+                    // reflect the fact that the task was being canceled.
+                    // So we treat this case as an unhandled exception.
+                    throw ex;
+                }
+                if (DEBUG) Slog.v(TAG, this + "  <<< doInBackground (was canceled)");
+                return null;
+            }
         }
 
         /* Runs on the UI thread */
@@ -75,25 +89,37 @@
             try {
                 AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
             } finally {
-                done.countDown();
+                mDone.countDown();
             }
         }
 
+        /* Runs on the UI thread */
         @Override
-        protected void onCancelled() {
+        protected void onCancelled(D data) {
             if (DEBUG) Slog.v(TAG, this + " onCancelled");
             try {
-                AsyncTaskLoader.this.dispatchOnCancelled(this, result);
+                AsyncTaskLoader.this.dispatchOnCancelled(this, data);
             } finally {
-                done.countDown();
+                mDone.countDown();
             }
         }
 
+        /* Runs on the UI thread, when the waiting task is posted to a handler.
+         * This method is only executed when task execution was deferred (waiting was true). */
         @Override
         public void run() {
             waiting = false;
             AsyncTaskLoader.this.executePendingTask();
         }
+
+        /* Used for testing purposes to wait for the task to complete. */
+        public void waitForLoader() {
+            try {
+                mDone.await();
+            } catch (InterruptedException e) {
+                // Ignore
+            }
+        }
     }
 
     volatile LoadTask mTask;
@@ -109,7 +135,7 @@
 
     /**
      * Set amount to throttle updates by.  This is the minimum time from
-     * when the last {@link #onLoadInBackground()} call has completed until
+     * when the last {@link #loadInBackground()} call has completed until
      * a new load is scheduled.
      *
      * @param delayMS Amount of delay, in milliseconds.
@@ -130,24 +156,9 @@
         executePendingTask();
     }
 
-    /**
-     * Attempt to cancel the current load task. See {@link AsyncTask#cancel(boolean)}
-     * for more info.  Must be called on the main thread of the process.
-     *
-     * <p>Cancelling is not an immediate operation, since the load is performed
-     * in a background thread.  If there is currently a load in progress, this
-     * method requests that the load be cancelled, and notes this is the case;
-     * once the background thread has completed its work its remaining state
-     * will be cleared.  If another load request comes in during this time,
-     * it will be held until the cancelled load is complete.
-     *
-     * @return Returns <tt>false</tt> if the task could not be cancelled,
-     *         typically because it has already completed normally, or
-     *         because {@link #startLoading()} hasn't been called; returns
-     *         <tt>true</tt> otherwise.
-     */
-    public boolean cancelLoad() {
-        if (DEBUG) Slog.v(TAG, "cancelLoad: mTask=" + mTask);
+    @Override
+    protected boolean onCancelLoad() {
+        if (DEBUG) Slog.v(TAG, "onCancelLoad: mTask=" + mTask);
         if (mTask != null) {
             if (mCancellingTask != null) {
                 // There was a pending task already waiting for a previous
@@ -173,7 +184,7 @@
                 if (DEBUG) Slog.v(TAG, "cancelLoad: cancelled=" + cancelled);
                 if (cancelled) {
                     mCancellingTask = mTask;
-                    onCancelLoadInBackground();
+                    cancelLoadInBackground();
                 }
                 mTask = null;
                 return cancelled;
@@ -184,7 +195,10 @@
 
     /**
      * Called if the task was canceled before it was completed.  Gives the class a chance
-     * to properly dispose of the result.
+     * to clean up post-cancellation and to properly dispose of the result.
+     *
+     * @param data The value that was returned by {@link #loadInBackground}, or null
+     * if the task threw {@link OperationCanceledException}.
      */
     public void onCanceled(D data) {
     }
@@ -218,6 +232,8 @@
             if (DEBUG) Slog.v(TAG, "Cancelled task is now canceled!");
             mLastLoadCompleteTime = SystemClock.uptimeMillis();
             mCancellingTask = null;
+            if (DEBUG) Slog.v(TAG, "Delivering cancellation");
+            deliverCancellation();
             executePendingTask();
         }
     }
@@ -240,38 +256,72 @@
     }
 
     /**
+     * Called on a worker thread to perform the actual load and to return
+     * the result of the load operation.
+     *
+     * Implementations should not deliver the result directly, but should return them
+     * from this method, which will eventually end up calling {@link #deliverResult} on
+     * the UI thread.  If implementations need to process the results on the UI thread
+     * they may override {@link #deliverResult} and do so there.
+     *
+     * To support cancellation, this method should periodically check the value of
+     * {@link #isLoadInBackgroundCanceled} and terminate when it returns true.
+     * Subclasses may also override {@link #cancelLoadInBackground} to interrupt the load
+     * directly instead of polling {@link #isLoadInBackgroundCanceled}.
+     *
+     * When the load is canceled, this method may either return normally or throw
+     * {@link OperationCanceledException}.  In either case, the {@link Loader} will
+     * call {@link #onCanceled} to perform post-cancellation cleanup and to dispose of the
+     * result object, if any.
+     *
+     * @return The result of the load operation.
+     *
+     * @throws OperationCanceledException if the load is canceled during execution.
+     *
+     * @see #isLoadInBackgroundCanceled
+     * @see #cancelLoadInBackground
+     * @see #onCanceled
      */
     public abstract D loadInBackground();
 
     /**
-     * Called on a worker thread to perform the actual load. Implementations should not deliver the
-     * result directly, but should return them from this method, which will eventually end up
-     * calling {@link #deliverResult} on the UI thread. If implementations need to process
-     * the results on the UI thread they may override {@link #deliverResult} and do so
-     * there.
+     * Calls {@link #loadInBackground()}.
      *
-     * @return Implementations must return the result of their load operation.
+     * This method is reserved for use by the loader framework.
+     * Subclasses should override {@link #loadInBackground} instead of this method.
+     *
+     * @return The result of the load operation.
+     *
+     * @throws OperationCanceledException if the load is canceled during execution.
+     *
+     * @see #loadInBackground
      */
     protected D onLoadInBackground() {
         return loadInBackground();
     }
 
     /**
-     * Override this method to try to abort the computation currently taking
-     * place on a background thread.
+     * Called on the main thread to abort a load in progress.
      *
-     * Note that when this method is called, it is possible that {@link #loadInBackground}
-     * has not started yet or has already completed.
+     * Override this method to abort the current invocation of {@link #loadInBackground}
+     * that is running in the background on a worker thread.
+     *
+     * This method should do nothing if {@link #loadInBackground} has not started
+     * running or if it has already finished.
+     *
+     * @see #loadInBackground
      */
-    protected void onCancelLoadInBackground() {
+    public void cancelLoadInBackground() {
     }
 
     /**
-     * Returns true if the current execution of {@link #loadInBackground()} is being canceled.
+     * Returns true if the current invocation of {@link #loadInBackground} is being canceled.
      *
-     * @return True if the current execution of {@link #loadInBackground()} is being canceled.
+     * @return True if the current invocation of {@link #loadInBackground} is being canceled.
+     *
+     * @see #loadInBackground
      */
-    protected boolean isLoadInBackgroundCanceled() {
+    public boolean isLoadInBackgroundCanceled() {
         return mCancellingTask != null;
     }
 
@@ -288,11 +338,7 @@
     public void waitForLoader() {
         LoadTask task = mTask;
         if (task != null) {
-            try {
-                task.done.await();
-            } catch (InterruptedException e) {
-                // Ignore
-            }
+            task.waitForLoader();
         }
     }
 
diff --git a/core/java/android/content/CancelationSignal.java b/core/java/android/content/CancellationSignal.java
similarity index 69%
rename from core/java/android/content/CancelationSignal.java
rename to core/java/android/content/CancellationSignal.java
index 58cf59d..2dbbe54 100644
--- a/core/java/android/content/CancelationSignal.java
+++ b/core/java/android/content/CancellationSignal.java
@@ -21,15 +21,15 @@
 /**
  * Provides the ability to cancel an operation in progress.
  */
-public final class CancelationSignal {
+public final class CancellationSignal {
     private boolean mIsCanceled;
     private OnCancelListener mOnCancelListener;
-    private ICancelationSignal mRemote;
+    private ICancellationSignal mRemote;
 
     /**
-     * Creates a cancelation signal, initially not canceled.
+     * Creates a cancellation signal, initially not canceled.
      */
-    public CancelationSignal() {
+    public CancellationSignal() {
     }
 
     /**
@@ -55,7 +55,7 @@
     }
 
     /**
-     * Cancels the operation and signals the cancelation listener.
+     * Cancels the operation and signals the cancellation listener.
      * If the operation has not yet started, then it will be canceled as soon as it does.
      */
     public void cancel() {
@@ -76,17 +76,23 @@
     }
 
     /**
-     * Sets the cancelation listener to be called when canceled.
-     * If {@link CancelationSignal#cancel} has already been called, then the provided
+     * Sets the cancellation listener to be called when canceled.
+     *
+     * This method is intended to be used by the recipient of a cancellation signal
+     * such as a database or a content provider to handle cancellation requests
+     * while performing a long-running operation.  This method is not intended to be
+     * used by applications themselves.
+     *
+     * If {@link CancellationSignal#cancel} has already been called, then the provided
      * listener is invoked immediately.
      *
-     * The listener is called while holding the cancelation signal's lock which is
+     * The listener is called while holding the cancellation signal's lock which is
      * also held while registering or unregistering the listener.  Because of the lock,
      * it is not possible for the listener to run after it has been unregistered.
-     * This design choice makes it easier for clients of {@link CancelationSignal} to
+     * This design choice makes it easier for clients of {@link CancellationSignal} to
      * prevent race conditions related to listener registration and unregistration.
      *
-     * @param listener The cancelation listener, or null to remove the current listener.
+     * @param listener The cancellation listener, or null to remove the current listener.
      */
     public void setOnCancelListener(OnCancelListener listener) {
         synchronized (this) {
@@ -104,7 +110,7 @@
      *
      * @hide
      */
-    public void setRemote(ICancelationSignal remote) {
+    public void setRemote(ICancellationSignal remote) {
         synchronized (this) {
             mRemote = remote;
             if (mIsCanceled && remote != null) {
@@ -118,47 +124,47 @@
 
     /**
      * Creates a transport that can be returned back to the caller of
-     * a Binder function and subsequently used to dispatch a cancelation signal.
+     * a Binder function and subsequently used to dispatch a cancellation signal.
      *
-     * @return The new cancelation signal transport.
+     * @return The new cancellation signal transport.
      *
      * @hide
      */
-    public static ICancelationSignal createTransport() {
+    public static ICancellationSignal createTransport() {
         return new Transport();
     }
 
     /**
-     * Given a locally created transport, returns its associated cancelation signal.
+     * Given a locally created transport, returns its associated cancellation signal.
      *
      * @param transport The locally created transport, or null if none.
-     * @return The associated cancelation signal, or null if none.
+     * @return The associated cancellation signal, or null if none.
      *
      * @hide
      */
-    public static CancelationSignal fromTransport(ICancelationSignal transport) {
+    public static CancellationSignal fromTransport(ICancellationSignal transport) {
         if (transport instanceof Transport) {
-            return ((Transport)transport).mCancelationSignal;
+            return ((Transport)transport).mCancellationSignal;
         }
         return null;
     }
 
     /**
-     * Listens for cancelation.
+     * Listens for cancellation.
      */
     public interface OnCancelListener {
         /**
-         * Called when {@link CancelationSignal#cancel} is invoked.
+         * Called when {@link CancellationSignal#cancel} is invoked.
          */
         void onCancel();
     }
 
-    private static final class Transport extends ICancelationSignal.Stub {
-        final CancelationSignal mCancelationSignal = new CancelationSignal();
+    private static final class Transport extends ICancellationSignal.Stub {
+        final CancellationSignal mCancellationSignal = new CancellationSignal();
 
         @Override
         public void cancel() throws RemoteException {
-            mCancelationSignal.cancel();
+            mCancellationSignal.cancel();
         }
     }
 }
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index adbeb6a..12e3ccf 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -178,10 +178,10 @@
         @Override
         public Cursor query(Uri uri, String[] projection,
                 String selection, String[] selectionArgs, String sortOrder,
-                ICancelationSignal cancelationSignal) {
+                ICancellationSignal cancellationSignal) {
             enforceReadPermission(uri);
             return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder,
-                    CancelationSignal.fromTransport(cancelationSignal));
+                    CancellationSignal.fromTransport(cancellationSignal));
         }
 
         @Override
@@ -263,8 +263,8 @@
         }
 
         @Override
-        public ICancelationSignal createCancelationSignal() throws RemoteException {
-            return CancelationSignal.createTransport();
+        public ICancellationSignal createCancellationSignal() throws RemoteException {
+            return CancellationSignal.createTransport();
         }
 
         private void enforceReadPermission(Uri uri) {
@@ -557,7 +557,7 @@
             String selection, String[] selectionArgs, String sortOrder);
 
     /**
-     * Implement this to handle query requests from clients with support for cancelation.
+     * Implement this to handle query requests from clients with support for cancellation.
      * This method can be called from multiple threads, as described in
      * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
      * and Threads</a>.
@@ -597,9 +597,9 @@
         return c;</pre>
      * <p>
      * If you implement this method then you must also implement the version of
-     * {@link #query(Uri, String[], String, String[], String)} that does not take a cancelation
-     * provider to ensure correct operation on older versions of the Android Framework in
-     * which the cancelation signal overload was not available.
+     * {@link #query(Uri, String[], String, String[], String)} that does not take a cancellation
+     * signal to ensure correct operation on older versions of the Android Framework in
+     * which the cancellation signal overload was not available.
      *
      * @param uri The URI to query. This will be the full URI sent by the client;
      *      if the client is requesting a specific record, the URI will end in a record number
@@ -614,14 +614,14 @@
      *      The values will be bound as Strings.
      * @param sortOrder How the rows in the cursor should be sorted.
      *      If null then the provider is free to define the sort order.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * If the operation is canceled, then {@link OperationCanceledException} will be thrown
      * when the query is executed.
      * @return a Cursor or null.
      */
     public Cursor query(Uri uri, String[] projection,
             String selection, String[] selectionArgs, String sortOrder,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         return query(uri, projection, selection, selectionArgs, sortOrder);
     }
 
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 9a1fa65..3ac5e07 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -52,15 +52,15 @@
 
     /** See {@link ContentProvider#query ContentProvider.query} */
     public Cursor query(Uri url, String[] projection, String selection,
-            String[] selectionArgs, String sortOrder, CancelationSignal cancelationSignal)
+            String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal)
                     throws RemoteException {
-        ICancelationSignal remoteCancelationSignal = null;
-        if (cancelationSignal != null) {
-            remoteCancelationSignal = mContentProvider.createCancelationSignal();
-            cancelationSignal.setRemote(remoteCancelationSignal);
+        ICancellationSignal remoteCancellationSignal = null;
+        if (cancellationSignal != null) {
+            remoteCancellationSignal = mContentProvider.createCancellationSignal();
+            cancellationSignal.setRemote(remoteCancellationSignal);
         }
         return mContentProvider.query(url, projection, selection,  selectionArgs, sortOrder,
-                remoteCancelationSignal);
+                remoteCancellationSignal);
     }
 
     /** See {@link ContentProvider#getType ContentProvider.getType} */
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index e0e277a..eb83dbc 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -105,11 +105,11 @@
                     String sortOrder = data.readString();
                     IContentObserver observer = IContentObserver.Stub.asInterface(
                             data.readStrongBinder());
-                    ICancelationSignal cancelationSignal = ICancelationSignal.Stub.asInterface(
+                    ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
                             data.readStrongBinder());
 
                     Cursor cursor = query(url, projection, selection, selectionArgs, sortOrder,
-                            cancelationSignal);
+                            cancellationSignal);
                     if (cursor != null) {
                         CursorToBulkCursorAdaptor adaptor = new CursorToBulkCursorAdaptor(
                                 cursor, observer, getProviderName());
@@ -300,9 +300,9 @@
                 {
                     data.enforceInterface(IContentProvider.descriptor);
 
-                    ICancelationSignal cancelationSignal = createCancelationSignal();
+                    ICancellationSignal cancellationSignal = createCancellationSignal();
                     reply.writeNoException();
-                    reply.writeStrongBinder(cancelationSignal.asBinder());
+                    reply.writeStrongBinder(cancellationSignal.asBinder());
                     return true;
                 }
             }
@@ -334,7 +334,7 @@
     }
 
     public Cursor query(Uri url, String[] projection, String selection,
-            String[] selectionArgs, String sortOrder, ICancelationSignal cancelationSignal)
+            String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)
                     throws RemoteException {
         BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
         Parcel data = Parcel.obtain();
@@ -363,7 +363,7 @@
             }
             data.writeString(sortOrder);
             data.writeStrongBinder(adaptor.getObserver().asBinder());
-            data.writeStrongBinder(cancelationSignal != null ? cancelationSignal.asBinder() : null);
+            data.writeStrongBinder(cancellationSignal != null ? cancellationSignal.asBinder() : null);
 
             mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
 
@@ -632,7 +632,7 @@
         }
     }
 
-    public ICancelationSignal createCancelationSignal() throws RemoteException {
+    public ICancellationSignal createCancellationSignal() throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
@@ -642,9 +642,9 @@
                     data, reply, 0);
 
             DatabaseUtils.readExceptionFromParcel(reply);
-            ICancelationSignal cancelationSignal = ICancelationSignal.Stub.asInterface(
+            ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
                     reply.readStrongBinder());
-            return cancelationSignal;
+            return cancellationSignal;
         } finally {
             data.recycle();
             reply.recycle();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index e79475a..96a65da 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -335,7 +335,7 @@
      * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
      *         clause (excluding the ORDER BY itself). Passing null will use the
      *         default sort order, which may be unordered.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * If the operation is canceled, then {@link OperationCanceledException} will be thrown
      * when the query is executed.
      * @return A Cursor object, which is positioned before the first entry, or null
@@ -343,7 +343,7 @@
      */
     public final Cursor query(final Uri uri, String[] projection,
             String selection, String[] selectionArgs, String sortOrder,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         IContentProvider provider = acquireProvider(uri);
         if (provider == null) {
             return null;
@@ -351,14 +351,14 @@
         try {
             long startTime = SystemClock.uptimeMillis();
 
-            ICancelationSignal remoteCancelationSignal = null;
-            if (cancelationSignal != null) {
-                cancelationSignal.throwIfCanceled();
-                remoteCancelationSignal = provider.createCancelationSignal();
-                cancelationSignal.setRemote(remoteCancelationSignal);
+            ICancellationSignal remoteCancellationSignal = null;
+            if (cancellationSignal != null) {
+                cancellationSignal.throwIfCanceled();
+                remoteCancellationSignal = provider.createCancellationSignal();
+                cancellationSignal.setRemote(remoteCancellationSignal);
             }
             Cursor qCursor = provider.query(uri, projection,
-                    selection, selectionArgs, sortOrder, remoteCancelationSignal);
+                    selection, selectionArgs, sortOrder, remoteCancellationSignal);
             if (qCursor == null) {
                 releaseProvider(provider);
                 return null;
diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java
index 6e4aca8..aed3728 100644
--- a/core/java/android/content/CursorLoader.java
+++ b/core/java/android/content/CursorLoader.java
@@ -48,7 +48,7 @@
     String mSortOrder;
 
     Cursor mCursor;
-    CancelationSignal mCancelationSignal;
+    CancellationSignal mCancellationSignal;
 
     /* Runs on a worker thread */
     @Override
@@ -57,11 +57,11 @@
             if (isLoadInBackgroundCanceled()) {
                 throw new OperationCanceledException();
             }
-            mCancelationSignal = new CancelationSignal();
+            mCancellationSignal = new CancellationSignal();
         }
         try {
             Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
-                    mSelectionArgs, mSortOrder, mCancelationSignal);
+                    mSelectionArgs, mSortOrder, mCancellationSignal);
             if (cursor != null) {
                 // Ensure the cursor window is filled
                 cursor.getCount();
@@ -70,18 +70,18 @@
             return cursor;
         } finally {
             synchronized (this) {
-                mCancelationSignal = null;
+                mCancellationSignal = null;
             }
         }
     }
 
     @Override
-    protected void onCancelLoadInBackground() {
-        super.onCancelLoadInBackground();
+    public void cancelLoadInBackground() {
+        super.cancelLoadInBackground();
 
         synchronized (this) {
-            if (mCancelationSignal != null) {
-                mCancelationSignal.cancel();
+            if (mCancellationSignal != null) {
+                mCancellationSignal.cancel();
             }
         }
     }
diff --git a/core/java/android/content/ICancelationSignal.aidl b/core/java/android/content/ICancellationSignal.aidl
similarity index 95%
rename from core/java/android/content/ICancelationSignal.aidl
rename to core/java/android/content/ICancellationSignal.aidl
index 3f5a24d..cf1c5d3 100644
--- a/core/java/android/content/ICancelationSignal.aidl
+++ b/core/java/android/content/ICancellationSignal.aidl
@@ -19,6 +19,6 @@
 /**
  * @hide
  */
-interface ICancelationSignal {
+interface ICancellationSignal {
     oneway void cancel();
 }
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index f52157f..16478b7 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -34,7 +34,7 @@
  */
 public interface IContentProvider extends IInterface {
     public Cursor query(Uri url, String[] projection, String selection,
-            String[] selectionArgs, String sortOrder, ICancelationSignal cancelationSignal)
+            String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)
                     throws RemoteException;
     public String getType(Uri url) throws RemoteException;
     public Uri insert(Uri url, ContentValues initialValues)
@@ -51,7 +51,7 @@
     public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
             throws RemoteException, OperationApplicationException;
     public Bundle call(String method, String arg, Bundle extras) throws RemoteException;
-    public ICancelationSignal createCancelationSignal() throws RemoteException;
+    public ICancellationSignal createCancellationSignal() throws RemoteException;
 
     // Data interchange.
     public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index fbc1b2b..ab62c44 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2957,6 +2957,13 @@
      */
     public static final int FLAG_RECEIVER_REPLACE_PENDING = 0x20000000;
     /**
+     * If set, when sending a broadcast the recipient is allowed to run at
+     * foreground priority, with a shorter timeout interval.  During normal
+     * broadcasts the receivers are not automatically hoisted out of the
+     * background priority class.
+     */
+    public static final int FLAG_RECEIVER_FOREGROUND = 0x10000000;
+    /**
      * If set, when sending a broadcast <i>before boot has completed</i> only
      * registered receivers will be called -- no BroadcastReceiver components
      * will be launched.  Sticky intent state will be recorded properly even
@@ -2969,14 +2976,14 @@
      *
      * @hide
      */
-    public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x10000000;
+    public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x08000000;
     /**
      * Set when this broadcast is for a boot upgrade, a special mode that
      * allows the broadcast to be sent before the system is ready and launches
      * the app process with no providers running in it.
      * @hide
      */
-    public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x08000000;
+    public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x04000000;
 
     /**
      * @hide Flags that can't be changed with PendingIntent.
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index ac05682..3052414 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -52,6 +52,7 @@
 public class Loader<D> {
     int mId;
     OnLoadCompleteListener<D> mListener;
+    OnLoadCanceledListener<D> mOnLoadCanceledListener;
     Context mContext;
     boolean mStarted = false;
     boolean mAbandoned = false;
@@ -100,6 +101,23 @@
     }
 
     /**
+     * Interface that is implemented to discover when a Loader has been canceled
+     * before it finished loading its data.  You do not normally need to implement
+     * this yourself; it is used in the implementation of {@link android.app.LoaderManager}
+     * to find out when a Loader it is managing has been canceled so that it
+     * can schedule the next Loader.  This interface should only be used if a
+     * Loader is not being used in conjunction with LoaderManager.
+     */
+    public interface OnLoadCanceledListener<D> {
+        /**
+         * Called on the thread that created the Loader when the load is canceled.
+         *
+         * @param loader the loader that canceled the load
+         */
+        public void onLoadCanceled(Loader<D> loader);
+    }
+
+    /**
      * Stores away the application context associated with context.
      * Since Loaders can be used across multiple activities it's dangerous to
      * store the context directly; always use {@link #getContext()} to retrieve
@@ -127,6 +145,18 @@
     }
 
     /**
+     * Informs the registered {@link OnLoadCanceledListener} that the load has been canceled.
+     * Should only be called by subclasses.
+     *
+     * Must be called from the process's main thread.
+     */
+    public void deliverCancellation() {
+        if (mOnLoadCanceledListener != null) {
+            mOnLoadCanceledListener.onLoadCanceled(this);
+        }
+    }
+
+    /**
      * @return an application context retrieved from the Context passed to the constructor.
      */
     public Context getContext() {
@@ -171,6 +201,40 @@
     }
 
     /**
+     * Registers a listener that will receive callbacks when a load is canceled.
+     * The callback will be called on the process's main thread so it's safe to
+     * pass the results to widgets.
+     *
+     * Must be called from the process's main thread.
+     *
+     * @param listener The listener to register.
+     */
+    public void registerOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {
+        if (mOnLoadCanceledListener != null) {
+            throw new IllegalStateException("There is already a listener registered");
+        }
+        mOnLoadCanceledListener = listener;
+    }
+
+    /**
+     * Unregisters a listener that was previously added with
+     * {@link #registerOnLoadCanceledListener}.
+     *
+     * Must be called from the process's main thread.
+     *
+     * @param listener The listener to unregister.
+     */
+    public void unregisterOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {
+        if (mOnLoadCanceledListener == null) {
+            throw new IllegalStateException("No listener register");
+        }
+        if (mOnLoadCanceledListener != listener) {
+            throw new IllegalArgumentException("Attempting to unregister the wrong listener");
+        }
+        mOnLoadCanceledListener = null;
+    }
+
+    /**
      * Return whether this load has been started.  That is, its {@link #startLoading()}
      * has been called and no calls to {@link #stopLoading()} or
      * {@link #reset()} have yet been made.
@@ -234,6 +298,43 @@
     }
 
     /**
+     * Attempt to cancel the current load task.
+     * Must be called on the main thread of the process.
+     *
+     * <p>Cancellation is not an immediate operation, since the load is performed
+     * in a background thread.  If there is currently a load in progress, this
+     * method requests that the load be canceled, and notes this is the case;
+     * once the background thread has completed its work its remaining state
+     * will be cleared.  If another load request comes in during this time,
+     * it will be held until the canceled load is complete.
+     *
+     * @return Returns <tt>false</tt> if the task could not be canceled,
+     * typically because it has already completed normally, or
+     * because {@link #startLoading()} hasn't been called; returns
+     * <tt>true</tt> otherwise.  When <tt>true</tt> is returned, the task
+     * is still running and the {@link OnLoadCanceledListener} will be called
+     * when the task completes.
+     */
+    public boolean cancelLoad() {
+        return onCancelLoad();
+    }
+
+    /**
+     * Subclasses must implement this to take care of requests to {@link #cancelLoad()}.
+     * This will always be called from the process's main thread.
+     *
+     * @return Returns <tt>false</tt> if the task could not be canceled,
+     * typically because it has already completed normally, or
+     * because {@link #startLoading()} hasn't been called; returns
+     * <tt>true</tt> otherwise.  When <tt>true</tt> is returned, the task
+     * is still running and the {@link OnLoadCanceledListener} will be called
+     * when the task completes.
+     */
+    protected boolean onCancelLoad() {
+        return false;
+    }
+
+    /**
      * Force an asynchronous load. Unlike {@link #startLoading()} this will ignore a previously
      * loaded data set and load a new one.  This simply calls through to the
      * implementation's {@link #onForceLoad()}.  You generally should only call this
diff --git a/core/java/android/content/OperationCanceledException.java b/core/java/android/content/OperationCanceledException.java
index 24afcfa..d783a07 100644
--- a/core/java/android/content/OperationCanceledException.java
+++ b/core/java/android/content/OperationCanceledException.java
@@ -19,7 +19,7 @@
 /**
  * An exception type that is thrown when an operation in progress is canceled.
  *
- * @see CancelationSignal
+ * @see CancellationSignal
  */
 public class OperationCanceledException extends RuntimeException {
     public OperationCanceledException() {
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 6015668..e04b2f7 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -347,6 +347,7 @@
             sb.append(" (no locale)");
         }
         switch (textLayoutDirection) {
+            case LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE: /* ltr not interesting */ break;
             case LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE: sb.append(" rtl"); break;
             default: sb.append(" layoutdir="); sb.append(textLayoutDirection); break;
         }
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index b69d9bf..0022118 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -21,6 +21,7 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.OperationApplicationException;
+import android.content.OperationCanceledException;
 import android.database.sqlite.SQLiteAbortException;
 import android.database.sqlite.SQLiteConstraintException;
 import android.database.sqlite.SQLiteDatabase;
@@ -107,6 +108,9 @@
             code = 9;
         } else if (e instanceof OperationApplicationException) {
             code = 10;
+        } else if (e instanceof OperationCanceledException) {
+            code = 11;
+            logException = false;
         } else {
             reply.writeException(e);
             Log.e(TAG, "Writing exception to parcel", e);
@@ -178,6 +182,8 @@
                 throw new SQLiteDiskIOException(msg);
             case 9:
                 throw new SQLiteException(msg);
+            case 11:
+                throw new OperationCanceledException(msg);
             default:
                 reply.readException(code, msg);
         }
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 710bd53..b5cef81 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -19,7 +19,7 @@
 import dalvik.system.BlockGuard;
 import dalvik.system.CloseGuard;
 
-import android.content.CancelationSignal;
+import android.content.CancellationSignal;
 import android.content.OperationCanceledException;
 import android.database.Cursor;
 import android.database.CursorWindow;
@@ -84,7 +84,7 @@
  *
  * @hide
  */
-public final class SQLiteConnection implements CancelationSignal.OnCancelListener {
+public final class SQLiteConnection implements CancellationSignal.OnCancelListener {
     private static final String TAG = "SQLiteConnection";
     private static final boolean DEBUG = false;
 
@@ -110,11 +110,11 @@
 
     private boolean mOnlyAllowReadOnlyOperations;
 
-    // The number of times attachCancelationSignal has been called.
+    // The number of times attachCancellationSignal has been called.
     // Because SQLite statement execution can be re-entrant, we keep track of how many
-    // times we have attempted to attach a cancelation signal to the connection so that
+    // times we have attempted to attach a cancellation signal to the connection so that
     // we can ensure that we detach the signal at the right time.
-    private int mCancelationSignalAttachCount;
+    private int mCancellationSignalAttachCount;
 
     private static native int nativeOpen(String path, int openFlags, String label,
             boolean enableTrace, boolean enableProfile);
@@ -355,14 +355,14 @@
      *
      * @param sql The SQL statement to execute.
      * @param bindArgs The arguments to bind, or null if none.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
      * or invalid number of bind arguments.
      * @throws OperationCanceledException if the operation was canceled.
      */
     public void execute(String sql, Object[] bindArgs,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
@@ -374,11 +374,11 @@
                 throwIfStatementForbidden(statement);
                 bindArguments(statement, bindArgs);
                 applyBlockGuardPolicy(statement);
-                attachCancelationSignal(cancelationSignal);
+                attachCancellationSignal(cancellationSignal);
                 try {
                     nativeExecute(mConnectionPtr, statement.mStatementPtr);
                 } finally {
-                    detachCancelationSignal(cancelationSignal);
+                    detachCancellationSignal(cancellationSignal);
                 }
             } finally {
                 releasePreparedStatement(statement);
@@ -396,7 +396,7 @@
      *
      * @param sql The SQL statement to execute.
      * @param bindArgs The arguments to bind, or null if none.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The value of the first column in the first row of the result set
      * as a <code>long</code>, or zero if none.
      *
@@ -405,7 +405,7 @@
      * @throws OperationCanceledException if the operation was canceled.
      */
     public long executeForLong(String sql, Object[] bindArgs,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
@@ -417,11 +417,11 @@
                 throwIfStatementForbidden(statement);
                 bindArguments(statement, bindArgs);
                 applyBlockGuardPolicy(statement);
-                attachCancelationSignal(cancelationSignal);
+                attachCancellationSignal(cancellationSignal);
                 try {
                     return nativeExecuteForLong(mConnectionPtr, statement.mStatementPtr);
                 } finally {
-                    detachCancelationSignal(cancelationSignal);
+                    detachCancellationSignal(cancellationSignal);
                 }
             } finally {
                 releasePreparedStatement(statement);
@@ -439,7 +439,7 @@
      *
      * @param sql The SQL statement to execute.
      * @param bindArgs The arguments to bind, or null if none.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The value of the first column in the first row of the result set
      * as a <code>String</code>, or null if none.
      *
@@ -448,7 +448,7 @@
      * @throws OperationCanceledException if the operation was canceled.
      */
     public String executeForString(String sql, Object[] bindArgs,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
@@ -460,11 +460,11 @@
                 throwIfStatementForbidden(statement);
                 bindArguments(statement, bindArgs);
                 applyBlockGuardPolicy(statement);
-                attachCancelationSignal(cancelationSignal);
+                attachCancellationSignal(cancellationSignal);
                 try {
                     return nativeExecuteForString(mConnectionPtr, statement.mStatementPtr);
                 } finally {
-                    detachCancelationSignal(cancelationSignal);
+                    detachCancellationSignal(cancellationSignal);
                 }
             } finally {
                 releasePreparedStatement(statement);
@@ -483,7 +483,7 @@
      *
      * @param sql The SQL statement to execute.
      * @param bindArgs The arguments to bind, or null if none.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The file descriptor for a shared memory region that contains
      * the value of the first column in the first row of the result set as a BLOB,
      * or null if none.
@@ -493,7 +493,7 @@
      * @throws OperationCanceledException if the operation was canceled.
      */
     public ParcelFileDescriptor executeForBlobFileDescriptor(String sql, Object[] bindArgs,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
@@ -506,13 +506,13 @@
                 throwIfStatementForbidden(statement);
                 bindArguments(statement, bindArgs);
                 applyBlockGuardPolicy(statement);
-                attachCancelationSignal(cancelationSignal);
+                attachCancellationSignal(cancellationSignal);
                 try {
                     int fd = nativeExecuteForBlobFileDescriptor(
                             mConnectionPtr, statement.mStatementPtr);
                     return fd >= 0 ? ParcelFileDescriptor.adoptFd(fd) : null;
                 } finally {
-                    detachCancelationSignal(cancelationSignal);
+                    detachCancellationSignal(cancellationSignal);
                 }
             } finally {
                 releasePreparedStatement(statement);
@@ -531,7 +531,7 @@
      *
      * @param sql The SQL statement to execute.
      * @param bindArgs The arguments to bind, or null if none.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The number of rows that were changed.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
@@ -539,7 +539,7 @@
      * @throws OperationCanceledException if the operation was canceled.
      */
     public int executeForChangedRowCount(String sql, Object[] bindArgs,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
@@ -552,12 +552,12 @@
                 throwIfStatementForbidden(statement);
                 bindArguments(statement, bindArgs);
                 applyBlockGuardPolicy(statement);
-                attachCancelationSignal(cancelationSignal);
+                attachCancellationSignal(cancellationSignal);
                 try {
                     return nativeExecuteForChangedRowCount(
                             mConnectionPtr, statement.mStatementPtr);
                 } finally {
-                    detachCancelationSignal(cancelationSignal);
+                    detachCancellationSignal(cancellationSignal);
                 }
             } finally {
                 releasePreparedStatement(statement);
@@ -576,7 +576,7 @@
      *
      * @param sql The SQL statement to execute.
      * @param bindArgs The arguments to bind, or null if none.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The row id of the last row that was inserted, or 0 if none.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
@@ -584,7 +584,7 @@
      * @throws OperationCanceledException if the operation was canceled.
      */
     public long executeForLastInsertedRowId(String sql, Object[] bindArgs,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
@@ -597,12 +597,12 @@
                 throwIfStatementForbidden(statement);
                 bindArguments(statement, bindArgs);
                 applyBlockGuardPolicy(statement);
-                attachCancelationSignal(cancelationSignal);
+                attachCancellationSignal(cancellationSignal);
                 try {
                     return nativeExecuteForLastInsertedRowId(
                             mConnectionPtr, statement.mStatementPtr);
                 } finally {
-                    detachCancelationSignal(cancelationSignal);
+                    detachCancellationSignal(cancellationSignal);
                 }
             } finally {
                 releasePreparedStatement(statement);
@@ -629,7 +629,7 @@
      * so that it does.  Must be greater than or equal to <code>startPos</code>.
      * @param countAllRows True to count all rows that the query would return
      * regagless of whether they fit in the window.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The number of rows that were counted during query execution.  Might
      * not be all rows in the result set unless <code>countAllRows</code> is true.
      *
@@ -639,7 +639,7 @@
      */
     public int executeForCursorWindow(String sql, Object[] bindArgs,
             CursorWindow window, int startPos, int requiredPos, boolean countAllRows,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
@@ -658,7 +658,7 @@
                 throwIfStatementForbidden(statement);
                 bindArguments(statement, bindArgs);
                 applyBlockGuardPolicy(statement);
-                attachCancelationSignal(cancelationSignal);
+                attachCancellationSignal(cancellationSignal);
                 try {
                     final long result = nativeExecuteForCursorWindow(
                             mConnectionPtr, statement.mStatementPtr, window.mWindowPtr,
@@ -669,7 +669,7 @@
                     window.setStartPosition(actualPos);
                     return countedRows;
                 } finally {
-                    detachCancelationSignal(cancelationSignal);
+                    detachCancellationSignal(cancellationSignal);
                 }
             } finally {
                 releasePreparedStatement(statement);
@@ -751,40 +751,40 @@
         recyclePreparedStatement(statement);
     }
 
-    private void attachCancelationSignal(CancelationSignal cancelationSignal) {
-        if (cancelationSignal != null) {
-            cancelationSignal.throwIfCanceled();
+    private void attachCancellationSignal(CancellationSignal cancellationSignal) {
+        if (cancellationSignal != null) {
+            cancellationSignal.throwIfCanceled();
 
-            mCancelationSignalAttachCount += 1;
-            if (mCancelationSignalAttachCount == 1) {
-                // Reset cancelation flag before executing the statement.
+            mCancellationSignalAttachCount += 1;
+            if (mCancellationSignalAttachCount == 1) {
+                // Reset cancellation flag before executing the statement.
                 nativeResetCancel(mConnectionPtr, true /*cancelable*/);
 
                 // After this point, onCancel() may be called concurrently.
-                cancelationSignal.setOnCancelListener(this);
+                cancellationSignal.setOnCancelListener(this);
             }
         }
     }
 
-    private void detachCancelationSignal(CancelationSignal cancelationSignal) {
-        if (cancelationSignal != null) {
-            assert mCancelationSignalAttachCount > 0;
+    private void detachCancellationSignal(CancellationSignal cancellationSignal) {
+        if (cancellationSignal != null) {
+            assert mCancellationSignalAttachCount > 0;
 
-            mCancelationSignalAttachCount -= 1;
-            if (mCancelationSignalAttachCount == 0) {
+            mCancellationSignalAttachCount -= 1;
+            if (mCancellationSignalAttachCount == 0) {
                 // After this point, onCancel() cannot be called concurrently.
-                cancelationSignal.setOnCancelListener(null);
+                cancellationSignal.setOnCancelListener(null);
 
-                // Reset cancelation flag after executing the statement.
+                // Reset cancellation flag after executing the statement.
                 nativeResetCancel(mConnectionPtr, false /*cancelable*/);
             }
         }
     }
 
-    // CancelationSignal.OnCancelationListener callback.
+    // CancellationSignal.OnCancelListener callback.
     // This method may be called on a different thread than the executing statement.
-    // However, it will only be called between calls to attachCancelationSignal and
-    // detachCancelationSignal, while a statement is executing.  We can safely assume
+    // However, it will only be called between calls to attachCancellationSignal and
+    // detachCancellationSignal, while a statement is executing.  We can safely assume
     // that the SQLite connection is still alive.
     @Override
     public void onCancel() {
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index d335738..236948e 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -18,7 +18,7 @@
 
 import dalvik.system.CloseGuard;
 
-import android.content.CancelationSignal;
+import android.content.CancellationSignal;
 import android.content.OperationCanceledException;
 import android.database.sqlite.SQLiteDebug.DbStats;
 import android.os.SystemClock;
@@ -284,7 +284,7 @@
      * @param sql If not null, try to find a connection that already has
      * the specified SQL statement in its prepared statement cache.
      * @param connectionFlags The connection request flags.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The connection that was acquired, never null.
      *
      * @throws IllegalStateException if the pool has been closed.
@@ -292,8 +292,8 @@
      * @throws OperationCanceledException if the operation was canceled.
      */
     public SQLiteConnection acquireConnection(String sql, int connectionFlags,
-            CancelationSignal cancelationSignal) {
-        return waitForConnection(sql, connectionFlags, cancelationSignal);
+            CancellationSignal cancellationSignal) {
+        return waitForConnection(sql, connectionFlags, cancellationSignal);
     }
 
     /**
@@ -503,7 +503,7 @@
 
     // Might throw.
     private SQLiteConnection waitForConnection(String sql, int connectionFlags,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         final boolean wantPrimaryConnection =
                 (connectionFlags & CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY) != 0;
 
@@ -512,8 +512,8 @@
             throwIfClosedLocked();
 
             // Abort if canceled.
-            if (cancelationSignal != null) {
-                cancelationSignal.throwIfCanceled();
+            if (cancellationSignal != null) {
+                cancellationSignal.throwIfCanceled();
             }
 
             // Try to acquire a connection.
@@ -550,9 +550,9 @@
                 mConnectionWaiterQueue = waiter;
             }
 
-            if (cancelationSignal != null) {
+            if (cancellationSignal != null) {
                 final int nonce = waiter.mNonce;
-                cancelationSignal.setOnCancelListener(new CancelationSignal.OnCancelListener() {
+                cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
                     @Override
                     public void onCancel() {
                         synchronized (mLock) {
@@ -588,8 +588,8 @@
                 final SQLiteConnection connection = waiter.mAssignedConnection;
                 final RuntimeException ex = waiter.mException;
                 if (connection != null || ex != null) {
-                    if (cancelationSignal != null) {
-                        cancelationSignal.setOnCancelListener(null);
+                    if (cancellationSignal != null) {
+                        cancellationSignal.setOnCancelListener(null);
                     }
                     recycleConnectionWaiterLocked(waiter);
                     if (connection != null) {
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 7db7bfb..505f83e 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -16,7 +16,7 @@
 
 package android.database.sqlite;
 
-import android.content.CancelationSignal;
+import android.content.CancellationSignal;
 import android.content.ContentValues;
 import android.content.OperationCanceledException;
 import android.content.res.Resources;
@@ -967,7 +967,7 @@
      *            default sort order, which may be unordered.
      * @param limit Limits the number of rows returned by the query,
      *            formatted as LIMIT clause. Passing null denotes no LIMIT clause.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * If the operation is canceled, then {@link OperationCanceledException} will be thrown
      * when the query is executed.
      * @return A {@link Cursor} object, which is positioned before the first entry. Note that
@@ -976,9 +976,9 @@
      */
     public Cursor query(boolean distinct, String table, String[] columns,
             String selection, String[] selectionArgs, String groupBy,
-            String having, String orderBy, String limit, CancelationSignal cancelationSignal) {
+            String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
         return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
-                groupBy, having, orderBy, limit, cancelationSignal);
+                groupBy, having, orderBy, limit, cancellationSignal);
     }
 
     /**
@@ -1049,7 +1049,7 @@
      *            default sort order, which may be unordered.
      * @param limit Limits the number of rows returned by the query,
      *            formatted as LIMIT clause. Passing null denotes no LIMIT clause.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * If the operation is canceled, then {@link OperationCanceledException} will be thrown
      * when the query is executed.
      * @return A {@link Cursor} object, which is positioned before the first entry. Note that
@@ -1059,13 +1059,13 @@
     public Cursor queryWithFactory(CursorFactory cursorFactory,
             boolean distinct, String table, String[] columns,
             String selection, String[] selectionArgs, String groupBy,
-            String having, String orderBy, String limit, CancelationSignal cancelationSignal) {
+            String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
         throwIfNotOpen(); // fail fast
         String sql = SQLiteQueryBuilder.buildQueryString(
                 distinct, table, columns, selection, groupBy, having, orderBy, limit);
 
         return rawQueryWithFactory(cursorFactory, sql, selectionArgs,
-                findEditTable(table), cancelationSignal);
+                findEditTable(table), cancellationSignal);
     }
 
     /**
@@ -1163,15 +1163,15 @@
      * @param selectionArgs You may include ?s in where clause in the query,
      *     which will be replaced by the values from selectionArgs. The
      *     values will be bound as Strings.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * If the operation is canceled, then {@link OperationCanceledException} will be thrown
      * when the query is executed.
      * @return A {@link Cursor} object, which is positioned before the first entry. Note that
      * {@link Cursor}s are not synchronized, see the documentation for more details.
      */
     public Cursor rawQuery(String sql, String[] selectionArgs,
-            CancelationSignal cancelationSignal) {
-        return rawQueryWithFactory(null, sql, selectionArgs, null, cancelationSignal);
+            CancellationSignal cancellationSignal) {
+        return rawQueryWithFactory(null, sql, selectionArgs, null, cancellationSignal);
     }
 
     /**
@@ -1201,7 +1201,7 @@
      *     which will be replaced by the values from selectionArgs. The
      *     values will be bound as Strings.
      * @param editTable the name of the first table, which is editable
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * If the operation is canceled, then {@link OperationCanceledException} will be thrown
      * when the query is executed.
      * @return A {@link Cursor} object, which is positioned before the first entry. Note that
@@ -1209,11 +1209,11 @@
      */
     public Cursor rawQueryWithFactory(
             CursorFactory cursorFactory, String sql, String[] selectionArgs,
-            String editTable, CancelationSignal cancelationSignal) {
+            String editTable, CancellationSignal cancellationSignal) {
         throwIfNotOpen(); // fail fast
 
         SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable,
-                cancelationSignal);
+                cancellationSignal);
         return driver.query(cursorFactory != null ? cursorFactory : mCursorFactory,
                 selectionArgs);
     }
diff --git a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
index c490dc6..3375e74 100644
--- a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
+++ b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
@@ -16,7 +16,7 @@
 
 package android.database.sqlite;
 
-import android.content.CancelationSignal;
+import android.content.CancellationSignal;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 
@@ -29,19 +29,19 @@
     private final SQLiteDatabase mDatabase;
     private final String mEditTable; 
     private final String mSql;
-    private final CancelationSignal mCancelationSignal;
+    private final CancellationSignal mCancellationSignal;
     private SQLiteQuery mQuery;
 
     public SQLiteDirectCursorDriver(SQLiteDatabase db, String sql, String editTable,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         mDatabase = db;
         mEditTable = editTable;
         mSql = sql;
-        mCancelationSignal = cancelationSignal;
+        mCancellationSignal = cancellationSignal;
     }
 
     public Cursor query(CursorFactory factory, String[] selectionArgs) {
-        final SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, mCancelationSignal);
+        final SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, mCancellationSignal);
         final Cursor cursor;
         try {
             query.bindAllArgsAsStrings(selectionArgs);
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index f3da2a6..9f0edfb 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -16,7 +16,7 @@
 
 package android.database.sqlite;
 
-import android.content.CancelationSignal;
+import android.content.CancellationSignal;
 import android.database.DatabaseUtils;
 
 import java.util.Arrays;
@@ -38,7 +38,7 @@
     private final Object[] mBindArgs;
 
     SQLiteProgram(SQLiteDatabase db, String sql, Object[] bindArgs,
-            CancelationSignal cancelationSignalForPrepare) {
+            CancellationSignal cancellationSignalForPrepare) {
         mDatabase = db;
         mSql = sql.trim();
 
@@ -57,7 +57,7 @@
                 SQLiteStatementInfo info = new SQLiteStatementInfo();
                 db.getThreadSession().prepare(mSql,
                         db.getThreadDefaultConnectionFlags(assumeReadOnly),
-                        cancelationSignalForPrepare, info);
+                        cancellationSignalForPrepare, info);
                 mReadOnly = info.readOnly;
                 mColumnNames = info.columnNames;
                 mNumParameters = info.numParameters;
diff --git a/core/java/android/database/sqlite/SQLiteQuery.java b/core/java/android/database/sqlite/SQLiteQuery.java
index df2e260..30e77b5 100644
--- a/core/java/android/database/sqlite/SQLiteQuery.java
+++ b/core/java/android/database/sqlite/SQLiteQuery.java
@@ -16,7 +16,7 @@
 
 package android.database.sqlite;
 
-import android.content.CancelationSignal;
+import android.content.CancellationSignal;
 import android.content.OperationCanceledException;
 import android.database.CursorWindow;
 import android.util.Log;
@@ -31,12 +31,12 @@
 public final class SQLiteQuery extends SQLiteProgram {
     private static final String TAG = "SQLiteQuery";
 
-    private final CancelationSignal mCancelationSignal;
+    private final CancellationSignal mCancellationSignal;
 
-    SQLiteQuery(SQLiteDatabase db, String query, CancelationSignal cancelationSignal) {
-        super(db, query, null, cancelationSignal);
+    SQLiteQuery(SQLiteDatabase db, String query, CancellationSignal cancellationSignal) {
+        super(db, query, null, cancellationSignal);
 
-        mCancelationSignal = cancelationSignal;
+        mCancellationSignal = cancellationSignal;
     }
 
     /**
@@ -61,7 +61,7 @@
             try {
                 int numRows = getSession().executeForCursorWindow(getSql(), getBindArgs(),
                         window, startPos, requiredPos, countAllRows, getConnectionFlags(),
-                        mCancelationSignal);
+                        mCancellationSignal);
                 return numRows;
             } catch (SQLiteDatabaseCorruptException ex) {
                 onCorruption();
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index 89469cb..6f84b5e 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -16,7 +16,7 @@
 
 package android.database.sqlite;
 
-import android.content.CancelationSignal;
+import android.content.CancellationSignal;
 import android.content.OperationCanceledException;
 import android.database.Cursor;
 import android.database.DatabaseUtils;
@@ -292,7 +292,7 @@
             String selection, String[] selectionArgs, String groupBy,
             String having, String sortOrder) {
         return query(db, projectionIn, selection, selectionArgs, groupBy, having, sortOrder,
-                null /* limit */, null /* cancelationSignal */);
+                null /* limit */, null /* cancellationSignal */);
     }
 
     /**
@@ -362,7 +362,7 @@
      *   will use the default sort order, which may be unordered.
      * @param limit Limits the number of rows returned by the query,
      *   formatted as LIMIT clause. Passing null denotes no LIMIT clause.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * If the operation is canceled, then {@link OperationCanceledException} will be thrown
      * when the query is executed.
      * @return a cursor over the result set
@@ -371,7 +371,7 @@
      */
     public Cursor query(SQLiteDatabase db, String[] projectionIn,
             String selection, String[] selectionArgs, String groupBy,
-            String having, String sortOrder, String limit, CancelationSignal cancelationSignal) {
+            String having, String sortOrder, String limit, CancellationSignal cancellationSignal) {
         if (mTables == null) {
             return null;
         }
@@ -387,7 +387,7 @@
             String sqlForValidation = buildQuery(projectionIn, "(" + selection + ")", groupBy,
                     having, sortOrder, limit);
             validateQuerySql(db, sqlForValidation,
-                    cancelationSignal); // will throw if query is invalid
+                    cancellationSignal); // will throw if query is invalid
         }
 
         String sql = buildQuery(
@@ -400,7 +400,7 @@
         return db.rawQueryWithFactory(
                 mFactory, sql, selectionArgs,
                 SQLiteDatabase.findEditTable(mTables),
-                cancelationSignal); // will throw if query is invalid
+                cancellationSignal); // will throw if query is invalid
     }
 
     /**
@@ -408,9 +408,9 @@
      * If the SQL statement is not valid, this method will throw a {@link SQLiteException}.
      */
     private void validateQuerySql(SQLiteDatabase db, String sql,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         db.getThreadSession().prepare(sql,
-                db.getThreadDefaultConnectionFlags(true /*readOnly*/), cancelationSignal, null);
+                db.getThreadDefaultConnectionFlags(true /*readOnly*/), cancellationSignal, null);
     }
 
     /**
diff --git a/core/java/android/database/sqlite/SQLiteSession.java b/core/java/android/database/sqlite/SQLiteSession.java
index b5a3e31..43efb03 100644
--- a/core/java/android/database/sqlite/SQLiteSession.java
+++ b/core/java/android/database/sqlite/SQLiteSession.java
@@ -16,7 +16,7 @@
 
 package android.database.sqlite;
 
-import android.content.CancelationSignal;
+import android.content.CancellationSignal;
 import android.content.OperationCanceledException;
 import android.database.CursorWindow;
 import android.database.DatabaseUtils;
@@ -280,7 +280,7 @@
      * @param transactionListener The transaction listener, or null if none.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      *
      * @throws IllegalStateException if {@link #setTransactionSuccessful} has already been
      * called for the current transaction.
@@ -293,21 +293,21 @@
      */
     public void beginTransaction(int transactionMode,
             SQLiteTransactionListener transactionListener, int connectionFlags,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         throwIfTransactionMarkedSuccessful();
         beginTransactionUnchecked(transactionMode, transactionListener, connectionFlags,
-                cancelationSignal);
+                cancellationSignal);
     }
 
     private void beginTransactionUnchecked(int transactionMode,
             SQLiteTransactionListener transactionListener, int connectionFlags,
-            CancelationSignal cancelationSignal) {
-        if (cancelationSignal != null) {
-            cancelationSignal.throwIfCanceled();
+            CancellationSignal cancellationSignal) {
+        if (cancellationSignal != null) {
+            cancellationSignal.throwIfCanceled();
         }
 
         if (mTransactionStack == null) {
-            acquireConnection(null, connectionFlags, cancelationSignal); // might throw
+            acquireConnection(null, connectionFlags, cancellationSignal); // might throw
         }
         try {
             // Set up the transaction such that we can back out safely
@@ -317,14 +317,14 @@
                 switch (transactionMode) {
                     case TRANSACTION_MODE_IMMEDIATE:
                         mConnection.execute("BEGIN IMMEDIATE;", null,
-                                cancelationSignal); // might throw
+                                cancellationSignal); // might throw
                         break;
                     case TRANSACTION_MODE_EXCLUSIVE:
                         mConnection.execute("BEGIN EXCLUSIVE;", null,
-                                cancelationSignal); // might throw
+                                cancellationSignal); // might throw
                         break;
                     default:
-                        mConnection.execute("BEGIN;", null, cancelationSignal); // might throw
+                        mConnection.execute("BEGIN;", null, cancellationSignal); // might throw
                         break;
                 }
             }
@@ -335,7 +335,7 @@
                     transactionListener.onBegin(); // might throw
                 } catch (RuntimeException ex) {
                     if (mTransactionStack == null) {
-                        mConnection.execute("ROLLBACK;", null, cancelationSignal); // might throw
+                        mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
                     }
                     throw ex;
                 }
@@ -384,7 +384,7 @@
      * This method must be called exactly once for each call to {@link #beginTransaction}.
      * </p>
      *
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      *
      * @throws IllegalStateException if there is no current transaction.
      * @throws SQLiteException if an error occurs.
@@ -394,16 +394,16 @@
      * @see #setTransactionSuccessful
      * @see #yieldTransaction
      */
-    public void endTransaction(CancelationSignal cancelationSignal) {
+    public void endTransaction(CancellationSignal cancellationSignal) {
         throwIfNoTransaction();
         assert mConnection != null;
 
-        endTransactionUnchecked(cancelationSignal);
+        endTransactionUnchecked(cancellationSignal);
     }
 
-    private void endTransactionUnchecked(CancelationSignal cancelationSignal) {
-        if (cancelationSignal != null) {
-            cancelationSignal.throwIfCanceled();
+    private void endTransactionUnchecked(CancellationSignal cancellationSignal) {
+        if (cancellationSignal != null) {
+            cancellationSignal.throwIfCanceled();
         }
 
         final Transaction top = mTransactionStack;
@@ -434,9 +434,9 @@
         } else {
             try {
                 if (successful) {
-                    mConnection.execute("COMMIT;", null, cancelationSignal); // might throw
+                    mConnection.execute("COMMIT;", null, cancellationSignal); // might throw
                 } else {
-                    mConnection.execute("ROLLBACK;", null, cancelationSignal); // might throw
+                    mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
                 }
             } finally {
                 releaseConnection(); // might throw
@@ -487,7 +487,7 @@
      * @param throwIfUnsafe If true, then instead of returning false when no
      * transaction is in progress, a nested transaction is in progress, or when
      * the transaction has already been marked successful, throws {@link IllegalStateException}.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return True if the transaction was actually yielded.
      *
      * @throws IllegalStateException if <code>throwIfNested</code> is true and
@@ -500,7 +500,7 @@
      * @see #endTransaction
      */
     public boolean yieldTransaction(long sleepAfterYieldDelayMillis, boolean throwIfUnsafe,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         if (throwIfUnsafe) {
             throwIfNoTransaction();
             throwIfTransactionMarkedSuccessful();
@@ -518,13 +518,13 @@
         }
 
         return yieldTransactionUnchecked(sleepAfterYieldDelayMillis,
-                cancelationSignal); // might throw
+                cancellationSignal); // might throw
     }
 
     private boolean yieldTransactionUnchecked(long sleepAfterYieldDelayMillis,
-            CancelationSignal cancelationSignal) {
-        if (cancelationSignal != null) {
-            cancelationSignal.throwIfCanceled();
+            CancellationSignal cancellationSignal) {
+        if (cancellationSignal != null) {
+            cancellationSignal.throwIfCanceled();
         }
 
         if (!mConnectionPool.shouldYieldConnection(mConnection, mConnectionFlags)) {
@@ -534,7 +534,7 @@
         final int transactionMode = mTransactionStack.mMode;
         final SQLiteTransactionListener listener = mTransactionStack.mListener;
         final int connectionFlags = mConnectionFlags;
-        endTransactionUnchecked(cancelationSignal); // might throw
+        endTransactionUnchecked(cancellationSignal); // might throw
 
         if (sleepAfterYieldDelayMillis > 0) {
             try {
@@ -545,7 +545,7 @@
         }
 
         beginTransactionUnchecked(transactionMode, listener, connectionFlags,
-                cancelationSignal); // might throw
+                cancellationSignal); // might throw
         return true;
     }
 
@@ -566,24 +566,24 @@
      * @param sql The SQL statement to prepare.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @param outStatementInfo The {@link SQLiteStatementInfo} object to populate
      * with information about the statement, or null if none.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error.
      * @throws OperationCanceledException if the operation was canceled.
      */
-    public void prepare(String sql, int connectionFlags, CancelationSignal cancelationSignal,
+    public void prepare(String sql, int connectionFlags, CancellationSignal cancellationSignal,
             SQLiteStatementInfo outStatementInfo) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
 
-        if (cancelationSignal != null) {
-            cancelationSignal.throwIfCanceled();
+        if (cancellationSignal != null) {
+            cancellationSignal.throwIfCanceled();
         }
 
-        acquireConnection(sql, connectionFlags, cancelationSignal); // might throw
+        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
         try {
             mConnection.prepare(sql, outStatementInfo); // might throw
         } finally {
@@ -598,25 +598,25 @@
      * @param bindArgs The arguments to bind, or null if none.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
      * or invalid number of bind arguments.
      * @throws OperationCanceledException if the operation was canceled.
      */
     public void execute(String sql, Object[] bindArgs, int connectionFlags,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
 
-        if (executeSpecial(sql, bindArgs, connectionFlags, cancelationSignal)) {
+        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
             return;
         }
 
-        acquireConnection(sql, connectionFlags, cancelationSignal); // might throw
+        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
         try {
-            mConnection.execute(sql, bindArgs, cancelationSignal); // might throw
+            mConnection.execute(sql, bindArgs, cancellationSignal); // might throw
         } finally {
             releaseConnection(); // might throw
         }
@@ -629,7 +629,7 @@
      * @param bindArgs The arguments to bind, or null if none.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The value of the first column in the first row of the result set
      * as a <code>long</code>, or zero if none.
      *
@@ -638,18 +638,18 @@
      * @throws OperationCanceledException if the operation was canceled.
      */
     public long executeForLong(String sql, Object[] bindArgs, int connectionFlags,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
 
-        if (executeSpecial(sql, bindArgs, connectionFlags, cancelationSignal)) {
+        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
             return 0;
         }
 
-        acquireConnection(sql, connectionFlags, cancelationSignal); // might throw
+        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
         try {
-            return mConnection.executeForLong(sql, bindArgs, cancelationSignal); // might throw
+            return mConnection.executeForLong(sql, bindArgs, cancellationSignal); // might throw
         } finally {
             releaseConnection(); // might throw
         }
@@ -662,7 +662,7 @@
      * @param bindArgs The arguments to bind, or null if none.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The value of the first column in the first row of the result set
      * as a <code>String</code>, or null if none.
      *
@@ -671,18 +671,18 @@
      * @throws OperationCanceledException if the operation was canceled.
      */
     public String executeForString(String sql, Object[] bindArgs, int connectionFlags,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
 
-        if (executeSpecial(sql, bindArgs, connectionFlags, cancelationSignal)) {
+        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
             return null;
         }
 
-        acquireConnection(sql, connectionFlags, cancelationSignal); // might throw
+        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
         try {
-            return mConnection.executeForString(sql, bindArgs, cancelationSignal); // might throw
+            return mConnection.executeForString(sql, bindArgs, cancellationSignal); // might throw
         } finally {
             releaseConnection(); // might throw
         }
@@ -696,7 +696,7 @@
      * @param bindArgs The arguments to bind, or null if none.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The file descriptor for a shared memory region that contains
      * the value of the first column in the first row of the result set as a BLOB,
      * or null if none.
@@ -706,19 +706,19 @@
      * @throws OperationCanceledException if the operation was canceled.
      */
     public ParcelFileDescriptor executeForBlobFileDescriptor(String sql, Object[] bindArgs,
-            int connectionFlags, CancelationSignal cancelationSignal) {
+            int connectionFlags, CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
 
-        if (executeSpecial(sql, bindArgs, connectionFlags, cancelationSignal)) {
+        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
             return null;
         }
 
-        acquireConnection(sql, connectionFlags, cancelationSignal); // might throw
+        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
         try {
             return mConnection.executeForBlobFileDescriptor(sql, bindArgs,
-                    cancelationSignal); // might throw
+                    cancellationSignal); // might throw
         } finally {
             releaseConnection(); // might throw
         }
@@ -732,7 +732,7 @@
      * @param bindArgs The arguments to bind, or null if none.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The number of rows that were changed.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
@@ -740,19 +740,19 @@
      * @throws OperationCanceledException if the operation was canceled.
      */
     public int executeForChangedRowCount(String sql, Object[] bindArgs, int connectionFlags,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
 
-        if (executeSpecial(sql, bindArgs, connectionFlags, cancelationSignal)) {
+        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
             return 0;
         }
 
-        acquireConnection(sql, connectionFlags, cancelationSignal); // might throw
+        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
         try {
             return mConnection.executeForChangedRowCount(sql, bindArgs,
-                    cancelationSignal); // might throw
+                    cancellationSignal); // might throw
         } finally {
             releaseConnection(); // might throw
         }
@@ -766,7 +766,7 @@
      * @param bindArgs The arguments to bind, or null if none.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The row id of the last row that was inserted, or 0 if none.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
@@ -774,19 +774,19 @@
      * @throws OperationCanceledException if the operation was canceled.
      */
     public long executeForLastInsertedRowId(String sql, Object[] bindArgs, int connectionFlags,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
 
-        if (executeSpecial(sql, bindArgs, connectionFlags, cancelationSignal)) {
+        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
             return 0;
         }
 
-        acquireConnection(sql, connectionFlags, cancelationSignal); // might throw
+        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
         try {
             return mConnection.executeForLastInsertedRowId(sql, bindArgs,
-                    cancelationSignal); // might throw
+                    cancellationSignal); // might throw
         } finally {
             releaseConnection(); // might throw
         }
@@ -808,7 +808,7 @@
      * regagless of whether they fit in the window.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The number of rows that were counted during query execution.  Might
      * not be all rows in the result set unless <code>countAllRows</code> is true.
      *
@@ -818,7 +818,7 @@
      */
     public int executeForCursorWindow(String sql, Object[] bindArgs,
             CursorWindow window, int startPos, int requiredPos, boolean countAllRows,
-            int connectionFlags, CancelationSignal cancelationSignal) {
+            int connectionFlags, CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
@@ -826,16 +826,16 @@
             throw new IllegalArgumentException("window must not be null.");
         }
 
-        if (executeSpecial(sql, bindArgs, connectionFlags, cancelationSignal)) {
+        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
             window.clear();
             return 0;
         }
 
-        acquireConnection(sql, connectionFlags, cancelationSignal); // might throw
+        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
         try {
             return mConnection.executeForCursorWindow(sql, bindArgs,
                     window, startPos, requiredPos, countAllRows,
-                    cancelationSignal); // might throw
+                    cancellationSignal); // might throw
         } finally {
             releaseConnection(); // might throw
         }
@@ -854,7 +854,7 @@
      * @param bindArgs The arguments to bind, or null if none.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
-     * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return True if the statement was of a special form that was handled here,
      * false otherwise.
      *
@@ -863,36 +863,36 @@
      * @throws OperationCanceledException if the operation was canceled.
      */
     private boolean executeSpecial(String sql, Object[] bindArgs, int connectionFlags,
-            CancelationSignal cancelationSignal) {
-        if (cancelationSignal != null) {
-            cancelationSignal.throwIfCanceled();
+            CancellationSignal cancellationSignal) {
+        if (cancellationSignal != null) {
+            cancellationSignal.throwIfCanceled();
         }
 
         final int type = DatabaseUtils.getSqlStatementType(sql);
         switch (type) {
             case DatabaseUtils.STATEMENT_BEGIN:
                 beginTransaction(TRANSACTION_MODE_EXCLUSIVE, null, connectionFlags,
-                        cancelationSignal);
+                        cancellationSignal);
                 return true;
 
             case DatabaseUtils.STATEMENT_COMMIT:
                 setTransactionSuccessful();
-                endTransaction(cancelationSignal);
+                endTransaction(cancellationSignal);
                 return true;
 
             case DatabaseUtils.STATEMENT_ABORT:
-                endTransaction(cancelationSignal);
+                endTransaction(cancellationSignal);
                 return true;
         }
         return false;
     }
 
     private void acquireConnection(String sql, int connectionFlags,
-            CancelationSignal cancelationSignal) {
+            CancellationSignal cancellationSignal) {
         if (mConnection == null) {
             assert mConnectionUseCount == 0;
             mConnection = mConnectionPool.acquireConnection(sql, connectionFlags,
-                    cancelationSignal); // might throw
+                    cancellationSignal); // might throw
             mConnectionFlags = connectionFlags;
         }
         mConnectionUseCount += 1;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a569317..2eef8f4 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -142,8 +142,19 @@
      * If an application uses the network in the background, it should listen
      * for this broadcast and stop using the background data if the value is
      * {@code false}.
+     * <p>
+     *
+     * @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH}, availability
+     *             of background data depends on several combined factors, and
+     *             this broadcast is no longer sent. Instead, when background
+     *             data is unavailable, {@link #getActiveNetworkInfo()} will now
+     *             appear disconnected. During first boot after a platform
+     *             upgrade, this broadcast will be sent once if
+     *             {@link #getBackgroundDataSetting()} was {@code false} before
+     *             the upgrade.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @Deprecated
     public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED =
             "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
 
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 633c38e0..442535a 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -43,7 +43,7 @@
     NetworkPolicy[] getNetworkPolicies();
 
     /** Snooze limit on policy matching given template. */
-    void snoozePolicy(in NetworkTemplate template);
+    void snoozeLimit(in NetworkTemplate template);
 
     /** Control if background data is restricted system-wide. */
     void setRestrictBackground(boolean restrictBackground);
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index d9ea700..04cf1a3 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -38,18 +38,25 @@
     public int cycleDay;
     public long warningBytes;
     public long limitBytes;
-    public long lastSnooze;
+    public long lastWarningSnooze;
+    public long lastLimitSnooze;
     public boolean metered;
 
     private static final long DEFAULT_MTU = 1500;
 
-    public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes, long limitBytes,
-            long lastSnooze, boolean metered) {
+    public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes,
+            long limitBytes, boolean metered) {
+        this(template, cycleDay, warningBytes, limitBytes, SNOOZE_NEVER, SNOOZE_NEVER, metered);
+    }
+
+    public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes,
+            long limitBytes, long lastWarningSnooze, long lastLimitSnooze, boolean metered) {
         this.template = checkNotNull(template, "missing NetworkTemplate");
         this.cycleDay = cycleDay;
         this.warningBytes = warningBytes;
         this.limitBytes = limitBytes;
-        this.lastSnooze = lastSnooze;
+        this.lastWarningSnooze = lastWarningSnooze;
+        this.lastLimitSnooze = lastLimitSnooze;
         this.metered = metered;
     }
 
@@ -58,7 +65,8 @@
         cycleDay = in.readInt();
         warningBytes = in.readLong();
         limitBytes = in.readLong();
-        lastSnooze = in.readLong();
+        lastWarningSnooze = in.readLong();
+        lastLimitSnooze = in.readLong();
         metered = in.readInt() != 0;
     }
 
@@ -68,7 +76,8 @@
         dest.writeInt(cycleDay);
         dest.writeLong(warningBytes);
         dest.writeLong(limitBytes);
-        dest.writeLong(lastSnooze);
+        dest.writeLong(lastWarningSnooze);
+        dest.writeLong(lastLimitSnooze);
         dest.writeInt(metered ? 1 : 0);
     }
 
@@ -78,6 +87,13 @@
     }
 
     /**
+     * Test if given measurement is over {@link #warningBytes}.
+     */
+    public boolean isOverWarning(long totalBytes) {
+        return warningBytes != WARNING_DISABLED && totalBytes >= warningBytes;
+    }
+
+    /**
      * Test if given measurement is near enough to {@link #limitBytes} to be
      * considered over-limit.
      */
@@ -88,6 +104,14 @@
         return limitBytes != LIMIT_DISABLED && totalBytes >= limitBytes;
     }
 
+    /**
+     * Clear any existing snooze values, setting to {@link #SNOOZE_NEVER}.
+     */
+    public void clearSnooze() {
+        lastWarningSnooze = SNOOZE_NEVER;
+        lastLimitSnooze = SNOOZE_NEVER;
+    }
+
     /** {@inheritDoc} */
     public int compareTo(NetworkPolicy another) {
         if (another == null || another.limitBytes == LIMIT_DISABLED) {
@@ -103,7 +127,8 @@
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(template, cycleDay, warningBytes, limitBytes, lastSnooze, metered);
+        return Objects.hashCode(template, cycleDay, warningBytes, limitBytes, lastWarningSnooze,
+                lastLimitSnooze, metered);
     }
 
     @Override
@@ -111,8 +136,10 @@
         if (obj instanceof NetworkPolicy) {
             final NetworkPolicy other = (NetworkPolicy) obj;
             return cycleDay == other.cycleDay && warningBytes == other.warningBytes
-                    && limitBytes == other.limitBytes && lastSnooze == other.lastSnooze
-                    && metered == other.metered && Objects.equal(template, other.template);
+                    && limitBytes == other.limitBytes
+                    && lastWarningSnooze == other.lastWarningSnooze
+                    && lastLimitSnooze == other.lastLimitSnooze && metered == other.metered
+                    && Objects.equal(template, other.template);
         }
         return false;
     }
@@ -120,8 +147,9 @@
     @Override
     public String toString() {
         return "NetworkPolicy[" + template + "]: cycleDay=" + cycleDay + ", warningBytes="
-                + warningBytes + ", limitBytes=" + limitBytes + ", lastSnooze=" + lastSnooze
-                + ", metered=" + metered;
+                + warningBytes + ", limitBytes=" + limitBytes + ", lastWarningSnooze="
+                + lastWarningSnooze + ", lastLimitSnooze=" + lastLimitSnooze + ", metered="
+                + metered;
     }
 
     public static final Creator<NetworkPolicy> CREATOR = new Creator<NetworkPolicy>() {
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 5e9abb7..fd6bed7 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -135,6 +135,8 @@
  * <p>There are a few threading rules that must be followed for this class to
  * work properly:</p>
  * <ul>
+ *     <li>The AsyncTask class must be loaded on the UI thread. This is done
+ *     automatically as of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}.</li>
  *     <li>The task instance must be created on the UI thread.</li>
  *     <li>{@link #execute} must be invoked on the UI thread.</li>
  *     <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute},
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 4e01672..d11219b 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -62,6 +62,14 @@
     public static final String ACTION_MTP_SESSION_END = "android.provider.action.MTP_SESSION_END";
 
     /**
+     * The method name used by the media scanner and mtp to tell the media provider to
+     * rescan and reclassify that have become unhidden because of renaming folders or
+     * removing nomedia files
+     * @hide
+     */
+    public static final String UNHIDE_CALL = "unhide";
+
+    /**
      * Activity Action: Launch a music player.
      * The activity should be able to play, browse, or manipulate music files stored on the device.
      *
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f14d27e..375e5e4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1678,6 +1678,13 @@
         public static final String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
 
         /**
+         * Scaling factor for Animator-based animations. This affects both the start delay and
+         * duration of all such animations. Setting to 0 will cause animations to end immediately.
+         * The default value is 1.
+         */
+        public static final String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
+
+        /**
          * Scaling factor for normal window animations. Setting to 0 will disable window
          * animations.
          * @hide
@@ -2475,6 +2482,11 @@
             Uri.parse("content://" + AUTHORITY + "/secure");
 
         /**
+         * Whether user has enabled development settings.
+         */
+        public static final String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
+
+        /**
          * Whether ADB is enabled.
          */
         public static final String ADB_ENABLED = "adb_enabled";
diff --git a/core/java/android/view/AccessibilityNodeInfoCache.java b/core/java/android/view/AccessibilityNodeInfoCache.java
new file mode 100644
index 0000000..244a491
--- /dev/null
+++ b/core/java/android/view/AccessibilityNodeInfoCache.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2012 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.view;
+
+import android.util.LongSparseArray;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+/**
+ * Simple cache for AccessibilityNodeInfos. The cache is mapping an
+ * accessibility id to an info. The cache allows storing of
+ * <code>null</code> values. It also tracks accessibility events
+ * and invalidates accordingly.
+ *
+ * @hide
+ */
+public class AccessibilityNodeInfoCache {
+
+    private final boolean ENABLED = true;
+
+    /**
+     * @return A new <strong>not synchronized</strong> AccessibilityNodeInfoCache.
+     */
+    public static AccessibilityNodeInfoCache newAccessibilityNodeInfoCache() {
+        return new AccessibilityNodeInfoCache();
+    }
+
+    /**
+     * @return A new <strong>synchronized</strong> AccessibilityNodeInfoCache.
+     */
+    public static AccessibilityNodeInfoCache newSynchronizedAccessibilityNodeInfoCache() {
+        return new AccessibilityNodeInfoCache() {
+            private final Object mLock = new Object();
+
+            @Override
+            public void clear() {
+                synchronized(mLock) {
+                    super.clear();
+                }
+            }
+
+            @Override
+            public AccessibilityNodeInfo get(long accessibilityNodeId) {
+                synchronized(mLock) {
+                    return super.get(accessibilityNodeId);
+                }
+            }
+
+            @Override
+            public void put(long accessibilityNodeId, AccessibilityNodeInfo info) {
+                synchronized(mLock) {
+                   super.put(accessibilityNodeId, info);
+                }
+            }
+
+            @Override
+            public void remove(long accessibilityNodeId) {
+                synchronized(mLock) {
+                   super.remove(accessibilityNodeId);
+                }
+            }
+        };
+    }
+
+    private final LongSparseArray<AccessibilityNodeInfo> mCacheImpl;
+
+    private AccessibilityNodeInfoCache() {
+        if (ENABLED) {
+            mCacheImpl = new LongSparseArray<AccessibilityNodeInfo>();
+        } else {
+            mCacheImpl = null;
+        }
+    }
+
+    /**
+     * The cache keeps track of {@link AccessibilityEvent}s and invalidates
+     * cached nodes as appropriate.
+     *
+     * @param event An event.
+     */
+    public void onAccessibilityEvent(AccessibilityEvent event) {
+        final int eventType = event.getEventType();
+        switch (eventType) {
+            case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
+            case AccessibilityEvent.TYPE_VIEW_SCROLLED:
+                clear();
+                break;
+            case AccessibilityEvent.TYPE_VIEW_FOCUSED:
+            case AccessibilityEvent.TYPE_VIEW_SELECTED:
+            case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
+            case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED:
+                final long accessibilityNodeId = event.getSourceNodeId();
+                remove(accessibilityNodeId);
+                break;
+        }
+    }
+
+    /**
+     * Gets a cached {@link AccessibilityNodeInfo} given its accessibility node id.
+     *
+     * @param accessibilityNodeId The info accessibility node id.
+     * @return The cached {@link AccessibilityNodeInfo} or null if such not found.
+     */
+    public AccessibilityNodeInfo get(long accessibilityNodeId) {
+        if (ENABLED) {
+            return mCacheImpl.get(accessibilityNodeId);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Caches an {@link AccessibilityNodeInfo} given its accessibility node id.
+     *
+     * @param accessibilityNodeId The info accessibility node id.
+     * @param info The {@link AccessibilityNodeInfo} to cache.
+     */
+    public void put(long accessibilityNodeId, AccessibilityNodeInfo info) {
+        if (ENABLED) {
+            mCacheImpl.put(accessibilityNodeId, info);
+        }
+    }
+
+    /**
+     * Returns whether the cache contains an accessibility node id key.
+     *
+     * @param accessibilityNodeId The key for which to check.
+     * @return True if the key is in the cache.
+     */
+    public boolean containsKey(long accessibilityNodeId) {
+        if (ENABLED) {
+            return (mCacheImpl.indexOfKey(accessibilityNodeId) >= 0);
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Removes a cached {@link AccessibilityNodeInfo}.
+     *
+     * @param accessibilityNodeId The info accessibility node id.
+     */
+    public void remove(long accessibilityNodeId) {
+        if (ENABLED) {
+            mCacheImpl.remove(accessibilityNodeId);
+        }
+    }
+
+    /**
+     * Clears the cache.
+     */
+    public void clear() {
+        if (ENABLED) {
+            mCacheImpl.clear();
+        }
+    }
+}
diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java
index 34e7d4d..0349a2b 100644
--- a/core/java/android/view/ActionMode.java
+++ b/core/java/android/view/ActionMode.java
@@ -18,9 +18,15 @@
 
 
 /**
- * Represents a contextual mode of the user interface. Action modes can be used for
- * modal interactions with content and replace parts of the normal UI until finished.
- * Examples of good action modes include selection modes, search, content editing, etc.
+ * Represents a contextual mode of the user interface. Action modes can be used to provide
+ * alternative interaction modes and replace parts of the normal UI until finished.
+ * Examples of good action modes include text selection and contextual actions.
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For information about how to provide contextual actions with {@code ActionMode},
+ * read the <a href="{@docRoot}guide/topics/ui/menu.html#context-menu">Menus</a>
+ * developer guide.</p>
+ * </div>
  */
 public abstract class ActionMode {
     private Object mTag;
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 63de128..c86ea77 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -26,7 +26,7 @@
 import android.util.Log;
 
 /**
- * Coodinates animations and drawing for UI on a particular thread.
+ * Coordinates animations and drawing for UI on a particular thread.
  * @hide
  */
 public final class Choreographer extends Handler {
@@ -94,8 +94,8 @@
     }
 
     /**
-     * Gets the choreographer for this thread.
-     * Must be called on the UI thread.
+     * Gets the choreographer for the calling thread.  Must be called from
+     * a thread that already has a {@link android.os.Looper} associated with it.
      *
      * @return The choreographer for this thread.
      * @throws IllegalStateException if the thread does not have a looper.
@@ -163,6 +163,15 @@
     }
 
     /**
+     * Return true if {@link #scheduleAnimation()} has been called but
+     * {@link OnAnimateListener#onAnimate() OnAnimateListener.onAnimate()} has
+     * not yet been called.
+     */
+    public boolean isAnimationScheduled() {
+        return mAnimationScheduled;
+    }
+
+    /**
      * Schedules drawing to occur on the next frame synchronization boundary.
      * Must be called on the UI thread.
      */
@@ -180,6 +189,15 @@
         }
     }
 
+    /**
+     * Return true if {@link #scheduleDraw()} has been called but
+     * {@link OnDrawListener#onDraw() OnDrawListener.onDraw()} has
+     * not yet been called.
+     */
+    public boolean isDrawScheduled() {
+        return mDrawScheduled;
+    }
+
     @Override
     public void handleMessage(Message msg) {
         switch (msg.what) {
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index c08a4024..fa4dd25 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -189,7 +189,7 @@
     }
 
     private static native int nGetMaximumTextureWidth();
-    private static native int nGetMaximumTextureHeight();    
+    private static native int nGetMaximumTextureHeight();
 
     ///////////////////////////////////////////////////////////////////////////
     // Setup
@@ -268,6 +268,24 @@
 
     private static native void nFinish(int renderer);
 
+    /**
+     * Returns the size of the stencil buffer required by the underlying
+     * implementation.
+     * 
+     * @return The minimum number of bits the stencil buffer must. Always >= 0.
+     * 
+     * @hide
+     */
+    public static int getStencilSize() {
+        return nGetStencilSize();
+    }
+
+    private static native int nGetStencilSize();
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Functor
+    ///////////////////////////////////////////////////////////////////////////
+
     @Override
     public boolean callDrawGLFunction(int drawGLFunction) {
         return nCallDrawGLFunction(mRenderer, drawGLFunction);
@@ -275,7 +293,6 @@
 
     private static native boolean nCallDrawGLFunction(int renderer, int drawGLFunction);
 
-
     ///////////////////////////////////////////////////////////////////////////
     // Memory
     ///////////////////////////////////////////////////////////////////////////
@@ -361,6 +378,12 @@
 
     private static native int nGetDisplayListSize(int displayList);
 
+    static void setDisplayListName(int displayList, String name) {
+        nSetDisplayListName(displayList, name);
+    }
+
+    private static native void nSetDisplayListName(int displayList, String name);
+
     @Override
     public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) {
         return nDrawDisplayList(mRenderer,
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index 0cb9449..969c9ab 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -31,10 +31,17 @@
     private GLES20RecordingCanvas mCanvas;
     private boolean mValid;
 
+    // Used for debugging
+    private final String mName;
+
     // The native display list will be destroyed when this object dies.
     // DO NOT overwrite this reference once it is set.
     private DisplayListFinalizer mFinalizer;
 
+    GLES20DisplayList(String name) {
+        mName = name;
+    }
+
     int getNativeDisplayList() {
         if (!mValid || mFinalizer == null) {
             throw new IllegalStateException("The display list is not valid.");
@@ -75,6 +82,7 @@
                 mCanvas.end(mFinalizer.mNativeDisplayList);
             } else {
                 mFinalizer = new DisplayListFinalizer(mCanvas.end(0));
+                GLES20Canvas.setDisplayListName(mFinalizer.mNativeDisplayList, mName);
             }
             mCanvas.recycle();
             mCanvas = null;
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 1c9cbbf..9e8a228 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -283,9 +283,12 @@
      * Creates a new display list that can be used to record batches of
      * drawing operations.
      * 
+     * @param name The name of the display list, used for debugging purpose.
+     *             May be null
+     * 
      * @return A new display list.
      */
-    public abstract DisplayList createDisplayList();
+    public abstract DisplayList createDisplayList(String name);
 
     /**
      * Creates a new hardware layer. A hardware layer built by calling this
@@ -1047,7 +1050,7 @@
                     EGL_BLUE_SIZE, 8,
                     EGL_ALPHA_SIZE, 8,
                     EGL_DEPTH_SIZE, 0,
-                    EGL_STENCIL_SIZE, 0,
+                    EGL_STENCIL_SIZE, GLES20Canvas.getStencilSize(),
                     EGL_SURFACE_TYPE, EGL_WINDOW_BIT |
                             (dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
                     EGL_NONE
@@ -1094,8 +1097,8 @@
         }
 
         @Override
-        public DisplayList createDisplayList() {
-            return new GLES20DisplayList();
+        public DisplayList createDisplayList(String name) {
+            return new GLES20DisplayList(name);
         }
 
         @Override
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8cac57d..7ba17b3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3761,8 +3761,14 @@
     }
 
     /**
-     * Called when this view wants to give up focus. This will cause
-     * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called.
+     * Called when this view wants to give up focus. If focus is cleared
+     * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called.
+     * <p>
+     * <strong>Note:</strong> When a View clears focus the framework is trying
+     * to give focus to the first focusable View from the top. Hence, if this
+     * View is the first from the top that can take focus, then its focus will
+     * not be cleared nor will the focus change callback be invoked.
+     * </p>
      */
     public void clearFocus() {
         if (DBG) {
@@ -3770,6 +3776,14 @@
         }
 
         if ((mPrivateFlags & FOCUSED) != 0) {
+            // If this is the first focusable do not clear focus since the we
+            // try to give it focus every time a view clears its focus. Hence,
+            // the view that would gain focus already has it.
+            View firstFocusable = getFirstFocusable();
+            if (firstFocusable == this) {
+                return;
+            }
+
             mPrivateFlags &= ~FOCUSED;
 
             if (mParent != null) {
@@ -3778,9 +3792,24 @@
 
             onFocusChanged(false, 0, null);
             refreshDrawableState();
+
+            // The view cleared focus and invoked the callbacks, so  now is the
+            // time to give focus to the the first focusable to ensure that the
+            // gain focus is announced after clear focus.
+            if (firstFocusable != null) {
+                firstFocusable.requestFocus(FOCUS_FORWARD);
+            }
         }
     }
 
+    private View getFirstFocusable() {
+        ViewRootImpl viewRoot = getViewRootImpl();
+        if (viewRoot != null) {
+            return viewRoot.focusSearch(null, FOCUS_FORWARD);
+        }
+        return null;
+    }
+
     /**
      * Called to clear the focus of a view that is about to be removed.
      * Doesn't call clearChildFocus, which prevents this view from taking
@@ -6822,7 +6851,8 @@
 
         if ((changed & VISIBILITY_MASK) != 0) {
             if (mParent instanceof ViewGroup) {
-                ((ViewGroup) mParent).onChildVisibilityChanged(this, (flags & VISIBILITY_MASK));
+                ((ViewGroup) mParent).onChildVisibilityChanged(this, (changed & VISIBILITY_MASK),
+                        (flags & VISIBILITY_MASK));
                 ((View) mParent).invalidate(true);
             } else if (mParent != null) {
                 mParent.invalidateChild(this, null);
@@ -7282,6 +7312,7 @@
      * 
      * @return The degrees of rotation.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getRotation() {
         return mTransformationInfo != null ? mTransformationInfo.mRotation : 0;
     }
@@ -7323,6 +7354,7 @@
      * 
      * @return The degrees of Y rotation.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getRotationY() {
         return mTransformationInfo != null ? mTransformationInfo.mRotationY : 0;
     }
@@ -7369,6 +7401,7 @@
      * 
      * @return The degrees of X rotation.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getRotationX() {
         return mTransformationInfo != null ? mTransformationInfo.mRotationX : 0;
     }
@@ -7416,6 +7449,7 @@
      * @see #getPivotY()
      * @return The scaling factor.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getScaleX() {
         return mTransformationInfo != null ? mTransformationInfo.mScaleX : 1;
     }
@@ -7454,6 +7488,7 @@
      * @see #getPivotY()
      * @return The scaling factor.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getScaleY() {
         return mTransformationInfo != null ? mTransformationInfo.mScaleY : 1;
     }
@@ -7492,6 +7527,7 @@
      * @see #getPivotY()
      * @return The x location of the pivot point.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getPivotX() {
         return mTransformationInfo != null ? mTransformationInfo.mPivotX : 0;
     }
@@ -7536,6 +7572,7 @@
      * @see #getPivotY()
      * @return The y location of the pivot point.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getPivotY() {
         return mTransformationInfo != null ? mTransformationInfo.mPivotY : 0;
     }
@@ -7576,6 +7613,7 @@
      * <p>By default this is 1.0f.
      * @return The opacity of the view.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getAlpha() {
         return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1;
     }
@@ -7589,6 +7627,10 @@
      * equivalent to calling {@link #setLayerType(int, android.graphics.Paint)} and
      * setting a hardware layer.</p>
      *
+     * <p>Note that setting alpha to a translucent value (0 < alpha < 1) may have
+     * performance implications. It is generally best to use the alpha property sparingly and
+     * transiently, as in the case of fading animations.</p>
+     *
      * @param alpha The opacity of the view.
      *
      * @see #setLayerType(int, android.graphics.Paint)
@@ -7886,6 +7928,7 @@
      *
      * @return The visual x position of this view, in pixels.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getX() {
         return mLeft + (mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0);
     }
@@ -7908,6 +7951,7 @@
      *
      * @return The visual y position of this view, in pixels.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getY() {
         return mTop + (mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0);
     }
@@ -7931,6 +7975,7 @@
      *
      * @return The horizontal position of this view relative to its left position, in pixels.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getTranslationX() {
         return mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0;
     }
@@ -7967,6 +8012,7 @@
      * @return The vertical position of this view relative to its top position,
      * in pixels.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getTranslationY() {
         return mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0;
     }
@@ -10373,7 +10419,8 @@
             // we copy in child display lists into ours in drawChild()
             mRecreateDisplayList = true;
             if (mDisplayList == null) {
-                mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList();
+                final String name = getClass().getSimpleName();
+                mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList(name);
                 // If we're creating a new display list, make sure our parent gets invalidated
                 // since they will need to recreate their display list to account for this
                 // new child display list.
@@ -12654,6 +12701,11 @@
             ViewDebug.trace(this, ViewDebug.HierarchyTraceType.REQUEST_LAYOUT);
         }
 
+        if (getAccessibilityNodeProvider() != null) {
+            throw new IllegalStateException("Views with AccessibilityNodeProvider"
+                    + " can't have children.");
+        }
+
         mPrivateFlags |= FORCE_LAYOUT;
         mPrivateFlags |= INVALIDATED;
 
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index dda695fc..d3af618 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -675,11 +675,14 @@
      */
     @Override
     public void clearFocus() {
-        super.clearFocus();
-
-        // clear any child focus if it exists
-        if (mFocused != null) {
+        if (DBG) {
+            System.out.println(this + " clearFocus()");
+        }
+        if (mFocused == null) {
+            super.clearFocus();
+        } else {
             mFocused.clearFocus();
+            mFocused = null;
         }
     }
 
@@ -691,12 +694,12 @@
         if (DBG) {
             System.out.println(this + " unFocus()");
         }
-
-        super.unFocus();
-        if (mFocused != null) {
+        if (mFocused == null) {
+            super.unFocus();
+        } else {
             mFocused.unFocus();
+            mFocused = null;
         }
-        mFocused = null;
     }
 
     /**
@@ -888,18 +891,20 @@
     }
 
     /**
+     * Called when a view's visibility has changed. Notify the parent to take any appropriate
+     * action.
+     *
+     * @param child The view whose visibility has changed
+     * @param oldVisibility The previous visibility value (GONE, INVISIBLE, or VISIBLE).
+     * @param newVisibility The new visibility value (GONE, INVISIBLE, or VISIBLE).
      * @hide
-     * @param child
-     * @param visibility
      */
-    protected void onChildVisibilityChanged(View child, int visibility) {
+    protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
         if (mTransition != null) {
-            if (visibility == VISIBLE) {
-                mTransition.showChild(this, child);
+            if (newVisibility == VISIBLE) {
+                mTransition.showChild(this, child, oldVisibility);
             } else {
-                mTransition.hideChild(this, child);
-            }
-            if (visibility != VISIBLE) {
+                mTransition.hideChild(this, child, newVisibility);
                 // Only track this on disappearing views - appearing views are already visible
                 // and don't need special handling during drawChild()
                 if (mVisibilityChangingChildren == null) {
@@ -914,7 +919,7 @@
 
         // in all cases, for drags
         if (mCurrentDrag != null) {
-            if (visibility == VISIBLE) {
+            if (newVisibility == VISIBLE) {
                 notifyChildOfDrag(child);
             }
         }
@@ -3351,6 +3356,11 @@
     private void addViewInner(View child, int index, LayoutParams params,
             boolean preventRequestLayout) {
 
+        if (getAccessibilityNodeProvider() != null) {
+            throw new IllegalStateException("Views with AccessibilityNodeProvider"
+                    + " can't have children.");
+        }
+
         if (mTransition != null) {
             // Don't prevent other add transitions from completing, but cancel remove
             // transitions to let them complete the process before we add to the container
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 89a1ef2..0fdcd0f 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -113,6 +113,10 @@
      * on that list are added to the list of properties associated with that animator.
      */
     ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();
+    private Runnable mPendingSetupAction;
+    private Runnable mPendingCleanupAction;
+    private Runnable mPendingOnStartAction;
+    private Runnable mPendingOnEndAction;
 
     /**
      * Constants used to associate a property being requested and the mechanism used to set
@@ -199,6 +203,10 @@
      */
     private HashMap<Animator, PropertyBundle> mAnimatorMap =
             new HashMap<Animator, PropertyBundle>();
+    private HashMap<Animator, Runnable> mAnimatorSetupMap;
+    private HashMap<Animator, Runnable> mAnimatorCleanupMap;
+    private HashMap<Animator, Runnable> mAnimatorOnStartMap;
+    private HashMap<Animator, Runnable> mAnimatorOnEndMap;
 
     /**
      * This is the information we need to set each property during the animation.
@@ -614,6 +622,93 @@
     }
 
     /**
+     * The View associated with this ViewPropertyAnimator will have its
+     * {@link View#setLayerType(int, android.graphics.Paint) layer type} set to
+     * {@link View#LAYER_TYPE_HARDWARE} for the duration of the next animation. This state
+     * is not persistent, either on the View or on this ViewPropertyAnimator: the layer type
+     * of the View will be restored when the animation ends to what it was when this method was
+     * called, and this setting on ViewPropertyAnimator is only valid for the next animation.
+     * Note that calling this method and then independently setting the layer type of the View
+     * (by a direct call to {@link View#setLayerType(int, android.graphics.Paint)}) will result
+     * in some inconsistency, including having the layer type restored to its pre-withLayer()
+     * value when the animation ends.
+     *
+     * @see View#setLayerType(int, android.graphics.Paint)
+     * @return This object, allowing calls to methods in this class to be chained.
+     */
+    public ViewPropertyAnimator withLayer() {
+         mPendingSetupAction= new Runnable() {
+            @Override
+            public void run() {
+                mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            }
+        };
+        final int currentLayerType = mView.getLayerType();
+        mPendingCleanupAction = new Runnable() {
+            @Override
+            public void run() {
+                mView.setLayerType(currentLayerType, null);
+            }
+        };
+        if (mAnimatorSetupMap == null) {
+            mAnimatorSetupMap = new HashMap<Animator, Runnable>();
+        }
+        if (mAnimatorCleanupMap == null) {
+            mAnimatorCleanupMap = new HashMap<Animator, Runnable>();
+        }
+
+        return this;
+    }
+
+    /**
+     * Specifies an action to take place when the next animation runs. If there is a
+     * {@link #setStartDelay(long) startDelay} set on this ViewPropertyAnimator, then the
+     * action will run after that startDelay expires, when the actual animation begins.
+     * This method, along with {@link #withEndAction(Runnable)}, is intended to help facilitate
+     * choreographing ViewPropertyAnimator animations with other animations or actions
+     * in the application.
+     *
+     * @param runnable The action to run when the next animation starts.
+     * @return This object, allowing calls to methods in this class to be chained.
+     */
+    public ViewPropertyAnimator withStartAction(Runnable runnable) {
+        mPendingOnStartAction = runnable;
+        if (runnable != null && mAnimatorOnStartMap == null) {
+            mAnimatorOnStartMap = new HashMap<Animator, Runnable>();
+        }
+        return this;
+    }
+
+    /**
+     * Specifies an action to take place when the next animation ends. The action is only
+     * run if the animation ends normally; if the ViewPropertyAnimator is canceled during
+     * that animation, the runnable will not run.
+     * This method, along with {@link #withStartAction(Runnable)}, is intended to help facilitate
+     * choreographing ViewPropertyAnimator animations with other animations or actions
+     * in the application.
+     *
+     * <p>For example, the following code animates a view to x=200 and then back to 0:</p>
+     * <pre>
+     *     Runnable endAction = new Runnable() {
+     *         public void run() {
+     *             view.animate().x(0);
+     *         }
+     *     };
+     *     view.animate().x(200).onEnd(endAction);
+     * </pre>
+     *
+     * @param runnable The action to run when the next animation ends.
+     * @return This object, allowing calls to methods in this class to be chained.
+     */
+    public ViewPropertyAnimator withEndAction(Runnable runnable) {
+        mPendingOnEndAction = runnable;
+        if (runnable != null && mAnimatorOnEndMap == null) {
+            mAnimatorOnEndMap = new HashMap<Animator, Runnable>();
+        }
+        return this;
+    }
+
+    /**
      * Starts the underlying Animator for a set of properties. We use a single animator that
      * simply runs from 0 to 1, and then use that fractional value to set each property
      * value accordingly.
@@ -630,6 +725,22 @@
             propertyMask |= nameValuesHolder.mNameConstant;
         }
         mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
+        if (mPendingSetupAction != null) {
+            mAnimatorSetupMap.put(animator, mPendingSetupAction);
+            mPendingSetupAction = null;
+        }
+        if (mPendingCleanupAction != null) {
+            mAnimatorCleanupMap.put(animator, mPendingCleanupAction);
+            mPendingCleanupAction = null;
+        }
+        if (mPendingOnStartAction != null) {
+            mAnimatorOnStartMap.put(animator, mPendingOnStartAction);
+            mPendingOnStartAction = null;
+        }
+        if (mPendingOnEndAction != null) {
+            mAnimatorOnEndMap.put(animator, mPendingOnEndAction);
+            mPendingOnEndAction = null;
+        }
         animator.addUpdateListener(mAnimatorEventListener);
         animator.addListener(mAnimatorEventListener);
         if (mStartDelaySet) {
@@ -800,6 +911,20 @@
             implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
         @Override
         public void onAnimationStart(Animator animation) {
+            if (mAnimatorSetupMap != null) {
+                Runnable r = mAnimatorSetupMap.get(animation);
+                if (r != null) {
+                    r.run();
+                }
+                mAnimatorSetupMap.remove(animation);
+            }
+            if (mAnimatorOnStartMap != null) {
+                Runnable r = mAnimatorOnStartMap.get(animation);
+                if (r != null) {
+                    r.run();
+                }
+                mAnimatorOnStartMap.remove(animation);
+            }
             if (mListener != null) {
                 mListener.onAnimationStart(animation);
             }
@@ -810,6 +935,9 @@
             if (mListener != null) {
                 mListener.onAnimationCancel(animation);
             }
+            if (mAnimatorOnEndMap != null) {
+                mAnimatorOnEndMap.remove(animation);
+            }
         }
 
         @Override
@@ -824,6 +952,20 @@
             if (mListener != null) {
                 mListener.onAnimationEnd(animation);
             }
+            if (mAnimatorOnEndMap != null) {
+                Runnable r = mAnimatorOnEndMap.get(animation);
+                if (r != null) {
+                    r.run();
+                }
+                mAnimatorOnEndMap.remove(animation);
+            }
+            if (mAnimatorCleanupMap != null) {
+                Runnable r = mAnimatorCleanupMap.get(animation);
+                if (r != null) {
+                    r.run();
+                }
+                mAnimatorCleanupMap.remove(animation);
+            }
             mAnimatorMap.remove(animation);
         }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1a4bdf4..cbf4b5a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -18,11 +18,13 @@
 
 import android.Manifest;
 import android.animation.LayoutTransition;
+import android.animation.ValueAnimator;
 import android.app.ActivityManagerNative;
 import android.content.ClipDescription;
 import android.content.ComponentCallbacks;
 import android.content.ComponentCallbacks2;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
@@ -52,6 +54,7 @@
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.LongSparseArray;
 import android.util.Pool;
 import android.util.Poolable;
 import android.util.PoolableManager;
@@ -81,7 +84,6 @@
 
 import java.io.IOException;
 import java.io.OutputStream;
-import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
@@ -139,6 +141,10 @@
     static final ArrayList<ComponentCallbacks> sConfigCallbacks
             = new ArrayList<ComponentCallbacks>();
 
+    private static boolean sUseRenderThread = false;
+    private static boolean sRenderThreadQueried = false;
+    private static final Object[] sRenderThreadQueryLock = new Object[0];
+
     long mLastTrackballTime = 0;
     final TrackballAxis mTrackballAxisX = new TrackballAxis();
     final TrackballAxis mTrackballAxisY = new TrackballAxis();
@@ -168,6 +174,7 @@
     View mView;
     View mFocusedView;
     View mRealFocusedView;  // this is not set to null in touch mode
+    View mOldFocusedView;
     int mViewVisibility;
     boolean mAppVisible = true;
     int mOrigWindowType = -1;
@@ -301,6 +308,8 @@
 
     SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
 
+    AccessibilityPrefetchStrategy mAccessibilityPrefetchStrategy;
+
     private final int mDensity;
 
     /**
@@ -315,8 +324,11 @@
             if (!mInitialized) {
                 try {
                     InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
-                    sWindowSession = Display.getWindowManager().openSession(
+                    IWindowManager windowManager = Display.getWindowManager();
+                    sWindowSession = windowManager.openSession(
                             imm.getClient(), imm.getInputContext());
+                    float animatorScale = windowManager.getAnimationScale(2);
+                    ValueAnimator.setDurationScale(animatorScale);
                     mInitialized = true;
                 } catch (RemoteException e) {
                 }
@@ -377,6 +389,31 @@
         mChoreographer = Choreographer.getInstance();
     }
 
+    /**
+     * @return True if the application requests the use of a separate render thread,
+     *         false otherwise
+     */
+    private static boolean isRenderThreadRequested(Context context) {
+        synchronized (sRenderThreadQueryLock) {
+            if (!sRenderThreadQueried) {
+                final PackageManager packageManager = context.getPackageManager();
+                final String packageName = context.getApplicationInfo().packageName;
+                try {
+                    ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName,
+                            PackageManager.GET_META_DATA);
+                    if (applicationInfo.metaData != null) {
+                        sUseRenderThread = applicationInfo.metaData.getBoolean(
+                                "android.graphics.renderThread", false);
+                    }
+                } catch (PackageManager.NameNotFoundException e) {
+                } finally {
+                    sRenderThreadQueried = true;
+                }
+            }
+            return sUseRenderThread;
+        }
+    }
+
     public static void addFirstDrawHandler(Runnable callback) {
         synchronized (sFirstDrawHandlers) {
             if (!sFirstDrawComplete) {
@@ -447,7 +484,7 @@
 
                 // If the application owns the surface, don't enable hardware acceleration
                 if (mSurfaceHolder == null) {
-                    enableHardwareAcceleration(attrs);
+                    enableHardwareAcceleration(mView.getContext(), attrs);
                 }
 
                 boolean restore = false;
@@ -607,7 +644,7 @@
         }
     }
 
-    private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
+    private void enableHardwareAcceleration(Context context, WindowManager.LayoutParams attrs) {
         mAttachInfo.mHardwareAccelerated = false;
         mAttachInfo.mHardwareAccelerationRequested = false;
 
@@ -640,20 +677,27 @@
             if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
                     && forceHwAccelerated)) {
                 // Don't enable hardware acceleration when we're not on the main thread
-                if (!HardwareRenderer.sSystemRendererDisabled
-                        && Looper.getMainLooper() != Looper.myLooper()) {
-                    Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
+                if (!HardwareRenderer.sSystemRendererDisabled &&
+                        Looper.getMainLooper() != Looper.myLooper()) {
+                    Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware " 
                             + "acceleration outside of the main thread, aborting");
                     return;
                 }
 
-                final boolean translucent = attrs.format != PixelFormat.OPAQUE;
+                boolean renderThread = isRenderThreadRequested(context);
+                if (renderThread) {
+                    Log.i(HardwareRenderer.LOG_TAG, "Render threat initiated");
+                }
+
                 if (mAttachInfo.mHardwareRenderer != null) {
                     mAttachInfo.mHardwareRenderer.destroy(true);
-                }                
+                }
+
+                final boolean translucent = attrs.format != PixelFormat.OPAQUE;
                 mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
                 mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested
                         = mAttachInfo.mHardwareRenderer != null;
+
             } else if (fakeHwAccelerated) {
                 // The window had wanted to use hardware acceleration, but this
                 // is not allowed in its process.  By setting this flag, it can
@@ -2226,32 +2270,33 @@
 
     public void requestChildFocus(View child, View focused) {
         checkThread();
-        if (mFocusedView != focused) {
-            mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mFocusedView, focused);
-            scheduleTraversals();
+
+        if (DEBUG_INPUT_RESIZE) {
+            Log.v(TAG, "Request child focus: focus now " + focused);
         }
+
+        mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mOldFocusedView, focused);
+        scheduleTraversals();
+
         mFocusedView = mRealFocusedView = focused;
-        if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Request child focus: focus now "
-                + mFocusedView);
     }
 
     public void clearChildFocus(View child) {
         checkThread();
 
-        View oldFocus = mFocusedView;
-
-        if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Clearing child focus");
-        mFocusedView = mRealFocusedView = null;
-        if (mView != null && !mView.hasFocus()) {
-            // If a view gets the focus, the listener will be invoked from requestChildFocus()
-            if (!mView.requestFocus(View.FOCUS_FORWARD)) {
-                mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null);
-            }
-        } else if (oldFocus != null) {
-            mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null);
+        if (DEBUG_INPUT_RESIZE) {
+            Log.v(TAG, "Clearing child focus");
         }
-    }
 
+        mOldFocusedView = mFocusedView;
+
+        // Invoke the listener only if there is no view to take focus
+        if (focusSearch(null, View.FOCUS_FORWARD) == null) {
+            mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mOldFocusedView, null);
+        }
+
+        mFocusedView = mRealFocusedView = null;
+    }
 
     public void focusableViewAvailable(View v) {
         checkThread();
@@ -2724,6 +2769,7 @@
                         mView.unFocus();
                         mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(focused, null);
                         mFocusedView = null;
+                        mOldFocusedView = null;
                         return true;
                     }
                 }
@@ -3438,11 +3484,11 @@
         if (args.localChanges != 0) {
             if (mAttachInfo != null) {
                 mAttachInfo.mSystemUiVisibility =
-                        (mAttachInfo.mSystemUiVisibility&~args.localChanges)
-                        | (args.localValue&args.localChanges);
+                        (mAttachInfo.mSystemUiVisibility & ~args.localChanges) |
+                                (args.localValue & args.localChanges);
+                mAttachInfo.mRecomputeGlobalAttributes = true;
             }
             mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
-            mAttachInfo.mRecomputeGlobalAttributes = true;
             scheduleTraversals();            
         }
         mView.dispatchSystemUiVisibilityChanged(args.globalVisibility);
@@ -3480,6 +3526,17 @@
         return mAccessibilityInteractionController;
     }
 
+    public AccessibilityPrefetchStrategy getAccessibilityPrefetchStrategy() {
+        if (mView == null) {
+            throw new IllegalStateException("getAccessibilityPrefetchStrategy"
+                    + " called when there is no mView");
+        }
+        if (mAccessibilityPrefetchStrategy == null) {
+            mAccessibilityPrefetchStrategy = new AccessibilityPrefetchStrategy();
+        }
+        return mAccessibilityPrefetchStrategy;
+    }
+
     private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
             boolean insetsPending) throws RemoteException {
 
@@ -3585,7 +3642,7 @@
         mView.debug();
     }
     
-    public void dumpGfxInfo(PrintWriter pw, int[] info) {
+    public void dumpGfxInfo(int[] info) {
         if (mView != null) {
             getGfxInfo(mView, info);
         } else {
@@ -3697,7 +3754,7 @@
      * Represents a pending input event that is waiting in a queue.
      *
      * Input events are processed in serial order by the timestamp specified by
-     * {@link InputEvent#getEventTime()}.  In general, the input dispatcher delivers
+     * {@link InputEvent#getEventTimeNano()}.  In general, the input dispatcher delivers
      * one input event to the application at a time and waits for the application
      * to finish handling it before delivering the next one.
      *
@@ -3706,7 +3763,7 @@
      * needing a queue on the application's side.
      */
     private static final class QueuedInputEvent {
-        public static final int FLAG_DELIVER_POST_IME = 1 << 0;
+        public static final int FLAG_DELIVER_POST_IME = 1;
 
         public QueuedInputEvent mNext;
 
@@ -3980,6 +4037,7 @@
         if (mView == null) {
             return false;
         }
+        getAccessibilityPrefetchStrategy().onAccessibilityEvent(event);
         mAccessibilityManager.sendAccessibilityEvent(event);
         return true;
     }
@@ -4539,6 +4597,13 @@
                 viewRootImpl.getAccessibilityInteractionController()
                     .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
                         interactionId, callback, interrogatingPid, interrogatingTid);
+            } else {
+                // We cannot make the call and notify the caller so it does not wait.
+                try {
+                    callback.setFindAccessibilityNodeInfosResult(null, interactionId);
+                } catch (RemoteException re) {
+                    /* best effort - ignore */
+                }
             }
         }
 
@@ -4550,28 +4615,49 @@
                 viewRootImpl.getAccessibilityInteractionController()
                     .performAccessibilityActionClientThread(accessibilityNodeId, action,
                             interactionId, callback, interogatingPid, interrogatingTid);
+            } else {
+                // We cannot make the call and notify the caller so it does not
+                try {
+                    callback.setPerformAccessibilityActionResult(false, interactionId);
+                } catch (RemoteException re) {
+                    /* best effort - ignore */
+                }
             }
         }
 
-        public void findAccessibilityNodeInfoByViewId(int viewId,
+        public void findAccessibilityNodeInfoByViewId(long accessibilityNodeId, int viewId,
                 int interactionId, IAccessibilityInteractionConnectionCallback callback,
                 int interrogatingPid, long interrogatingTid) {
             ViewRootImpl viewRootImpl = mViewRootImpl.get();
             if (viewRootImpl != null && viewRootImpl.mView != null) {
                 viewRootImpl.getAccessibilityInteractionController()
-                    .findAccessibilityNodeInfoByViewIdClientThread(viewId, interactionId, callback,
-                            interrogatingPid, interrogatingTid);
-            }
-        }
-
-        public void findAccessibilityNodeInfosByText(String text, long accessibilityNodeId,
-                int interactionId, IAccessibilityInteractionConnectionCallback callback,
-                int interrogatingPid, long interrogatingTid) {
-            ViewRootImpl viewRootImpl = mViewRootImpl.get();
-            if (viewRootImpl != null && viewRootImpl.mView != null) {
-                viewRootImpl.getAccessibilityInteractionController()
-                    .findAccessibilityNodeInfosByTextClientThread(text, accessibilityNodeId,
+                    .findAccessibilityNodeInfoByViewIdClientThread(accessibilityNodeId, viewId,
                             interactionId, callback, interrogatingPid, interrogatingTid);
+            } else {
+                // We cannot make the call and notify the caller so it does not
+                try {
+                    callback.setFindAccessibilityNodeInfoResult(null, interactionId);
+                } catch (RemoteException re) {
+                    /* best effort - ignore */
+                }
+            }
+        }
+
+        public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
+                int interactionId, IAccessibilityInteractionConnectionCallback callback,
+                int interrogatingPid, long interrogatingTid) {
+            ViewRootImpl viewRootImpl = mViewRootImpl.get();
+            if (viewRootImpl != null && viewRootImpl.mView != null) {
+                viewRootImpl.getAccessibilityInteractionController()
+                    .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
+                            interactionId, callback, interrogatingPid, interrogatingTid);
+            } else {
+                // We cannot make the call and notify the caller so it does not
+                try {
+                    callback.setFindAccessibilityNodeInfosResult(null, interactionId);
+                } catch (RemoteException re) {
+                    /* best effort - ignore */
+                }
             }
         }
     }
@@ -4649,6 +4735,7 @@
                 long interrogatingTid) {
             Message message = Message.obtain();
             message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID;
+            message.arg1 = interrogatingPid;
             SomeArgs args = mPool.acquire();
             args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
             args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
@@ -4671,40 +4758,47 @@
 
         public void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message) {
             SomeArgs args = (SomeArgs) message.obj;
+            final int interrogatingPid = message.arg1;
             final int accessibilityViewId = args.argi1;
             final int virtualDescendantId = args.argi2;
             final int interactionId = args.argi3;
             final IAccessibilityInteractionConnectionCallback callback =
                 (IAccessibilityInteractionConnectionCallback) args.arg1;
             mPool.release(args);
-            AccessibilityNodeInfo info = null;
+            List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
+            infos.clear();
             try {
                 View target = findViewByAccessibilityId(accessibilityViewId);
                 if (target != null && target.getVisibility() == View.VISIBLE) {
                     AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
                     if (provider != null) {
-                        info = provider.createAccessibilityNodeInfo(virtualDescendantId);
+                        infos.add(provider.createAccessibilityNodeInfo(virtualDescendantId));
                     } else if (virtualDescendantId == View.NO_ID) {
-                        info = target.createAccessibilityNodeInfo();
+                        getAccessibilityPrefetchStrategy().prefetchAccessibilityNodeInfos(
+                                interrogatingPid, target, infos);
                     }
                 }
             } finally {
                 try {
-                    callback.setFindAccessibilityNodeInfoResult(info, interactionId);
+                    callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
+                    infos.clear();
                 } catch (RemoteException re) {
                     /* ignore - the other side will time out */
                 }
             }
         }
 
-        public void findAccessibilityNodeInfoByViewIdClientThread(int viewId, int interactionId,
-                IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
-                long interrogatingTid) {
+        public void findAccessibilityNodeInfoByViewIdClientThread(long accessibilityNodeId,
+                int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback,
+                int interrogatingPid, long interrogatingTid) {
             Message message = Message.obtain();
             message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID;
-            message.arg1 = viewId;
-            message.arg2 = interactionId;
-            message.obj = callback;
+            message.arg1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
+            SomeArgs args = mPool.acquire();
+            args.argi1 = viewId;
+            args.argi2 = interactionId;
+            args.arg1 = callback;
+            message.obj = args;
             // If the interrogation is performed by the same thread as the main UI
             // thread in this process, set the message as a static reference so
             // after this call completes the same thread but in the interrogating
@@ -4720,17 +4814,26 @@
         }
 
         public void findAccessibilityNodeInfoByViewIdUiThread(Message message) {
-            final int viewId = message.arg1;
-            final int interactionId = message.arg2;
+            final int accessibilityViewId = message.arg1;
+            SomeArgs args = (SomeArgs) message.obj;
+            final int viewId = args.argi1;
+            final int interactionId = args.argi2;
             final IAccessibilityInteractionConnectionCallback callback =
-                (IAccessibilityInteractionConnectionCallback) message.obj;
-
+                (IAccessibilityInteractionConnectionCallback) args.arg1;
+            mPool.release(args);
             AccessibilityNodeInfo info = null;
             try {
-                View root = ViewRootImpl.this.mView;
-                View target = root.findViewById(viewId);
-                if (target != null && target.getVisibility() == View.VISIBLE) {
-                    info = target.createAccessibilityNodeInfo();
+                View root = null;
+                if (accessibilityViewId != View.NO_ID) {
+                    root = findViewByAccessibilityId(accessibilityViewId);
+                } else {
+                    root = ViewRootImpl.this.mView;
+                }
+                if (root != null) {
+                    View target = root.findViewById(viewId);
+                    if (target != null && target.getVisibility() == View.VISIBLE) {
+                        info = target.createAccessibilityNodeInfo();
+                    }
                 }
             } finally {
                 try {
@@ -4741,8 +4844,8 @@
             }
         }
 
-        public void findAccessibilityNodeInfosByTextClientThread(String text,
-                long accessibilityNodeId, int interactionId,
+        public void findAccessibilityNodeInfosByTextClientThread(long accessibilityNodeId,
+                String text, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
                 long interrogatingTid) {
             Message message = Message.obtain();
@@ -4779,7 +4882,7 @@
             mPool.release(args);
             List<AccessibilityNodeInfo> infos = null;
             try {
-                View target = null;
+                View target;
                 if (accessibilityViewId != View.NO_ID) {
                     target = findViewByAccessibilityId(accessibilityViewId);
                 } else {
@@ -4934,4 +5037,88 @@
             }
         }
     }
+
+    /**
+     * This class encapsulates a prefetching strategy for the accessibility APIs for
+     * querying window content.It is responsible to prefetch a batch of
+     * AccessibilityNodeInfos in addition to the one for a requested node. It caches
+     * the ids of the prefeteched nodes such that they are fetched only once.
+     */
+    class AccessibilityPrefetchStrategy {
+        private static final int MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE = 100;
+
+        // We need to keep track of what we have sent for each interrogating
+        // process. Usually there will be only one such process but we
+        // should support the general case. Note that the accessibility event
+        // stream will take care of clearing caches of querying processes that
+        // are not longer alive, so we do not waste memory.
+        private final LongSparseArray<AccessibilityNodeInfoCache> mAccessibilityNodeInfoCaches =
+            new LongSparseArray<AccessibilityNodeInfoCache>();
+
+        private AccessibilityNodeInfoCache getCacheForInterrogatingPid(long interrogatingPid) {
+            AccessibilityNodeInfoCache cache = mAccessibilityNodeInfoCaches.get(interrogatingPid);
+            if (cache == null) {
+                cache = AccessibilityNodeInfoCache.newAccessibilityNodeInfoCache();
+                mAccessibilityNodeInfoCaches.put(interrogatingPid, cache);
+            }
+            return cache;
+        }
+
+        public void onAccessibilityEvent(AccessibilityEvent event) {
+            final int cacheCount = mAccessibilityNodeInfoCaches.size();
+            for (int i = 0; i < cacheCount; i++) {
+                AccessibilityNodeInfoCache cache = mAccessibilityNodeInfoCaches.valueAt(i);
+                cache.onAccessibilityEvent(event);
+            }
+        }
+
+        public void prefetchAccessibilityNodeInfos(long interrogatingPid, View root,
+                List<AccessibilityNodeInfo> outInfos) {
+            addAndCacheNotCachedNodeInfo(interrogatingPid, root, outInfos);
+            addAndCacheNotCachedPredecessorInfos(interrogatingPid, root, outInfos);
+            addAndCacheNotCachedDescendantInfos(interrogatingPid, root, outInfos);
+        }
+
+        private void addAndCacheNotCachedNodeInfo(long interrogatingPid,
+                View view, List<AccessibilityNodeInfo> outInfos) {
+            final long accessibilityNodeId = AccessibilityNodeInfo.makeNodeId(
+                    view.getAccessibilityViewId(), View.NO_ID);
+            AccessibilityNodeInfoCache cache = getCacheForInterrogatingPid(interrogatingPid);
+            if (!cache.containsKey(accessibilityNodeId)) {
+                // Account for the ids of the fetched infos. The infos will be
+                // cached in the window querying process. We just need to know
+                // which infos are cached to avoid fetching a cached one again.
+                cache.put(accessibilityNodeId, null);
+                outInfos.add(view.createAccessibilityNodeInfo());
+            }
+        }
+
+        private void addAndCacheNotCachedPredecessorInfos(long interrogatingPid, View view,
+                List<AccessibilityNodeInfo> outInfos) {
+            ViewParent predecessor = view.getParent();
+            while (predecessor instanceof View
+                    && outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+                View predecessorView = (View) predecessor;
+                addAndCacheNotCachedNodeInfo(interrogatingPid, predecessorView, outInfos);
+                predecessor = predecessor.getParent();
+            }
+        }
+
+        private void addAndCacheNotCachedDescendantInfos(long interrogatingPid, View view,
+                List<AccessibilityNodeInfo> outInfos) {
+            if (outInfos.size() > MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE
+                    || view.getAccessibilityNodeProvider() != null) {
+                return;
+            }
+            addAndCacheNotCachedNodeInfo(interrogatingPid, view, outInfos);
+            if (view instanceof ViewGroup) {
+                ViewGroup rootGroup = (ViewGroup) view;
+                final int childCount = rootGroup.getChildCount();
+                for (int i = 0; i < childCount; i++) {
+                View child = rootGroup.getChildAt(i);
+                    addAndCacheNotCachedDescendantInfos(interrogatingPid, child, outInfos);
+                }
+            }
+        }
+    }
 }
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index d7113374..6bdc4e8 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -490,7 +490,7 @@
 
                     for (int i = 0; i < count; i++) {
                         ViewRootImpl root = mRoots[i];
-                        root.dumpGfxInfo(pw, info);
+                        root.dumpGfxInfo(info);
 
                         String name = root.getClass().getName() + '@' +
                                 Integer.toHexString(hashCode());                        
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 95c070c..072fdd8 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -24,7 +24,9 @@
 import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.SparseArray;
+import android.view.AccessibilityNodeInfoCache;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -97,6 +99,11 @@
     private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache =
         new SparseArray<IAccessibilityServiceConnection>();
 
+    // The connection cache is shared between all interrogating threads since
+    // at any given time there is only one window allowing querying.
+    private static final AccessibilityNodeInfoCache sAccessibilityNodeInfoCache =
+        AccessibilityNodeInfoCache.newSynchronizedAccessibilityNodeInfoCache();
+
     /**
      * @return The client for the current thread.
      */
@@ -145,7 +152,9 @@
      * Finds an {@link AccessibilityNodeInfo} by accessibility id.
      *
      * @param connectionId The id of a connection for interacting with the system.
-     * @param accessibilityWindowId A unique window id.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
      * @param accessibilityNodeId A unique node accessibility id
      *     (accessibility view and virtual descendant id).
      * @return An {@link AccessibilityNodeInfo} if found, null otherwise.
@@ -155,16 +164,22 @@
         try {
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
+                AccessibilityNodeInfo cachedInfo = sAccessibilityNodeInfoCache.get(accessibilityNodeId); 
+                if (cachedInfo != null) {
+                    return cachedInfo;
+                }
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final float windowScale = connection.findAccessibilityNodeInfoByAccessibilityId(
                         accessibilityWindowId, accessibilityNodeId, interactionId, this,
                         Thread.currentThread().getId());
                 // If the scale is zero the call has failed.
                 if (windowScale > 0) {
-                    AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
+                    List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
-                    finalizeAccessibilityNodeInfo(info, connectionId, windowScale);
-                    return info;
+                    finalizeAccessibilityNodeInfos(infos, connectionId, windowScale);
+                    if (infos != null && !infos.isEmpty()) {
+                        return infos.get(0);
+                    }
                 }
             } else {
                 if (DEBUG) {
@@ -181,22 +196,30 @@
     }
 
     /**
-     * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed
-     * in the currently active window and starts from the root View in the window.
+     * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed in
+     * the window whose id is specified and starts from the node whose accessibility
+     * id is specified.
      *
      * @param connectionId The id of a connection for interacting with the system.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id from where to start the search. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+     *     to start from the root.
      * @param viewId The id of the view.
      * @return An {@link AccessibilityNodeInfo} if found, null otherwise.
      */
-    public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int connectionId,
-            int viewId) {
+    public AccessibilityNodeInfo findAccessibilityNodeInfoByViewId(int connectionId,
+            int accessibilityWindowId, long accessibilityNodeId, int viewId) {
         try {
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final float windowScale =
-                    connection.findAccessibilityNodeInfoByViewIdInActiveWindow(viewId,
-                            interactionId, this, Thread.currentThread().getId());
+                    connection.findAccessibilityNodeInfoByViewId(accessibilityWindowId,
+                            accessibilityNodeId, viewId, interactionId, this,
+                            Thread.currentThread().getId());
                 // If the scale is zero the call has failed.
                 if (windowScale > 0) {
                     AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
@@ -220,64 +243,27 @@
 
     /**
      * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
-     * insensitive containment. The search is performed in the currently
-     * active window and starts from the root View in the window.
-     *
-     * @param connectionId The id of a connection for interacting with the system.
-     * @param text The searched text.
-     * @return A list of found {@link AccessibilityNodeInfo}s.
-     */
-    public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByTextInActiveWindow(
-            int connectionId, String text) {
-        try {
-            IAccessibilityServiceConnection connection = getConnection(connectionId);
-            if (connection != null) {
-                final int interactionId = mInteractionIdCounter.getAndIncrement();
-                final float windowScale =
-                    connection.findAccessibilityNodeInfosByTextInActiveWindow(text,
-                            interactionId, this, Thread.currentThread().getId());
-                // If the scale is zero the call has failed.
-                if (windowScale > 0) {
-                    List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
-                            interactionId);
-                    finalizeAccessibilityNodeInfos(infos, connectionId, windowScale);
-                    return infos;
-                }
-            } else {
-                if (DEBUG) {
-                    Log.w(LOG_TAG, "No connection for connection id: " + connectionId);
-                }
-            }
-        } catch (RemoteException re) {
-            if (DEBUG) {
-                Log.w(LOG_TAG, "Error while calling remote"
-                        + " findAccessibilityNodeInfosByViewTextInActiveWindow", re);
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
      * insensitive containment. The search is performed in the window whose
-     * id is specified and starts from the View whose accessibility id is
+     * id is specified and starts from the node whose accessibility id is
      * specified.
      *
      * @param connectionId The id of a connection for interacting with the system.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id from where to start the search. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
      * @param text The searched text.
-     * @param accessibilityWindowId A unique window id.
-     * @param accessibilityNodeId A unique node id (accessibility and virtual descendant id) from
-     *        where to start the search. Use {@link android.view.View#NO_ID} to start from the root.
      * @return A list of found {@link AccessibilityNodeInfo}s.
      */
     public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(int connectionId,
-            String text, int accessibilityWindowId, long accessibilityNodeId) {
+            int accessibilityWindowId, long accessibilityNodeId, String text) {
         try {
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
-                final float windowScale = connection.findAccessibilityNodeInfosByText(text,
-                        accessibilityWindowId, accessibilityNodeId, interactionId, this,
+                final float windowScale = connection.findAccessibilityNodeInfosByText(
+                        accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
                         Thread.currentThread().getId());
                 // If the scale is zero the call has failed.
                 if (windowScale > 0) {
@@ -304,7 +290,9 @@
      * Performs an accessibility action on an {@link AccessibilityNodeInfo}.
      *
      * @param connectionId The id of a connection for interacting with the system.
-     * @param accessibilityWindowId The id of the window.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
      * @param accessibilityNodeId A unique node id (accessibility and virtual descendant id).
      * @param action The action to perform.
      * @return Whether the action was performed.
@@ -319,7 +307,7 @@
                         accessibilityWindowId, accessibilityNodeId, action, interactionId, this,
                         Thread.currentThread().getId());
                 if (success) {
-                    return getPerformAccessibilityActionResult(interactionId);
+                    return getPerformAccessibilityActionResultAndClear(interactionId);
                 }
             } else {
                 if (DEBUG) {
@@ -334,6 +322,24 @@
         return false;
     }
 
+    public void clearCache() {
+        if (DEBUG) {
+            Log.w(LOG_TAG, "clearCache()");
+        }
+        sAccessibilityNodeInfoCache.clear();
+    }
+
+    public void removeCachedNode(long accessibilityNodeId) {
+        if (DEBUG) {
+            Log.w(LOG_TAG, "removeCachedNode(" + accessibilityNodeId +")");
+        }
+        sAccessibilityNodeInfoCache.remove(accessibilityNodeId);
+    }
+
+    public void onAccessibilityEvent(AccessibilityEvent event) {
+        sAccessibilityNodeInfoCache.onAccessibilityEvent(event);
+    }
+
     /**
      * Gets the the result of an async request that returns an {@link AccessibilityNodeInfo}.
      *
@@ -358,6 +364,9 @@
             if (interactionId > mInteractionId) {
                 mFindAccessibilityNodeInfoResult = info;
                 mInteractionId = interactionId;
+                if (info != null) {
+                    sAccessibilityNodeInfoCache.put(info.getSourceNodeId(), info);
+                }
             }
             mInstanceLock.notifyAll();
         }
@@ -386,8 +395,20 @@
                 int interactionId) {
         synchronized (mInstanceLock) {
             if (interactionId > mInteractionId) {
-                mFindAccessibilityNodeInfosResult = infos;
+                // If the call is not an IPC, i.e. it is made from the same process, we need to
+                // instantiate new result list to avoid passing internal instances to clients.
+                final boolean isIpcCall = (queryLocalInterface(getInterfaceDescriptor()) == null);
+                if (!isIpcCall) {
+                    mFindAccessibilityNodeInfosResult = new ArrayList<AccessibilityNodeInfo>(infos);
+                } else {
+                    mFindAccessibilityNodeInfosResult = infos;
+                }
                 mInteractionId = interactionId;
+                final int infoCount = infos.size();
+                for (int i = 0; i < infoCount; i ++) {
+                    AccessibilityNodeInfo info = infos.get(i);
+                    sAccessibilityNodeInfoCache.put(info.getSourceNodeId(), info);
+                }
             }
             mInstanceLock.notifyAll();
         }
@@ -399,7 +420,7 @@
      * @param interactionId The interaction id to match the result with the request.
      * @return Whether the action was performed.
      */
-    private boolean getPerformAccessibilityActionResult(int interactionId) {
+    private boolean getPerformAccessibilityActionResultAndClear(int interactionId) {
         synchronized (mInstanceLock) {
             final boolean success = waitForResultTimedLocked(interactionId);
             final boolean result = success ? mPerformAccessibilityActionResult : false;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 6939c2c..d7d6792 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -380,8 +380,8 @@
             return Collections.emptyList();
         }
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
-        return client.findAccessibilityNodeInfosByText(mConnectionId, text, mWindowId,
-                mSourceNodeId);
+        return client.findAccessibilityNodeInfosByText(mConnectionId, mWindowId, mSourceNodeId,
+                text);
     }
 
     /**
@@ -903,6 +903,17 @@
     }
 
     /**
+     * Gets the id of the source node.
+     *
+     * @return The id.
+     *
+     * @hide
+     */
+    public long getSourceNodeId() {
+        return mSourceNodeId;
+    }
+
+    /**
      * Sets if this instance is sealed.
      *
      * @param sealed Whether is sealed.
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index 07aeb9a..b60f50e 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -564,6 +564,17 @@
     }
 
     /**
+     * Gets the id of the source node.
+     *
+     * @return The id.
+     *
+     * @hide
+     */
+    public long getSourceNodeId() {
+        return mSourceNodeId;
+    }
+
+    /**
      * Sets the unique id of the IAccessibilityServiceConnection over which
      * this instance can send requests to the system.
      *
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
index a90c427..ae6869c 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
@@ -31,13 +31,13 @@
         IAccessibilityInteractionConnectionCallback callback,
         int interrogatingPid, long interrogatingTid);
 
-    void findAccessibilityNodeInfoByViewId(int id, int interactionId,
+    void findAccessibilityNodeInfoByViewId(long accessibilityNodeId, int id, int interactionId,
         IAccessibilityInteractionConnectionCallback callback,
         int interrogatingPid, long interrogatingTid);
 
-    void findAccessibilityNodeInfosByText(String text, long accessibilityNodeId,
-        int interactionId, IAccessibilityInteractionConnectionCallback callback,
-        int interrogatingPid, long interrogatingTid);
+    void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, int interactionId,
+        IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
+        long interrogatingTid);
 
     void performAccessibilityAction(long accessibilityNodeId, int action, int interactionId,
         IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index c3794be..320c75d 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -49,5 +49,7 @@
 
     void removeAccessibilityInteractionConnection(IWindow windowToken);
 
-    void registerEventListener(IEventListener client);
+    void registerUiTestAutomationService(IEventListener listener, in AccessibilityServiceInfo info);
+
+    void unregisterUiTestAutomationService(IEventListener listener);
 }
diff --git a/core/java/android/webkit/Network.java b/core/java/android/webkit/Network.java
index 30bbb04..ee9b949 100644
--- a/core/java/android/webkit/Network.java
+++ b/core/java/android/webkit/Network.java
@@ -169,7 +169,9 @@
             if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction()))
                 return;
 
-            NetworkInfo info = (NetworkInfo)intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
+            final ConnectivityManager connManager = (ConnectivityManager) context
+                    .getSystemService(Context.CONNECTIVITY_SERVICE);
+            final NetworkInfo info = connManager.getActiveNetworkInfo();
             if (info != null)
                 mRoaming = info.isRoaming();
         };
diff --git a/core/java/android/webkit/WebCoreThreadWatchdog.java b/core/java/android/webkit/WebCoreThreadWatchdog.java
index d100260..0541d5d 100644
--- a/core/java/android/webkit/WebCoreThreadWatchdog.java
+++ b/core/java/android/webkit/WebCoreThreadWatchdog.java
@@ -40,9 +40,6 @@
     // WebCore thread unresponsive.
     private static final int TIMED_OUT = 101;
 
-    // Message to tell the Watchdog thread to terminate.
-    private static final int QUIT = 102;
-
     // Wait 10s after hearing back from the WebCore thread before checking it's still alive.
     private static final int HEARTBEAT_PERIOD = 10 * 1000;
 
@@ -57,7 +54,6 @@
     private Handler mWebCoreThreadHandler;
     private Handler mHandler;
     private boolean mPaused;
-    private boolean mPendingQuit;
 
     private static WebCoreThreadWatchdog sInstance;
 
@@ -88,12 +84,6 @@
         }
     }
 
-    public synchronized static void quit() {
-        if (sInstance != null) {
-            sInstance.quitWatchdog();
-        }
-    }
-
     private void setContext(Context context) {
         mContext = context;
     }
@@ -103,19 +93,6 @@
         mWebCoreThreadHandler = webCoreThreadHandler;
     }
 
-    private void quitWatchdog() {
-        if (mHandler == null) {
-            // The thread hasn't started yet, so set a flag to stop it starting.
-            mPendingQuit = true;
-            return;
-        }
-        // Clear any pending messages, and then post a quit to the WatchDog handler.
-        mHandler.removeMessages(TIMED_OUT);
-        mHandler.removeMessages(IS_ALIVE);
-        mWebCoreThreadHandler.removeMessages(EventHub.HEARTBEAT);
-        mHandler.obtainMessage(QUIT).sendToTarget();
-    }
-
     private void pauseWatchdog() {
         mPaused = true;
 
@@ -146,12 +123,8 @@
         mHandler.sendMessageDelayed(mHandler.obtainMessage(TIMED_OUT), TIMEOUT_PERIOD);
     }
 
-    private boolean createHandler() {
+    private void createHandler() {
         synchronized (WebCoreThreadWatchdog.class) {
-            if (mPendingQuit) {
-                return false;
-            }
-
             mHandler = new Handler() {
                 @Override
                 public void handleMessage(Message msg) {
@@ -206,15 +179,9 @@
                             .setIcon(android.R.drawable.ic_dialog_alert)
                             .show();
                         break;
-
-                    case QUIT:
-                        Looper.myLooper().quit();
-                        break;
                     }
                 }
             };
-
-            return true;
         }
     }
 
@@ -222,9 +189,7 @@
     public void run() {
         Looper.prepare();
 
-        if (!createHandler()) {
-            return;
-        }
+        createHandler();
 
         // Send the initial control to WebViewCore and start the timeout timer as long as we aren't
         // paused.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index cc8eef2..4a42e92 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -789,12 +789,18 @@
     // know to handle Shift and arrows natively first
     private boolean mAccessibilityScriptInjected;
 
-    static final boolean USE_JAVA_TEXT_SELECTION = true;
-    static final boolean DEBUG_TEXT_HANDLES = false;
-    private Region mTextSelectionRegion = new Region();
-    private Paint mTextSelectionPaint;
     private Drawable mSelectHandleLeft;
     private Drawable mSelectHandleRight;
+    private Rect mSelectCursorBase = new Rect();
+    private int mSelectCursorBaseLayerId;
+    private Rect mSelectCursorExtent = new Rect();
+    private int mSelectCursorExtentLayerId;
+    private Rect mSelectDraggingCursor;
+    private Point mSelectDraggingOffset = new Point();
+    static final int HANDLE_ID_START = 0;
+    static final int HANDLE_ID_END = 1;
+    static final int HANDLE_ID_BASE = 2;
+    static final int HANDLE_ID_EXTENT = 3;
 
     static boolean sDisableNavcache = false;
     // the color used to highlight the touch rectangles
@@ -2656,12 +2662,6 @@
         return mZoomManager.getScale();
     }
 
-    // Called by JNI. Returns the scale to apply to the text selection handles
-    /* package */ float getTextHandleScale() {
-        float density = mContext.getResources().getDisplayMetrics().density;
-        return density / getScale();
-    }
-
     /**
      * Compute the reading level scale of the WebView
      * @param scale The current scale.
@@ -3852,6 +3852,16 @@
         if (x == mScrollingLayerRect.left && y == mScrollingLayerRect.top) {
             return;
         }
+        if (mSelectingText) {
+            int dx = mScrollingLayerRect.left - x;
+            int dy = mScrollingLayerRect.top - y;
+            if (mSelectCursorBaseLayerId == mCurrentScrollingLayerId) {
+                mSelectCursorBase.offset(dx, dy);
+            }
+            if (mSelectCursorExtentLayerId == mCurrentScrollingLayerId) {
+                mSelectCursorExtent.offset(dx, dy);
+            }
+        }
         nativeScrollLayer(mCurrentScrollingLayerId, x, y);
         mScrollingLayerRect.left = x;
         mScrollingLayerRect.top = y;
@@ -4624,12 +4634,7 @@
      * Select the word at the indicated content coordinates.
      */
     boolean selectText(int x, int y) {
-        if (!setUpSelect(true, x, y)) {
-            return false;
-        }
-        nativeSetExtendSelection();
-        mDrawSelectionPointer = false;
-        mTouchMode = TOUCH_DRAG_MODE;
+        mWebViewCore.sendMessage(EventHub.SELECT_WORD_AT, x, y);
         return true;
     }
 
@@ -4830,11 +4835,8 @@
         int extras = DRAW_EXTRAS_NONE;
         if (mFindIsUp) {
             extras = DRAW_EXTRAS_FIND;
-        } else if (mSelectingText && (!USE_JAVA_TEXT_SELECTION || DEBUG_TEXT_HANDLES)) {
+        } else if (mSelectingText) {
             extras = DRAW_EXTRAS_SELECTION;
-            nativeSetSelectionPointer(mNativeClass,
-                    mDrawSelectionPointer,
-                    mZoomManager.getInvScale(), mSelectX, mSelectY - getTitleHeight());
         } else if (drawCursorRing) {
             extras = DRAW_EXTRAS_CURSOR_RING;
         }
@@ -4879,7 +4881,7 @@
         }
 
         canvas.restoreToCount(saveCount);
-        if (mSelectingText && USE_JAVA_TEXT_SELECTION) {
+        if (mSelectingText) {
             drawTextSelectionHandles(canvas);
         }
 
@@ -4901,30 +4903,12 @@
     }
 
     private void drawTextSelectionHandles(Canvas canvas) {
-        if (mTextSelectionPaint == null) {
-            mTextSelectionPaint = new Paint();
-            mTextSelectionPaint.setColor(HIGHLIGHT_COLOR);
-        }
-        mTextSelectionRegion.setEmpty();
-        nativeGetTextSelectionRegion(mNativeClass, mTextSelectionRegion);
-        Rect r = new Rect();
-        RegionIterator iter = new RegionIterator(mTextSelectionRegion);
-        Rect clip = canvas.getClipBounds();
-        while (iter.next(r)) {
-            r.set(contentToViewDimension(r.left),
-                    contentToViewDimension(r.top),
-                    contentToViewDimension(r.right),
-                    contentToViewDimension(r.bottom));
-            if (r.intersect(clip)) {
-                canvas.drawRect(r, mTextSelectionPaint);
-            }
-        }
         if (mSelectHandleLeft == null) {
             mSelectHandleLeft = mContext.getResources().getDrawable(
                     com.android.internal.R.drawable.text_select_handle_left);
         }
         int[] handles = new int[4];
-        nativeGetSelectionHandles(mNativeClass, handles);
+        getSelectionHandles(handles);
         int start_x = contentToViewDimension(handles[0]);
         int start_y = contentToViewDimension(handles[1]);
         int end_x = contentToViewDimension(handles[2]);
@@ -4942,14 +4926,31 @@
         mSelectHandleRight.setBounds(end_x, end_y,
                 end_x + mSelectHandleRight.getIntrinsicWidth(),
                 end_y + mSelectHandleRight.getIntrinsicHeight());
-        if (DEBUG_TEXT_HANDLES) {
-            mSelectHandleLeft.setAlpha(125);
-            mSelectHandleRight.setAlpha(125);
-        }
         mSelectHandleLeft.draw(canvas);
         mSelectHandleRight.draw(canvas);
     }
 
+    /**
+     * Takes an int[4] array as an output param with the values being
+     * startX, startY, endX, endY
+     */
+    private void getSelectionHandles(int[] handles) {
+        handles[0] = mSelectCursorBase.right;
+        handles[1] = mSelectCursorBase.bottom -
+                (mSelectCursorBase.height() / 4);
+        handles[2] = mSelectCursorExtent.left;
+        handles[3] = mSelectCursorExtent.bottom
+                - (mSelectCursorExtent.height() / 4);
+        if (!nativeIsBaseFirst(mNativeClass)) {
+            int swap = handles[0];
+            handles[0] = handles[2];
+            handles[2] = swap;
+            swap = handles[1];
+            handles[1] = handles[3];
+            handles[3] = swap;
+        }
+    }
+
     // draw history
     private boolean mDrawHistory = false;
     private Picture mHistoryPicture = null;
@@ -5009,7 +5010,7 @@
     /* package */ void deleteSelection(int start, int end) {
         mTextGeneration++;
         WebViewCore.TextSelectionData data
-                = new WebViewCore.TextSelectionData(start, end);
+                = new WebViewCore.TextSelectionData(start, end, 0);
         mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, mTextGeneration, 0,
                 data);
     }
@@ -5462,15 +5463,6 @@
                         return pinScrollTo(mContentWidth, mScrollY, true, 0);
                 }
             }
-            if (mSelectingText) {
-                int xRate = keyCode == KeyEvent.KEYCODE_DPAD_LEFT
-                    ? -1 : keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ? 1 : 0;
-                int yRate = keyCode == KeyEvent.KEYCODE_DPAD_UP ?
-                    -1 : keyCode == KeyEvent.KEYCODE_DPAD_DOWN ? 1 : 0;
-                int multiplier = event.getRepeatCount() + 1;
-                moveSelection(xRate * multiplier, yRate * multiplier);
-                return true;
-            }
             if (navHandledKey(keyCode, 1, false, event.getEventTime())) {
                 playSoundEffect(keyCodeToSoundsEffect(keyCode));
                 return true;
@@ -5623,14 +5615,8 @@
             mGotCenterDown = false;
 
             if (mSelectingText) {
-                if (mExtendSelection) {
-                    copySelection();
-                    selectionDone();
-                } else {
-                    mExtendSelection = true;
-                    nativeSetExtendSelection();
-                    invalidate(); // draw the i-beam instead of the arrow
-                }
+                copySelection();
+                selectionDone();
                 return true; // discard press if copy in progress
             }
 
@@ -5676,21 +5662,7 @@
         return false;
     }
 
-    /*
-     * Enter selecting text mode, and see if CAB should be shown.
-     * Returns true if the WebView is now in
-     * selecting text mode (including if it was already in that mode, and this
-     * method did nothing).
-     */
-    private boolean setUpSelect(boolean selectWord, int x, int y) {
-        if (0 == mNativeClass) return false; // client isn't initialized
-        if (inFullScreenMode()) return false;
-        if (mSelectingText) return true;
-        nativeResetSelection();
-        if (selectWord && !nativeWordSelection(x, y)) {
-            selectionDone();
-            return false;
-        }
+    private boolean startSelectActionMode() {
         mSelectCallback = new SelectActionModeCallback();
         mSelectCallback.setWebView(this);
         if (startActionMode(mSelectCallback) == null) {
@@ -5699,54 +5671,43 @@
             selectionDone();
             return false;
         }
-        mExtendSelection = false;
-        mSelectingText = mDrawSelectionPointer = true;
-        if (DEBUG_TEXT_HANDLES) {
-            // Debugging text handles requires running in software mode
-            setLayerType(LAYER_TYPE_SOFTWARE, null);
-        }
-        // don't let the picture change during text selection
-        WebViewCore.pauseUpdatePicture(mWebViewCore);
-        if (nativeHasCursorNode()) {
-            Rect rect = nativeCursorNodeBounds();
-            mSelectX = contentToViewX(rect.left);
-            mSelectY = contentToViewY(rect.top);
-        } else if (mLastTouchY > getVisibleTitleHeightImpl()) {
-            mSelectX = mScrollX + mLastTouchX;
-            mSelectY = mScrollY + mLastTouchY;
-        } else {
-            mSelectX = mScrollX + getViewWidth() / 2;
-            mSelectY = mScrollY + getViewHeightWithTitle() / 2;
-        }
-        nativeHideCursor();
-        mMinAutoScrollX = 0;
-        mMaxAutoScrollX = getViewWidth();
-        mMinAutoScrollY = 0;
-        mMaxAutoScrollY = getViewHeightWithTitle();
-        mCurrentScrollingLayerId = nativeScrollableLayer(viewToContentX(mSelectX),
-                viewToContentY(mSelectY), mScrollingLayerRect,
-                mScrollingLayerBounds);
-        if (mCurrentScrollingLayerId != 0) {
-            if (mScrollingLayerRect.left != mScrollingLayerRect.right) {
-                mMinAutoScrollX = Math.max(mMinAutoScrollX,
-                        contentToViewX(mScrollingLayerBounds.left));
-                mMaxAutoScrollX = Math.min(mMaxAutoScrollX,
-                        contentToViewX(mScrollingLayerBounds.right));
-            }
-            if (mScrollingLayerRect.top != mScrollingLayerRect.bottom) {
-                mMinAutoScrollY = Math.max(mMinAutoScrollY,
-                        contentToViewY(mScrollingLayerBounds.top));
-                mMaxAutoScrollY = Math.min(mMaxAutoScrollY,
-                        contentToViewY(mScrollingLayerBounds.bottom));
-            }
-        }
-        mMinAutoScrollX += SELECT_SCROLL;
-        mMaxAutoScrollX -= SELECT_SCROLL;
-        mMinAutoScrollY += SELECT_SCROLL;
-        mMaxAutoScrollY -= SELECT_SCROLL;
+        performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
         return true;
     }
 
+    private void syncSelectionCursors() {
+        mSelectCursorBaseLayerId =
+                nativeGetHandleLayerId(mNativeClass, HANDLE_ID_BASE, mSelectCursorBase);
+        mSelectCursorExtentLayerId =
+                nativeGetHandleLayerId(mNativeClass, HANDLE_ID_EXTENT, mSelectCursorExtent);
+    }
+
+    private boolean setupWebkitSelect() {
+        syncSelectionCursors();
+        if (!startSelectActionMode()) {
+            selectionDone();
+            return false;
+        }
+        mSelectingText = true;
+        mTouchMode = TOUCH_DRAG_MODE;
+        return true;
+    }
+
+    private void updateWebkitSelection() {
+        int[] handles = null;
+        if (mSelectingText) {
+            handles = new int[4];
+            handles[0] = mSelectCursorBase.centerX();
+            handles[1] = mSelectCursorBase.centerY();
+            handles[2] = mSelectCursorExtent.centerX();
+            handles[3] = mSelectCursorExtent.centerY();
+        } else {
+            nativeSetTextSelection(mNativeClass, 0);
+        }
+        mWebViewCore.removeMessages(EventHub.SELECT_TEXT);
+        mWebViewCore.sendMessageAtFrontOfQueue(EventHub.SELECT_TEXT, handles);
+    }
+
     /**
      * Use this method to put the WebView into text selection mode.
      * Do not rely on this functionality; it will be deprecated in the future.
@@ -5755,7 +5716,6 @@
     @Deprecated
     public void emulateShiftHeld() {
         checkThread();
-        setUpSelect(false, 0, 0);
     }
 
     /**
@@ -5764,17 +5724,7 @@
      * @hide This is an implementation detail.
      */
     public void selectAll() {
-        if (0 == mNativeClass) return; // client isn't initialized
-        if (inFullScreenMode()) return;
-        if (!mSelectingText) {
-            // retrieve a point somewhere within the text
-            Point select = nativeSelectableText();
-            if (!selectText(select.x, select.y)) return;
-        }
-        nativeSelectAll();
-        mDrawSelectionPointer = false;
-        mExtendSelection = true;
-        invalidate();
+        mWebViewCore.sendMessage(EventHub.SELECT_ALL);
     }
 
     /**
@@ -5783,17 +5733,11 @@
     void selectionDone() {
         if (mSelectingText) {
             mSelectingText = false;
-            if (DEBUG_TEXT_HANDLES) {
-                // Debugging text handles required running in software mode, set
-                // back to default now
-                setLayerType(LAYER_TYPE_NONE, null);
-            }
             // finish is idempotent, so this is fine even if selectionDone was
             // called by mSelectCallback.onDestroyActionMode
             mSelectCallback.finish();
             mSelectCallback = null;
-            WebViewCore.resumePriority();
-            WebViewCore.resumeUpdatePicture(mWebViewCore);
+            updateWebkitSelection();
             invalidate(); // redraw without selection
             mAutoScrollX = 0;
             mAutoScrollY = 0;
@@ -5821,7 +5765,7 @@
                     .getSystemService(Context.CLIPBOARD_SERVICE);
             cm.setText(selection);
             int[] handles = new int[4];
-            nativeGetSelectionHandles(mNativeClass, handles);
+            getSelectionHandles(handles);
             mWebViewCore.sendMessage(EventHub.COPY_TEXT, handles);
         }
         invalidate(); // remove selection region and pointer
@@ -5836,7 +5780,7 @@
     public void cutSelection() {
         copySelection();
         int[] handles = new int[4];
-        nativeGetSelectionHandles(mNativeClass, handles);
+        getSelectionHandles(handles);
         mWebViewCore.sendMessage(EventHub.DELETE_TEXT, handles);
     }
 
@@ -5854,7 +5798,7 @@
             CharSequence pasteText = clipItem.getText();
             if (pasteText != null) {
                 int[] handles = new int[4];
-                nativeGetSelectionHandles(mNativeClass, handles);
+                getSelectionHandles(handles);
                 mWebViewCore.sendMessage(EventHub.DELETE_TEXT, handles);
                 mWebViewCore.sendMessage(EventHub.INSERT_TEXT,
                         pasteText.toString());
@@ -6406,13 +6350,28 @@
                         EventLog.writeEvent(EventLogTags.BROWSER_DOUBLE_TAP_DURATION,
                                 (eventTime - mLastTouchUpTime), eventTime);
                     }
-                    if (mSelectingText) {
-                        mDrawSelectionPointer = false;
-                        mSelectionStarted = nativeStartSelection(contentX, contentY);
+                    mSelectionStarted = false;
+                    if (mSelectingText && mSelectHandleLeft != null
+                            && mSelectHandleRight != null) {
+                        int shiftedY = y - getTitleHeight() + mScrollY;
+                        int shiftedX = x + mScrollX;
+                        if (mSelectHandleLeft.getBounds()
+                                .contains(shiftedX, shiftedY)) {
+                            mSelectionStarted = true;
+                            mSelectDraggingCursor = mSelectCursorBase;
+                        } else if (mSelectHandleRight.getBounds()
+                                .contains(shiftedX, shiftedY)) {
+                            mSelectionStarted = true;
+                            mSelectDraggingCursor = mSelectCursorExtent;
+                        }
+                        if (mSelectDraggingCursor != null) {
+                            mSelectDraggingOffset.set(
+                                    mSelectDraggingCursor.left - contentX,
+                                    mSelectDraggingCursor.top - contentY);
+                        }
                         if (DebugFlags.WEB_VIEW) {
                             Log.v(LOGTAG, "select=" + contentX + "," + contentY);
                         }
-                        invalidate();
                     }
                 }
                 // Trigger the link
@@ -6478,6 +6437,26 @@
                         removeTouchHighlight();
                     }
                 }
+                if (mSelectingText && mSelectionStarted) {
+                    if (DebugFlags.WEB_VIEW) {
+                        Log.v(LOGTAG, "extend=" + contentX + "," + contentY);
+                    }
+                    ViewParent parent = getParent();
+                    if (parent != null) {
+                        parent.requestDisallowInterceptTouchEvent(true);
+                    }
+                    if (deltaX != 0 || deltaY != 0) {
+                        mSelectDraggingCursor.offsetTo(
+                                contentX + mSelectDraggingOffset.x,
+                                contentY + mSelectDraggingOffset.y);
+                        updateWebkitSelection();
+                        mLastTouchX = x;
+                        mLastTouchY = y;
+                        invalidate();
+                    }
+                    break;
+                }
+
                 // pass the touch events from UI thread to WebCore thread
                 if (shouldForwardTouchEvent() && mConfirmMove && (firstMove
                         || eventTime - mLastSentTouchTime > mCurrentTouchInterval)) {
@@ -6520,30 +6499,6 @@
                 } else {
                     mVelocityTracker.addMovement(ev);
                 }
-                if (mSelectingText && mSelectionStarted) {
-                    if (DebugFlags.WEB_VIEW) {
-                        Log.v(LOGTAG, "extend=" + contentX + "," + contentY);
-                    }
-                    ViewParent parent = getParent();
-                    if (parent != null) {
-                        parent.requestDisallowInterceptTouchEvent(true);
-                    }
-                    mAutoScrollX = x <= mMinAutoScrollX ? -SELECT_SCROLL
-                            : x >= mMaxAutoScrollX ? SELECT_SCROLL : 0;
-                    mAutoScrollY = y <= mMinAutoScrollY ? -SELECT_SCROLL
-                            : y >= mMaxAutoScrollY ? SELECT_SCROLL : 0;
-                    if ((mAutoScrollX != 0 || mAutoScrollY != 0)
-                            && !mSentAutoScrollMessage) {
-                        mSentAutoScrollMessage = true;
-                        mPrivateHandler.sendEmptyMessageDelayed(
-                                SCROLL_SELECT_TEXT, SELECT_SCROLL_INTERVAL);
-                    }
-                    if (deltaX != 0 || deltaY != 0) {
-                        nativeExtendSelection(contentX, contentY);
-                        invalidate();
-                    }
-                    break;
-                }
 
                 if (mTouchMode != TOUCH_DRAG_MODE &&
                         mTouchMode != TOUCH_DRAG_LAYER_MODE) {
@@ -6758,7 +6713,7 @@
                         } else {
                             if (mSelectingText) {
                                 // tapping on selection or controls does nothing
-                                if (!nativeHitSelection(contentX, contentY)) {
+                                if (!mSelectionStarted) {
                                     selectionDone();
                                 }
                                 break;
@@ -7055,6 +7010,12 @@
         if (mOverScrollGlow != null) {
             mOverScrollGlow.releaseAll();
         }
+
+        if (mSelectingText) {
+            mSelectionStarted = false;
+            syncSelectionCursors();
+            invalidate();
+        }
     }
 
     private void cancelTouch() {
@@ -7119,8 +7080,6 @@
     private int mTrackballYMove = 0;
     private boolean mSelectingText = false;
     private boolean mSelectionStarted = false;
-    private boolean mExtendSelection = false;
-    private boolean mDrawSelectionPointer = false;
     private static final int TRACKBALL_KEY_TIMEOUT = 1000;
     private static final int TRACKBALL_TIMEOUT = 200;
     private static final int TRACKBALL_WAIT = 100;
@@ -7189,14 +7148,8 @@
             mTrackballDown = false;
             mTrackballUpTime = time;
             if (mSelectingText) {
-                if (mExtendSelection) {
-                    copySelection();
-                    selectionDone();
-                } else {
-                    mExtendSelection = true;
-                    nativeSetExtendSelection();
-                    invalidate(); // draw the i-beam instead of the arrow
-                }
+                copySelection();
+                selectionDone();
                 return true; // discard press if copy in progress
             }
             if (DebugFlags.WEB_VIEW) {
@@ -7239,42 +7192,6 @@
         return true;
     }
 
-    void moveSelection(float xRate, float yRate) {
-        if (mNativeClass == 0)
-            return;
-        int width = getViewWidth();
-        int height = getViewHeight();
-        mSelectX += xRate;
-        mSelectY += yRate;
-        int maxX = width + mScrollX;
-        int maxY = height + mScrollY;
-        mSelectX = Math.min(maxX, Math.max(mScrollX - SELECT_CURSOR_OFFSET
-                , mSelectX));
-        mSelectY = Math.min(maxY, Math.max(mScrollY - SELECT_CURSOR_OFFSET
-                , mSelectY));
-        if (DebugFlags.WEB_VIEW) {
-            Log.v(LOGTAG, "moveSelection"
-                    + " mSelectX=" + mSelectX
-                    + " mSelectY=" + mSelectY
-                    + " mScrollX=" + mScrollX
-                    + " mScrollY=" + mScrollY
-                    + " xRate=" + xRate
-                    + " yRate=" + yRate
-                    );
-        }
-        nativeMoveSelection(viewToContentX(mSelectX), viewToContentY(mSelectY));
-        int scrollX = mSelectX < mScrollX ? -SELECT_CURSOR_OFFSET
-                : mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
-                : 0;
-        int scrollY = mSelectY < mScrollY ? -SELECT_CURSOR_OFFSET
-                : mSelectY > maxY - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
-                : 0;
-        pinScrollBy(scrollX, scrollY, true, 0);
-        Rect select = new Rect(mSelectX, mSelectY, mSelectX + 1, mSelectY + 1);
-        requestRectangleOnScreen(select);
-        invalidate();
-   }
-
     private int scaleTrackballX(float xRate, int width) {
         int xMove = (int) (xRate / TRACKBALL_SCALE * width);
         int nextXMove = xMove;
@@ -7328,21 +7245,6 @@
         float yRate = mTrackballRemainsY * 1000 / elapsed;
         int viewWidth = getViewWidth();
         int viewHeight = getViewHeight();
-        if (mSelectingText) {
-            if (!mDrawSelectionPointer) {
-                // The last selection was made by touch, disabling drawing the
-                // selection pointer. Allow the trackball to adjust the
-                // position of the touch control.
-                mSelectX = contentToViewX(nativeSelectionX());
-                mSelectY = contentToViewY(nativeSelectionY());
-                mDrawSelectionPointer = mExtendSelection = true;
-                nativeSetExtendSelection();
-            }
-            moveSelection(scaleTrackballX(xRate, viewWidth),
-                    scaleTrackballY(yRate, viewHeight));
-            mTrackballRemainsX = mTrackballRemainsY = 0;
-            return;
-        }
         float ax = Math.abs(xRate);
         float ay = Math.abs(yRate);
         float maxA = Math.max(ax, ay);
@@ -9204,6 +9106,18 @@
                 mInputConnection.setSelection(data.mStart, data.mEnd);
             }
         }
+
+        nativeSetTextSelection(mNativeClass, data.mSelectTextPtr);
+        if (data.mSelectTextPtr != 0) {
+            if (!mSelectingText) {
+                setupWebkitSelect();
+            } else if (!mSelectionStarted) {
+                syncSelectionCursors();
+            }
+        } else {
+            selectionDone();
+        }
+        invalidate();
     }
 
     // Class used to use a dropdown for a <select> element
@@ -9952,7 +9866,6 @@
     private native boolean  nativeMoveCursor(int keyCode, int count,
             boolean noScroll);
     private native int      nativeMoveGeneration();
-    private native void     nativeMoveSelection(int x, int y);
     /**
      * @return true if the page should get the shift and arrow keys, rather
      * than select text/navigation.
@@ -9962,15 +9875,8 @@
      */
     private native boolean  nativePageShouldHandleShiftAndArrows();
     private native boolean  nativePointInNavCache(int x, int y, int slop);
-    // Like many other of our native methods, you must make sure that
-    // mNativeClass is not null before calling this method.
-    private native void     nativeResetSelection();
-    private native Point    nativeSelectableText();
-    private native void     nativeSelectAll();
     private native void     nativeSelectBestAt(Rect rect);
     private native void     nativeSelectAt(int x, int y);
-    private native int      nativeSelectionX();
-    private native int      nativeSelectionY();
     private native int      nativeFindIndex();
     private native void     nativeSetExtendSelection();
     private native void     nativeSetFindIsEmpty();
@@ -10026,12 +9932,14 @@
     private native int      nativeGetBackgroundColor();
     native boolean  nativeSetProperty(String key, String value);
     native String   nativeGetProperty(String key);
-    private native void     nativeGetTextSelectionRegion(int instance, Region region);
-    private native void     nativeGetSelectionHandles(int instance, int[] handles);
     /**
      * See {@link ComponentCallbacks2} for the trim levels and descriptions
      */
     private static native void     nativeOnTrimMemory(int level);
     private static native void nativeSetPauseDrawing(int instance, boolean pause);
     private static native boolean nativeDisableNavcache();
+    private static native void nativeSetTextSelection(int instance, int selection);
+    private static native int nativeGetHandleLayerId(int instance, int handle,
+            Rect cursorLocation);
+    private static native boolean nativeIsBaseFirst(int instance);
 }
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index fe51581..395a638 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -835,12 +835,14 @@
     }
 
     static class TextSelectionData {
-        public TextSelectionData(int start, int end) {
+        public TextSelectionData(int start, int end, int selectTextPtr) {
             mStart = start;
             mEnd = end;
+            mSelectTextPtr = selectTextPtr;
         }
         int mStart;
         int mEnd;
+        int mSelectTextPtr;
     }
 
     static class TouchUpData {
@@ -1118,6 +1120,9 @@
         static final int COPY_TEXT = 210;
         static final int DELETE_TEXT = 211;
         static final int INSERT_TEXT = 212;
+        static final int SELECT_TEXT = 213;
+        static final int SELECT_WORD_AT = 214;
+        static final int SELECT_ALL = 215;
 
         // Private handler for WebCore messages.
         private Handler mHandler;
@@ -1194,7 +1199,6 @@
                                 mSettings.onDestroyed();
                                 mNativeClass = 0;
                                 mWebView = null;
-                                WebCoreThreadWatchdog.quit();
                             }
                             break;
 
@@ -1747,6 +1751,25 @@
                         case INSERT_TEXT:
                             nativeInsertText(mNativeClass, (String) msg.obj);
                             break;
+                        case SELECT_TEXT: {
+                            int[] args = (int[]) msg.obj;
+                            if (args == null) {
+                                nativeClearTextSelection(mNativeClass);
+                            } else {
+                                nativeSelectText(mNativeClass, args[0],
+                                        args[1], args[2], args[3]);
+                            }
+                            break;
+                        }
+                        case SELECT_WORD_AT: {
+                            int x = msg.arg1;
+                            int y = msg.arg2;
+                            nativeSelectWordAt(mNativeClass, x, y);
+                            break;
+                        }
+                        case SELECT_ALL:
+                            nativeSelectAll(mNativeClass);
+                            break;
                     }
                 }
             };
@@ -2700,11 +2723,11 @@
 
     // called by JNI
     private void updateTextSelection(int pointer, int start, int end,
-            int textGeneration) {
+            int textGeneration, int selectionPtr) {
         if (mWebView != null) {
             Message.obtain(mWebView.mPrivateHandler,
                 WebView.UPDATE_TEXT_SELECTION_MSG_ID, pointer, textGeneration,
-                new TextSelectionData(start, end)).sendToTarget();
+                new TextSelectionData(start, end, selectionPtr)).sendToTarget();
         }
     }
 
@@ -2771,7 +2794,7 @@
         if (mWebView != null) {
             Message.obtain(mWebView.mPrivateHandler,
                     WebView.REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID, pointer,
-                    textGeneration, new TextSelectionData(selStart, selEnd))
+                    textGeneration, new TextSelectionData(selStart, selEnd, 0))
                     .sendToTarget();
         }
     }
@@ -3026,4 +3049,9 @@
      */
     private native String nativeGetText(int nativeClass,
             int startX, int startY, int endX, int endY);
+    private native void nativeSelectText(int nativeClass,
+            int startX, int startY, int endX, int endY);
+    private native void nativeClearTextSelection(int nativeClass);
+    private native void nativeSelectWordAt(int nativeClass, int x, int y);
+    private native void nativeSelectAll(int nativeClass);
 }
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 7d58011..984ec79 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -842,9 +842,11 @@
      * @hide
      */
     @Override
-    protected void onChildVisibilityChanged(View child, int visibility) {
-        super.onChildVisibilityChanged(child, visibility);
-        invalidateStructure();
+    protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
+        super.onChildVisibilityChanged(child, oldVisibility, newVisibility);
+        if (oldVisibility == GONE || newVisibility == GONE) {
+            invalidateStructure();
+        }
     }
 
     // Measurement
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index e20d12a..67fd059 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1651,6 +1651,7 @@
                 // are focusable
                 if (mItemsCanFocus && hasFocus() && !sel.hasFocus()) {
                     final boolean focusWasTaken = (sel == focusLayoutRestoreDirectChild &&
+                            focusLayoutRestoreView != null &&
                             focusLayoutRestoreView.requestFocus()) || sel.requestFocus();
                     if (!focusWasTaken) {
                         // selected item didn't take focus, fine, but still want
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index d395fb2..84e86af 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -56,13 +56,13 @@
 /**
  * A widget that enables the user to select a number form a predefined range.
  * The widget presents an input field and up and down buttons for selecting the
- * current value. Pressing/long pressing the up and down buttons increments and
+ * current value. Pressing/long-pressing the up and down buttons increments and
  * decrements the current value respectively. Touching the input field shows a
- * scroll wheel, tapping on which while shown and not moving allows direct edit
- * of the current value. Sliding motions up or down hide the buttons and the
- * input field, show the scroll wheel, and rotate the latter. Flinging is
+ * scroll wheel, which when touched allows direct edit
+ * of the current value. Sliding gestures up or down hide the buttons and the
+ * input filed, show and rotate the scroll wheel. Flinging is
  * also supported. The widget enables mapping from positions to strings such
- * that instead the position index the corresponding string is displayed.
+ * that, instead of the position index, the corresponding string is displayed.
  * <p>
  * For an example of using this widget, see {@link android.widget.TimePicker}.
  * </p>
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 40d8a77..164bc64 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -256,10 +256,7 @@
 
     private float mShadowRadius, mShadowDx, mShadowDy;
 
-    private static final int PREDRAW_NOT_REGISTERED = 0;
-    private static final int PREDRAW_PENDING = 1;
-    private static final int PREDRAW_DONE = 2;
-    private int mPreDrawState = PREDRAW_NOT_REGISTERED;
+    private boolean mPreDrawRegistered;
 
     private TextUtils.TruncateAt mEllipsize = null;
 
@@ -365,8 +362,6 @@
 
     private SpellChecker mSpellChecker;
 
-    private boolean mSoftInputShownOnFocus = true;
-
     // The alignment to pass to Layout, or null if not resolved.
     private Layout.Alignment mLayoutAlignment;
 
@@ -2384,29 +2379,6 @@
     }
 
     /**
-     * Sets whether the soft input method will be made visible when this
-     * TextView gets focused. The default is true.
-     *
-     * @attr ref android.R.styleable#TextView_softInputShownOnFocus
-     * @hide
-     */
-    @android.view.RemotableViewMethod
-    public final void setSoftInputShownOnFocus(boolean show) {
-        mSoftInputShownOnFocus = show;
-    }
-
-    /**
-     * Returns whether the soft input method will be made visible when this
-     * TextView gets focused. The default is true.
-     *
-     * @attr ref android.R.styleable#TextView_softInputShownOnFocus
-     * @hide
-     */
-    public final boolean getSoftInputShownOnFocus() {
-        return mSoftInputShownOnFocus;
-    }
-
-    /**
      * Returns the list of URLSpans attached to the text
      * (by {@link Linkify} or otherwise) if any.  You can call
      * {@link URLSpan#getURL} on them to find where they link to
@@ -4387,26 +4359,16 @@
     }
 
     private void registerForPreDraw() {
-        final ViewTreeObserver observer = getViewTreeObserver();
-
-        if (mPreDrawState == PREDRAW_NOT_REGISTERED) {
-            observer.addOnPreDrawListener(this);
-            mPreDrawState = PREDRAW_PENDING;
-        } else if (mPreDrawState == PREDRAW_DONE) {
-            mPreDrawState = PREDRAW_PENDING;
+        if (!mPreDrawRegistered) {
+            getViewTreeObserver().addOnPreDrawListener(this);
+            mPreDrawRegistered = true;
         }
-
-        // else state is PREDRAW_PENDING, so keep waiting.
     }
 
     /**
      * {@inheritDoc}
      */
     public boolean onPreDraw() {
-        if (mPreDrawState != PREDRAW_PENDING) {
-            return true;
-        }
-
         if (mLayout == null) {
             assumeLayout();
         }
@@ -4457,7 +4419,9 @@
             startSelectionActionMode();
         }
 
-        mPreDrawState = PREDRAW_DONE;
+        getViewTreeObserver().removeOnPreDrawListener(this);
+        mPreDrawRegistered = false;
+
         return !changed;
     }
 
@@ -4492,10 +4456,9 @@
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
 
-        final ViewTreeObserver observer = getViewTreeObserver();
-        if (mPreDrawState != PREDRAW_NOT_REGISTERED) {
-            observer.removeOnPreDrawListener(this);
-            mPreDrawState = PREDRAW_NOT_REGISTERED;
+        if (mPreDrawRegistered) {
+            getViewTreeObserver().removeOnPreDrawListener(this);
+            mPreDrawRegistered = false;
         }
 
         if (mError != null) {
@@ -4768,12 +4731,6 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
-        if (mPreDrawState == PREDRAW_DONE) {
-            final ViewTreeObserver observer = getViewTreeObserver();
-            observer.removeOnPreDrawListener(this);
-            mPreDrawState = PREDRAW_NOT_REGISTERED;
-        }
-
         if (mCurrentAlpha <= ViewConfiguration.ALPHA_THRESHOLD_INT) return;
 
         restartMarqueeIfNeeded();
@@ -5040,7 +4997,7 @@
             if (mTextDisplayList == null || !mTextDisplayList.isValid() ||
                     !mTextDisplayListIsValid) {
                 if (mTextDisplayList == null) {
-                    mTextDisplayList = getHardwareRenderer().createDisplayList();
+                    mTextDisplayList = getHardwareRenderer().createDisplayList("Text");
                 }
 
                 final HardwareCanvas hardwareCanvas = mTextDisplayList.start();
@@ -5539,7 +5496,7 @@
                                 && mLayout != null && onCheckIsTextEditor()) {
                             InputMethodManager imm = InputMethodManager.peekInstance();
                             viewClicked(imm);
-                            if (imm != null && mSoftInputShownOnFocus) {
+                            if (imm != null) {
                                 imm.showSoftInput(this, 0);
                             }
                         }
@@ -8395,7 +8352,7 @@
                 // Show the IME, except when selecting in read-only text.
                 final InputMethodManager imm = InputMethodManager.peekInstance();
                 viewClicked(imm);
-                if (!mTextIsSelectable && mSoftInputShownOnFocus) {
+                if (!mTextIsSelectable) {
                     handled |= imm != null && imm.showSoftInput(this, 0);
                 }
 
@@ -10190,7 +10147,7 @@
         }
 
         final boolean selectionStarted = mSelectionActionMode != null || willExtract;
-        if (selectionStarted && !mTextIsSelectable && mSoftInputShownOnFocus) {
+        if (selectionStarted && !mTextIsSelectable) {
             // Show the IME to be able to replace text, except when selecting non editable text.
             final InputMethodManager imm = InputMethodManager.peekInstance();
             if (imm != null) {
diff --git a/core/java/com/android/internal/util/FastMath.java b/core/java/com/android/internal/util/FastMath.java
index efd0871..88a17e6 100644
--- a/core/java/com/android/internal/util/FastMath.java
+++ b/core/java/com/android/internal/util/FastMath.java
@@ -26,8 +26,8 @@
      * thought it may return slightly different results. It does not try to
      * handle (in any meaningful way) NaN or infinities.
      */
-    public static int round(float x) {
-        long lx = (long)(x * (65536 * 256f));
-        return (int)((lx + 0x800000) >> 24);
+    public static int round(float value) {
+        long lx = (long) (value * (65536 * 256f));
+        return (int) ((lx + 0x800000) >> 24);
     }
 }
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index ebd355a..d51ced11 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -653,6 +653,7 @@
 
             case MotionEvent.ACTION_CANCEL:
                 handleMove(event);
+                handleCancel(event);
                 handled = true;
                 break;
         }
@@ -678,6 +679,12 @@
         if (DEBUG && mDragging) Log.v(TAG, "** Handle RELEASE");
         switchToState(STATE_FINISH, event.getX(), event.getY());
     }
+    
+    private void handleCancel(MotionEvent event) {
+        if (DEBUG && mDragging) Log.v(TAG, "** Handle CANCEL");
+        mActiveTarget = -1; // Drop the active target if canceled.
+        switchToState(STATE_FINISH, event.getX(), event.getY());
+    }
 
     private void handleMove(MotionEvent event) {
         if (!mDragging) {
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 6a533c0..e19bb38 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -188,6 +188,14 @@
     renderer->finish();
 }
 
+static jint android_view_GLES20Canvas_getStencilSize(JNIEnv* env, jobject clazz) {
+    return OpenGLRenderer::getStencilSize();
+}
+
+// ----------------------------------------------------------------------------
+// Functor
+// ----------------------------------------------------------------------------
+
 static bool android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, Functor *functor) {
     android::uirenderer::Rect dirty;
@@ -618,6 +626,15 @@
     return displayList->getSize();
 }
 
+static void android_view_GLES20Canvas_setDisplayListName(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, jstring name) {
+    if (name != NULL) {
+        const char* textArray = env->GetStringUTFChars(name, NULL);
+        displayList->setName(textArray);
+        env->ReleaseStringUTFChars(name, textArray);
+    }
+}
+
 static OpenGLRenderer* android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env,
         jobject clazz) {
     return new DisplayListRenderer;
@@ -808,6 +825,8 @@
     { "nPrepareDirty",      "(IIIIIZ)V",       (void*) android_view_GLES20Canvas_prepareDirty },
     { "nFinish",            "(I)V",            (void*) android_view_GLES20Canvas_finish },
 
+    { "nGetStencilSize",    "()I",             (void*) android_view_GLES20Canvas_getStencilSize },
+
     { "nCallDrawGLFunction", "(II)Z",
             (void*) android_view_GLES20Canvas_callDrawGLFunction },
 
@@ -880,10 +899,14 @@
     { "nGetDisplayList",         "(II)I",      (void*) android_view_GLES20Canvas_getDisplayList },
     { "nDestroyDisplayList",     "(I)V",       (void*) android_view_GLES20Canvas_destroyDisplayList },
     { "nGetDisplayListSize",     "(I)I",       (void*) android_view_GLES20Canvas_getDisplayListSize },
-    { "nCreateDisplayListRenderer", "()I",     (void*) android_view_GLES20Canvas_createDisplayListRenderer },
-    { "nResetDisplayListRenderer", "(I)V",     (void*) android_view_GLES20Canvas_resetDisplayListRenderer },
+    { "nSetDisplayListName",     "(ILjava/lang/String;)V",
+                                               (void*) android_view_GLES20Canvas_setDisplayListName },
     { "nDrawDisplayList",        "(IIIILandroid/graphics/Rect;)Z",
                                                (void*) android_view_GLES20Canvas_drawDisplayList },
+
+    { "nCreateDisplayListRenderer", "()I",     (void*) android_view_GLES20Canvas_createDisplayListRenderer },
+    { "nResetDisplayListRenderer",  "(I)V",    (void*) android_view_GLES20Canvas_resetDisplayListRenderer },
+
     { "nOutputDisplayList",      "(II)V",      (void*) android_view_GLES20Canvas_outputDisplayList },
     { "nInterrupt",              "(I)V",       (void*) android_view_GLES20Canvas_interrupt },
     { "nResume",                 "(I)V",       (void*) android_view_GLES20Canvas_resume },
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 030a6b3..1175cbb 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -881,7 +881,7 @@
     <string name="replace" msgid="5781686059063148930">"Erstat..."</string>
     <string name="delete" msgid="6098684844021697789">"Slet"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopier webadresse"</string>
-    <string name="selectTextMode" msgid="1018691815143165326">"Marker tekst"</string>
+    <string name="selectTextMode" msgid="1018691815143165326">"Markér tekst"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Tekstmarkering"</string>
     <string name="addToDictionary" msgid="9090375111134433012">"føj til ordbog"</string>
     <string name="deleteText" msgid="7070985395199629156">"slet"</string>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index f9e1f5b..ce734fc 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -22,19 +22,9 @@
     <!-- Do not translate. These are all of the drawable resources that should be preloaded by
          the zygote process before it starts forking application processes. -->
     <array name="preloaded_drawables">
-       <item>@drawable/spinner_black_16</item>
-       <item>@drawable/spinner_black_20</item>
-       <item>@drawable/spinner_black_48</item>
-       <item>@drawable/spinner_black_76</item>
-       <item>@drawable/spinner_white_16</item>
-       <item>@drawable/spinner_white_48</item>
-       <item>@drawable/spinner_white_76</item>
-       <item>@drawable/toast_frame</item>
        <item>@drawable/toast_frame_holo</item>
-       <item>@drawable/btn_check_on_selected</item>
        <item>@drawable/btn_check_on_pressed_holo_light</item>
        <item>@drawable/btn_check_on_pressed_holo_dark</item>
-       <item>@drawable/btn_check_on_pressed</item>
        <item>@drawable/btn_check_on_holo_light</item>
        <item>@drawable/btn_check_on_holo_dark</item>
        <item>@drawable/btn_check_on_focused_holo_light</item>
@@ -43,13 +33,8 @@
        <item>@drawable/btn_check_on_disabled_holo_dark</item>
        <item>@drawable/btn_check_on_disabled_focused_holo_light</item>
        <item>@drawable/btn_check_on_disabled_focused_holo_dark</item>
-       <item>@drawable/btn_check_on_disable_focused</item>
-       <item>@drawable/btn_check_on_disable</item>
-       <item>@drawable/btn_check_on</item>
-       <item>@drawable/btn_check_off_selected</item>
        <item>@drawable/btn_check_off_pressed_holo_light</item>
        <item>@drawable/btn_check_off_pressed_holo_dark</item>
-       <item>@drawable/btn_check_off_pressed</item>
        <item>@drawable/btn_check_off_holo_light</item>
        <item>@drawable/btn_check_off_holo_dark</item>
        <item>@drawable/btn_check_off_focused_holo_light</item>
@@ -58,16 +43,10 @@
        <item>@drawable/btn_check_off_disabled_holo_dark</item>
        <item>@drawable/btn_check_off_disabled_focused_holo_light</item>
        <item>@drawable/btn_check_off_disabled_focused_holo_dark</item>
-       <item>@drawable/btn_check_off_disable_focused</item>
-       <item>@drawable/btn_check_off_disable</item>
-       <item>@drawable/btn_check_label_background</item>
        <item>@drawable/btn_check_holo_light</item>
        <item>@drawable/btn_check_holo_dark</item>
-       <item>@drawable/btn_check</item>
-       <item>@drawable/btn_radio_on_selected</item>
        <item>@drawable/btn_radio_on_pressed_holo_light</item>
        <item>@drawable/btn_radio_on_pressed_holo_dark</item>
-       <item>@drawable/btn_radio_on_pressed</item>
        <item>@drawable/btn_radio_on_holo_light</item>
        <item>@drawable/btn_radio_on_holo_dark</item>
        <item>@drawable/btn_radio_on_focused_holo_light</item>
@@ -76,11 +55,8 @@
        <item>@drawable/btn_radio_on_disabled_holo_dark</item>
        <item>@drawable/btn_radio_on_disabled_focused_holo_light</item>
        <item>@drawable/btn_radio_on_disabled_focused_holo_dark</item>
-       <item>@drawable/btn_radio_on</item>
-       <item>@drawable/btn_radio_off_selected</item>
        <item>@drawable/btn_radio_off_pressed_holo_light</item>
        <item>@drawable/btn_radio_off_pressed_holo_dark</item>
-       <item>@drawable/btn_radio_off_pressed</item>
        <item>@drawable/btn_radio_off_holo_light</item>
        <item>@drawable/btn_radio_off_holo_dark</item>
        <item>@drawable/btn_radio_off_focused_holo_light</item>
@@ -89,23 +65,10 @@
        <item>@drawable/btn_radio_off_disabled_holo_dark</item>
        <item>@drawable/btn_radio_off_disabled_focused_holo_light</item>
        <item>@drawable/btn_radio_off_disabled_focused_holo_dark</item>
-       <item>@drawable/btn_radio_label_background</item>
-       <item>@drawable/btn_radio</item>
-       <item>@drawable/btn_default_transparent_normal</item>
-       <item>@drawable/btn_default_small_selected</item>
-       <item>@drawable/btn_default_small_pressed</item>
-       <item>@drawable/btn_default_small_normal_disable_focused</item>
-       <item>@drawable/btn_default_small_normal_disable</item>
-       <item>@drawable/btn_default_small_normal</item>
-       <item>@drawable/btn_default_selected</item>
        <item>@drawable/btn_default_pressed_holo_light</item>
        <item>@drawable/btn_default_pressed_holo_dark</item>
-       <item>@drawable/btn_default_pressed</item>
        <item>@drawable/btn_default_normal_holo_light</item>
        <item>@drawable/btn_default_normal_holo_dark</item>
-       <item>@drawable/btn_default_normal_disable_focused</item>
-       <item>@drawable/btn_default_normal_disable</item>
-       <item>@drawable/btn_default_normal</item>
        <item>@drawable/btn_default_focused_holo_light</item>
        <item>@drawable/btn_default_focused_holo_dark</item>
        <item>@drawable/btn_default_disabled_holo_light</item>
@@ -114,24 +77,6 @@
        <item>@drawable/btn_default_disabled_focused_holo_dark</item>
        <item>@drawable/btn_default_holo_dark</item>
        <item>@drawable/btn_default_holo_light</item>
-       <item>@drawable/btn_default</item>
-       <item>@drawable/btn_default_small</item>
-       <item>@drawable/btn_dropdown_disabled</item>
-       <item>@drawable/btn_dropdown_disabled_focused</item>
-       <item>@drawable/btn_dropdown_normal</item>
-       <item>@drawable/btn_dropdown_pressed</item>
-       <item>@drawable/btn_dropdown_selected</item>
-       <item>@drawable/btn_star_label_background</item>
-       <item>@drawable/btn_star_big_off</item>
-       <item>@drawable/btn_star_big_on</item>
-       <item>@drawable/btn_star_big_on_disable</item>
-       <item>@drawable/btn_star_big_off_disable</item>
-       <item>@drawable/btn_star_big_on_pressed</item>
-       <item>@drawable/btn_star_big_off_pressed</item>
-       <item>@drawable/btn_star_big_on_selected</item>
-       <item>@drawable/btn_star_big_off_selected</item>
-       <item>@drawable/btn_star_big_on_disable_focused</item>
-       <item>@drawable/btn_star_big_off_disable_focused</item>
        <item>@drawable/btn_star_off_normal_holo_light</item>
        <item>@drawable/btn_star_on_normal_holo_light</item>
        <item>@drawable/btn_star_on_disabled_holo_light</item>
@@ -154,7 +99,6 @@
        <item>@drawable/btn_star_on_disabled_focused_holo_dark</item>
        <item>@drawable/btn_star_off_disabled_focused_holo_dark</item>
        <item>@drawable/btn_star_holo_dark</item>
-       <item>@drawable/btn_star</item>
        <item>@drawable/btn_toggle_on_pressed_holo_light</item>
        <item>@drawable/btn_toggle_on_pressed_holo_dark</item>
        <item>@drawable/btn_toggle_on_normal_holo_light</item>
@@ -165,7 +109,6 @@
        <item>@drawable/btn_toggle_on_disabled_holo_dark</item>
        <item>@drawable/btn_toggle_on_disabled_focused_holo_light</item>
        <item>@drawable/btn_toggle_on_disabled_focused_holo_dark</item>
-       <item>@drawable/btn_toggle_on</item>
        <item>@drawable/btn_toggle_off_pressed_holo_light</item>
        <item>@drawable/btn_toggle_off_pressed_holo_dark</item>
        <item>@drawable/btn_toggle_off_normal_holo_light</item>
@@ -176,23 +119,10 @@
        <item>@drawable/btn_toggle_off_disabled_holo_dark</item>
        <item>@drawable/btn_toggle_off_disabled_focused_holo_light</item>
        <item>@drawable/btn_toggle_off_disabled_focused_holo_dark</item>
-       <item>@drawable/btn_toggle_off</item>
        <item>@drawable/btn_toggle_holo_light</item>
        <item>@drawable/btn_toggle_holo_dark</item>
-       <item>@drawable/btn_toggle</item>
-       <item>@drawable/btn_toggle_bg</item>
-       <item>@drawable/btn_dropdown</item>
-       <item>@drawable/btn_dropdown</item>
-       <item>@drawable/light_header_dither</item>
-       <item>@drawable/divider_horizontal_textfield</item>
-       <item>@drawable/divider_horizontal_dark_opaque</item>
-       <item>@drawable/divider_horizontal_dark</item>
-       <item>@drawable/divider_horizontal_bright_opaque</item>
-       <item>@drawable/divider_horizontal_bright</item>
-       <item>@drawable/divider_vertical_dark</item>
        <item>@drawable/edit_text_holo_light</item>
        <item>@drawable/edit_text_holo_dark</item>
-       <item>@drawable/edit_text</item>
        <item>@drawable/text_cursor_holo_light</item>
        <item>@drawable/text_cursor_holo_dark</item>
        <item>@drawable/text_select_handle_left</item>
@@ -200,70 +130,45 @@
        <item>@drawable/text_edit_paste_window</item>
        <item>@drawable/expander_close_holo_dark</item>
        <item>@drawable/expander_close_holo_light</item>
-       <item>@drawable/expander_ic_maximized</item>
-       <item>@drawable/expander_ic_minimized</item>
-       <item>@drawable/expander_group</item>
        <item>@drawable/expander_group_holo_dark</item>
        <item>@drawable/expander_group_holo_light</item>
-       <item>@drawable/list_selector_background</item>
-       <item>@drawable/list_selector_background_light</item>
-       <item>@drawable/list_selector_background_longpress</item>
-       <item>@drawable/list_selector_background_longpress_light</item>
-       <item>@drawable/list_selector_background_pressed</item>
-       <item>@drawable/list_selector_background_pressed_light</item>
-       <item>@drawable/list_selector_background_selected</item>
        <item>@drawable/list_selector_holo_dark</item>
        <item>@drawable/list_selector_holo_light</item>
        <item>@drawable/list_section_divider_holo_light</item>
        <item>@drawable/list_section_divider_holo_dark</item>
-       <item>@drawable/menu_background</item>
-       <item>@drawable/menu_background_fill_parent_width</item>
        <item>@drawable/menu_hardkey_panel_holo_dark</item>
        <item>@drawable/menu_hardkey_panel_holo_light</item>
        <item>@drawable/menu_submenu_background</item>
-       <item>@drawable/menu_selector</item>
        <item>@drawable/menu_dropdown_panel_holo_light</item>
        <item>@drawable/menu_dropdown_panel_holo_dark</item>
        <item>@drawable/overscroll_edge</item>
        <item>@drawable/overscroll_glow</item>
-       <item>@drawable/panel_background</item>
-       <item>@drawable/popup_bottom_bright</item>
-       <item>@drawable/popup_bottom_dark</item>
-       <item>@drawable/popup_bottom_medium</item>
-       <item>@drawable/popup_center_bright</item>
-       <item>@drawable/popup_center_dark</item>
-       <item>@drawable/popup_center_medium</item>
-       <item>@drawable/popup_full_bright</item>
-       <item>@drawable/popup_full_dark</item>
-       <item>@drawable/popup_top_bright</item>
-       <item>@drawable/popup_top_dark</item>
        <item>@drawable/popup_inline_error_above_holo_dark</item>
        <item>@drawable/popup_inline_error_above_holo_light</item>
        <item>@drawable/popup_inline_error_holo_dark</item>
        <item>@drawable/popup_inline_error_holo_light</item>
+       <item>@drawable/spinner_16_outer_holo</item>
+       <item>@drawable/spinner_16_inner_holo</item>
+       <item>@drawable/spinner_48_outer_holo</item>
+       <item>@drawable/spinner_48_inner_holo</item>
+       <item>@drawable/spinner_76_outer_holo</item>
+       <item>@drawable/spinner_76_inner_holo</item>
        <item>@drawable/progress_bg_holo_dark</item>
        <item>@drawable/progress_bg_holo_light</item>
-       <item>@drawable/progress_horizontal</item>
        <item>@drawable/progress_horizontal_holo_dark</item>
        <item>@drawable/progress_horizontal_holo_light</item>
-       <item>@drawable/progress_indeterminate_horizontal</item>
        <item>@drawable/progress_indeterminate_horizontal_holo</item>
-       <item>@drawable/progress_large</item>
        <item>@drawable/progress_large_holo</item>
-       <item>@drawable/progress_large_white</item>
-       <item>@drawable/progress_medium</item>
        <item>@drawable/progress_medium_holo</item>
-       <item>@drawable/progress_medium_white</item>
        <item>@drawable/progress_primary_holo_dark</item>
        <item>@drawable/progress_primary_holo_light</item>
        <item>@drawable/progress_secondary_holo_dark</item>
        <item>@drawable/progress_secondary_holo_light</item>
-       <item>@drawable/progress_small</item>
        <item>@drawable/progress_small_holo</item>
-       <item>@drawable/progress_small_titlebar</item>
-       <item>@drawable/progress_small_white</item>
        <item>@drawable/scrubber_progress_horizontal_holo_dark</item>
        <item>@drawable/scrubber_progress_horizontal_holo_light</item>
+       <item>@drawable/background_holo_light</item>
+       <item>@drawable/background_holo_dark</item>
        <item>@drawable/screen_background_dark</item>
        <item>@drawable/screen_background_dark_transparent</item>
        <item>@drawable/screen_background_light</item>
@@ -272,8 +177,6 @@
        <item>@drawable/screen_background_selector_light</item>
        <item>@drawable/scrollbar_handle_holo_dark</item>
        <item>@drawable/scrollbar_handle_holo_light</item>
-       <item>@drawable/scrollbar_handle_horizontal</item>
-       <item>@drawable/scrollbar_handle_vertical</item>
        <item>@drawable/spinner_background_holo_dark</item>
        <item>@drawable/spinner_background_holo_light</item>
        <item>@drawable/spinner_ab_default_holo_dark</item>
@@ -290,9 +193,6 @@
        <item>@drawable/spinner_default_holo_light</item>
        <item>@drawable/spinner_disabled_holo_dark</item>
        <item>@drawable/spinner_disabled_holo_light</item>
-       <item>@drawable/spinner_dropdown_background</item>
-       <item>@drawable/spinner_dropdown_background_down</item>
-       <item>@drawable/spinner_dropdown_background_up</item>
        <item>@drawable/spinner_focused_holo_dark</item>
        <item>@drawable/spinner_focused_holo_light</item>
        <item>@drawable/spinner_pressed_holo_dark</item>
@@ -337,7 +237,6 @@
        <item>@drawable/dialog_middle_holo_light</item>
        <item>@drawable/dialog_top_holo_dark</item>
        <item>@drawable/dialog_top_holo_light</item>
-       <item>@drawable/ic_dialog_alert</item>
        <item>@drawable/ic_dialog_alert_holo_dark</item>
        <item>@drawable/ic_dialog_alert_holo_light</item>
        <item>@drawable/list_divider_holo_dark</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index b514bf5..16b7ff3 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2061,7 +2061,7 @@
         </attr>
         <!-- Direction of the text. A heuristic is used to determine the resolved text direction
              of paragraphs. -->
-        <attr name="textDirection" format="integer">
+         <attr name="textDirection" format="integer">
             <!-- Default -->
             <enum name="inherit" value="0" />
             <!-- Default for the root view. The first strong directional character determines the
@@ -2072,16 +2072,12 @@
                  it is LTR if it contains any strong LTR characters.  If there are neither, the
                  paragraph direction is the view’s resolved layout direction. -->
             <enum name="anyRtl" value="2" />
-            <!-- The paragraph direction is the same as the one held by a 60% majority of the
-                 characters. If there is no majority then the paragraph direction is the resolved
-                 layout direction of the View. -->
-            <enum name="charCount" value="3" />
             <!-- The paragraph direction is left to right. -->
-            <enum name="ltr" value="4" />
+            <enum name="ltr" value="3" />
             <!-- The paragraph direction is right to left. -->
-            <enum name="rtl" value="5" />
+            <enum name="rtl" value="4" />
             <!-- The paragraph direction is coming from the system Locale. -->
-            <enum name="locale" value="6" />
+            <enum name="locale" value="5" />
         </attr>
     </declare-styleable>
 
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 3b6d6f1..571c4ad 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -112,7 +112,7 @@
     </style>
 
     <!-- Standard animations for a translucent window or activity.  This
-         style is <em>not<em> used by default for the translucent theme
+         style is <em>not</em> used by default for the translucent theme
          (since translucent activities are a special case that have no
          clear UI paradigm), but you can make your own specialized theme
          with this animation style if you would like to have the standard
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index fe5388b..7046fc5 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -29,15 +29,16 @@
 ===============================================================
  -->
 <resources>
-    <!-- The default system theme. This is the theme used for activities
-         that have not explicitly set their own theme.
-         
+    <!-- The default theme for apps on API level 10 and lower. This is the theme used for
+         activities that have not explicitly set their own theme.
          <p>You can count on this being a dark
          background with light text on top, but should try to make no
          other assumptions about its appearance. In particular, the text
          inside of widgets using this theme may be completely different,
          with the widget container being a light color and the text on top
          of it a dark color.
+         <p>If you're developing for API level 11 and higher, you should instead use {@link
+         #Theme_Holo} or {@link #Theme_DeviceDefault}.</p>
     -->
     <style name="Theme">
 
@@ -370,13 +371,12 @@
         <item name="pointerStyle">@android:style/Pointer</item>
     </style>
 
-    <!-- Variant of the default (dark) theme with no title bar -->
+    <!-- Variant of {@link #Theme} with no title bar -->
     <style name="Theme.NoTitleBar">
         <item name="android:windowNoTitle">true</item>
     </style>
 
-    <!-- Variant of the default (dark) theme that has no title bar and
-         fills the entire screen -->
+    <!-- Variant of {@link #Theme} that has no title bar and no status bar -->
     <style name="Theme.NoTitleBar.Fullscreen">
         <item name="android:windowFullscreen">true</item>
         <item name="android:windowContentOverlay">@null</item>
@@ -385,7 +385,8 @@
     <!-- Theme for a light background with dark text on top.  Set your activity
          to this theme if you would like such an appearance.  As with the
          default theme, you should try to assume little more than that the
-         background will be a light color. -->
+         background will be a light color.
+         <p>This is designed for API level 10 and lower.</p>-->
     <style name="Theme.Light">
         <item name="windowBackground">@android:drawable/screen_background_selector_light</item>
         <item name="colorBackground">@android:color/background_light</item>
@@ -457,19 +458,19 @@
         <item name="detailsElementBackground">@android:drawable/panel_bg_holo_light</item>
     </style>
 
-    <!-- Variant of the light theme with no title bar -->
+    <!-- Variant of {@link #Theme_Light} with no title bar -->
     <style name="Theme.Light.NoTitleBar">
         <item name="android:windowNoTitle">true</item>
     </style>
 
-    <!-- Variant of the light theme that has no title bar and
-         fills the entire screen -->
+    <!-- Variant of {@link #Theme_Light} that has no title bar and
+         no status bar -->
     <style name="Theme.Light.NoTitleBar.Fullscreen">
         <item name="android:windowFullscreen">true</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
     
-    <!-- Special variation on the default theme that ensures the background is
+    <!-- Variant on {@link #Theme} that ensures the background is
          completely black.  This is useful for things like image viewers and
          media players.   If you want the normal (dark background) theme
          do <em>not</em> use this, use {@link #Theme}. -->
@@ -478,40 +479,40 @@
         <item name="android:colorBackground">@android:color/black</item>
     </style>
     
-    <!-- Variant of the black theme with no title bar -->
+    <!-- Variant of {@link #Theme_Black} with no title bar -->
     <style name="Theme.Black.NoTitleBar">
         <item name="android:windowNoTitle">true</item>
     </style>
 
-    <!-- Variant of the black theme that has no title bar and
-         fills the entire screen -->
+    <!-- Variant of {@link #Theme_Black} that has no title bar and
+         no status bar -->
     <style name="Theme.Black.NoTitleBar.Fullscreen">
         <item name="android:windowFullscreen">true</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
     
-    <!-- Default theme for windows that want to have the user's selected
-         wallpaper appear behind them.  -->
+    <!-- Theme for windows that want to have the user's selected
+         wallpaper appear behind them (for API level 10 and lower).  -->
     <style name="Theme.Wallpaper">
         <item name="android:windowBackground">@android:color/transparent</item>
         <item name="android:colorBackgroundCacheHint">@null</item>
         <item name="android:windowShowWallpaper">true</item>
     </style>
 
-    <!-- Variant of the translucent theme with no title bar -->
+    <!-- Variant of {@link #Theme_Wallpaper} that has no title bar -->
     <style name="Theme.Wallpaper.NoTitleBar">
         <item name="android:windowNoTitle">true</item>
     </style>
 
-    <!-- Variant of the translucent theme that has no title bar and
-         fills the entire screen -->
+    <!-- Variant of {@link #Theme_Wallpaper} that
+         has no title bar or status bar. -->
     <style name="Theme.Wallpaper.NoTitleBar.Fullscreen">
         <item name="android:windowFullscreen">true</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
 
-    <!-- Theme for a wallpaper's setting activity that is designed to be on
-         top of a dark background. -->
+    <!-- Theme for a wallpaper's setting activity, which is designed to be a transparent
+         background with a dark shade, so the previous Activity is visible in the background. -->
     <style name="Theme.WallpaperSettings">
         <item name="android:windowBackground">@android:drawable/screen_background_dark_transparent</item>
         <item name="android:colorBackgroundCacheHint">@null</item>
@@ -519,8 +520,8 @@
         <item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>
     </style>
 
-    <!-- Theme for a wallpaper's setting activity that is designed to be on
-         top of a light background. -->
+    <!-- Theme for a wallpaper's setting activity, which is designed to be a transparent
+         background with a light shade, so the previous Activity is visible in the background. -->
     <style name="Theme.Light.WallpaperSettings">
         <item name="android:windowBackground">@android:drawable/screen_background_light_transparent</item>
         <item name="android:colorBackgroundCacheHint">@null</item>
@@ -538,8 +539,8 @@
     <style name="PreviewWallpaperSettings">
     </style>
     
-    <!-- Default theme for translucent activities, that is windows that allow you
-         to see through them to the windows behind.  This sets up the translucent
+    <!-- Theme for translucent activities (on API level 10 and lower). That is, windows
+         that allow you to see through them to the windows behind.  This sets up the translucent
          flag and appropriate animations for your windows.  -->
     <style name="Theme.Translucent">
         <item name="android:windowBackground">@android:color/transparent</item>
@@ -551,14 +552,14 @@
         <item name="android:windowAnimationStyle">@android:style/Animation</item>
     </style>
 
-    <!-- Variant of the translucent theme with no title bar -->
+    <!-- Variant of {@link #Theme_Translucent} with no title bar -->
     <style name="Theme.Translucent.NoTitleBar">
         <item name="android:windowNoTitle">true</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
 
-    <!-- Variant of the translucent theme that has no title bar and
-         fills the entire screen -->
+    <!-- Variant of {@link #Theme_Translucent} that has no title bar and
+         no status bar -->
     <style name="Theme.Translucent.NoTitleBar.Fullscreen">
         <item name="android:windowFullscreen">true</item>
     </style>
@@ -574,7 +575,8 @@
         <item name="android:windowNoDisplay">true</item>
     </style>
 
-    <!-- Default theme for dialog windows and activities, which is used by the
+    <!-- Default theme for dialog windows and activities (on API level 10 and lower),
+         which is used by the
          {@link android.app.Dialog} class.  This changes the window to be
          floating (not fill the entire screen), and puts a frame around its
          contents.  You can set this theme on an activity if you would like to
@@ -622,7 +624,7 @@
         <item name="listPreferredItemPaddingRight">10dip</item>
     </style>
 
-    <!-- Variation of Theme.Dialog that does not include a frame (or background).
+    <!-- Variant of {@link Theme_Dialog} that does not include a frame (or background).
          The view hierarchy of the dialog is responsible for drawing all of
          its pixels. -->
     <style name="Theme.Dialog.NoFrame">
@@ -636,7 +638,7 @@
         <item name="android:windowCloseOnTouchOutside">false</item>
     </style>
 
-    <!-- Default theme for alert dialog windows, which is used by the
+    <!-- Default theme for alert dialog windows (on API level 10 and lower), which is used by the
          {@link android.app.AlertDialog} class.  This is basically a dialog
          but sets the background to empty so it can do two-tone backgrounds. -->
     <style name="Theme.Dialog.Alert">
@@ -648,8 +650,8 @@
         <item name="textAppearanceListItemSmall">@android:style/TextAppearance.Large.Inverse</item>
     </style>
     
-    <!-- Default dark theme for panel windows.  This removes all extraneous
-         window decorations, so you basically have an empty rectangle in which
+    <!-- Default dark theme for panel windows (on API level 10 and lower).  This removes all
+         extraneous window decorations, so you basically have an empty rectangle in which
          to place your content.  It makes the window floating, with a transparent
          background, and turns off dimming behind the window. -->
     <style name="Theme.Panel">
@@ -664,8 +666,8 @@
         <item name="android:windowNoTitle">true</item>
     </style>
 
-    <!-- Default light theme for panel windows.  This removes all extraneous
-         window decorations, so you basically have an empty rectangle in which
+    <!-- Default light theme for panel windows (on API level 10 and lower).  This removes all
+         extraneous window decorations, so you basically have an empty rectangle in which
          to place your content.  It makes the window floating, with a transparent
          background, and turns off dimming behind the window. -->
     <style name="Theme.Light.Panel">
@@ -712,7 +714,7 @@
         <item name="android:windowNoTitle">true</item>
     </style>
 
-    <!-- Default theme for input methods, which is used by the
+    <!-- Default theme for input methods (on API level 10 and lower), which is used by the
          {@link android.inputmethodservice.InputMethodService} class.
          this inherits from Theme.Panel, but sets up IME appropriate animations
          and a few custom attributes. -->
@@ -723,7 +725,7 @@
         <item name="android:imeExtractExitAnimation">@android:anim/input_method_extract_exit</item>
     </style>
 
-    <!-- Default theme for modern holo style input methods, which is used by the
+    <!-- Default theme for holo style input methods, which is used by the
          {@link android.inputmethodservice.InputMethodService} class.
          this inherits from Theme.Panel, but sets up IME appropriate animations
          and a few custom attributes. -->
@@ -842,14 +844,23 @@
         <item name="android:windowActionModeOverlay">true</item>
     </style>
     
-    <!-- New Honeycomb holographic theme. Dark version.  The widgets in the
-         holographic theme are translucent on their brackground, so applications
-         must ensure that any background they use with this theme is itself
-         dark; otherwise, it will be difficult to see the widgets.  The new
-         UI style also includes a full action bar by default.
+    <!-- Honeycomb holographic theme (dark version).
+         <p>This is the default system theme for apps that target API level 11 - 13. Starting
+         with API level 14, the default system theme is supplied by {@link #Theme_DeviceDefault},
+         which might apply a different style on different devices. If you want to ensure that your
+         app consistenly uses the Holo theme at all times, you must explicitly declare it in your
+         manifest. For example, {@code &lt;application android:theme="@android:style/Theme.Holo"&gt;}.
+         For more information, read <a
+         href="http://android-developers.blogspot.com/2012/01/holo-everywhere.html">Holo
+         Everywhere</a>.</p>
+         <p>The widgets in the holographic theme are translucent on their brackground, so
+         applications must ensure that any background they use with this theme is itself
+         dark; otherwise, it will be difficult to see the widgets. This UI style also includes a
+         full action bar by default.</p>
 
-         Styles used by the Holo theme are named using the convention Type.Holo.Etc.
-         (For example, Widget.Holo.Button, TextAppearance.Holo.Widget.PopupMenu.Large.)
+         <p>Styles used by the Holo theme are named using the convention Type.Holo.Etc
+         (for example, {@code Widget.Holo.Button} and {@code
+         TextAppearance.Holo.Widget.PopupMenu.Large}).
          Specific resources used by Holo are named using the convention @type/foo_bar_baz_holo
          with trailing _dark or _light specifiers if they are not shared between both light and
          dark versions of the theme. -->
@@ -951,15 +962,12 @@
         <item name="listDividerAlertDialog">@android:drawable/list_divider_holo_dark</item>
 
         <item name="expandableListPreferredItemPaddingLeft">40dip</item>
-        <item name="expandableListPreferredChildPaddingLeft">
-                ?android:attr/expandableListPreferredItemPaddingLeft</item>
+        <item name="expandableListPreferredChildPaddingLeft">?android:attr/expandableListPreferredItemPaddingLeft</item>
 
         <item name="expandableListPreferredItemIndicatorLeft">3dip</item>
         <item name="expandableListPreferredItemIndicatorRight">0dip</item>
-        <item name="expandableListPreferredChildIndicatorLeft">
-                ?android:attr/expandableListPreferredItemIndicatorLeft</item>
-        <item name="expandableListPreferredChildIndicatorRight">
-                ?android:attr/expandableListPreferredItemIndicatorRight</item>
+        <item name="expandableListPreferredChildIndicatorLeft">?android:attr/expandableListPreferredItemIndicatorLeft</item>
+        <item name="expandableListPreferredChildIndicatorRight">?android:attr/expandableListPreferredItemIndicatorRight</item>
 
         <!-- Gallery attributes -->
         <item name="galleryItemBackground">@android:drawable/gallery_item_background</item>
@@ -1156,10 +1164,10 @@
 
     </style>
 
-    <!-- New Honeycomb holographic theme. Light version.  The widgets in the
+    <!-- Honeycomb holographic theme (light version).  The widgets in the
          holographic theme are translucent on their brackground, so applications
          must ensure that any background they use with this theme is itself
-         light; otherwise, it will be difficult to see the widgets.  The new
+         light; otherwise, it will be difficult to see the widgets.  This
          UI style also includes a full action bar by default. -->
     <style name="Theme.Holo.Light" parent="Theme.Light">
         <item name="colorForeground">@android:color/bright_foreground_holo_light</item>
@@ -1257,15 +1265,12 @@
         <item name="activatedBackgroundIndicator">@android:drawable/activated_background_holo_light</item>
 
         <item name="expandableListPreferredItemPaddingLeft">40dip</item>
-        <item name="expandableListPreferredChildPaddingLeft">
-                ?android:attr/expandableListPreferredItemPaddingLeft</item>
+        <item name="expandableListPreferredChildPaddingLeft">?android:attr/expandableListPreferredItemPaddingLeft</item>
 
         <item name="expandableListPreferredItemIndicatorLeft">3dip</item>
         <item name="expandableListPreferredItemIndicatorRight">0dip</item>
-        <item name="expandableListPreferredChildIndicatorLeft">
-                ?android:attr/expandableListPreferredItemIndicatorLeft</item>
-        <item name="expandableListPreferredChildIndicatorRight">
-                ?android:attr/expandableListPreferredItemIndicatorRight</item>
+        <item name="expandableListPreferredChildIndicatorLeft">?android:attr/expandableListPreferredItemIndicatorLeft</item>
+        <item name="expandableListPreferredChildIndicatorRight">?android:attr/expandableListPreferredItemIndicatorRight</item>
 
         <item name="listDividerAlertDialog">@android:drawable/list_divider_holo_light</item>
 
@@ -1522,6 +1527,7 @@
     </style>
  
     <!-- Dialog themes for Holo -->
+    <eat-comment />
 
     <!-- Holo theme for dialog windows and activities, which is used by the
          {@link android.app.Dialog} class.  This changes the window to be
@@ -1554,27 +1560,27 @@
         <item name="listPreferredItemPaddingRight">16dip</item>
     </style>
 
-    <!-- Variation of Theme.Holo.Dialog that has a nice minumum width for
+    <!-- Variant of Theme.Holo.Dialog that has a nice minimum width for
          a regular dialog. -->
     <style name="Theme.Holo.Dialog.MinWidth">
         <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
         <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
     </style>
 
-    <!-- Variation of Theme.Holo.Dialog that does not include a title bar. -->
+    <!-- Variant of Theme.Holo.Dialog that does not include a title bar. -->
     <style name="Theme.Holo.Dialog.NoActionBar">
         <item name="android:windowActionBar">false</item>
         <item name="android:windowNoTitle">true</item>
     </style>
 
-    <!-- Variation of Theme.Holo.Dialog.NoActionVar that has a nice minumum width for
+    <!-- Variant of Theme.Holo.Dialog.NoActionBar that has a nice minimum width for
          a regular dialog. -->
     <style name="Theme.Holo.Dialog.NoActionBar.MinWidth">
         <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
         <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
     </style>
 
-    <!-- Variation of Theme.Holo.Dialog that does not include a frame (or background).
+    <!-- Variant of Theme.Holo.Dialog that does not include a frame (or background).
          The view hierarchy of the dialog is responsible for drawing all of
          its pixels. -->
     <style name="Theme.Holo.Dialog.NoFrame">
@@ -1646,20 +1652,20 @@
         <item name="listPreferredItemPaddingRight">16dip</item>
     </style>
 
-    <!-- Variation of Theme.Holo.Light.Dialog that has a nice minumum width for
+    <!-- Variant of Theme.Holo.Light.Dialog that has a nice minimum width for
          a regular dialog. -->
     <style name="Theme.Holo.Light.Dialog.MinWidth">
         <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
         <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
     </style>
 
-    <!-- Variation of Theme.Holo.Light.Dialog that does not include a title bar. -->
+    <!-- Variant of Theme.Holo.Light.Dialog that does not include a title bar. -->
     <style name="Theme.Holo.Light.Dialog.NoActionBar">
         <item name="android:windowActionBar">false</item>
         <item name="android:windowNoTitle">true</item>
     </style>
 
-    <!-- Variation of Theme.Holo.Light.Dialog.NoActionBar that has a nice minumum width for
+    <!-- Variant of Theme.Holo.Light.Dialog.NoActionBar that has a nice minimum width for
          a regular dialog. -->
     <style name="Theme.Holo.Light.Dialog.NoActionBar.MinWidth">
         <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
@@ -1700,7 +1706,8 @@
         <item name="android:windowShowWallpaper">true</item>
     </style>
 
-    <!-- Variant of the holographic (dark) theme with no title bar -->
+    <!--Default holographic (dark) for windows that want to have the user's selected
+         wallpaper appear behind them and without an action bar. -->
     <style name="Theme.Holo.Wallpaper.NoTitleBar">
         <item name="android:windowNoTitle">true</item>
     </style>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 8135986..abe4aad 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -31,6 +31,24 @@
 ===============================================================
  -->
 <resources>
+
+    <!-- The default theme for apps that target API level 14 and higher.
+         <p>The DeviceDefault themes are aliases for a specific device’s native look and feel. The
+         DeviceDefault theme family and widget style family offer ways for you to target your app
+         to a device’s native theme with all device customizations intact.</p>
+         <p>For example, when you set your app's {@code targetSdkVersion} to 14 or higher, this
+         theme is applied to your application by default. As such, your app might appear with the
+         {@link #Theme_Holo Holo} styles on one device, but with a different set of styles on
+         another device. This is great if you want your app to fit with the device's native look and
+         feel. If, however, you prefer to keep your UI style the same across all devices, you should
+         apply a specific theme such as {@link #Theme_Holo Holo} or one of your own design. For more
+         information, read <a
+         href="http://android-developers.blogspot.com/2012/01/holo-everywhere.html">Holo
+         Everywhere</a>.</p>
+         <p>Styles used by the DeviceDefault theme are named using the convention
+         Type.DeviceDefault.Etc (for example, {@code Widget.DeviceDefault.Button} and
+         {@code TextAppearance.DeviceDefault.Widget.PopupMenu.Large}).</p>
+          -->
     <style name="Theme.DeviceDefault" parent="Theme.Holo" >
         <!-- Text styles -->
         <item name="textAppearance">@android:style/TextAppearance.DeviceDefault</item>
@@ -176,12 +194,16 @@
         <!-- DatePicker style -->
         <item name="datePickerStyle">@style/Widget.DeviceDefault.DatePicker</item>
     </style>
+
+    <!-- Variant of {@link #Theme_DeviceDefault} with no action bar -->
     <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Holo.NoActionBar" >
 
     </style>
+    <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar -->
     <style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Holo.NoActionBar.Fullscreen" >
 
     </style>
+    <!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
     <style name="Theme.DeviceDefault.Light" parent="Theme.Holo.Light" >
         <!-- Text styles -->
         <item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Light</item>
@@ -322,12 +344,17 @@
         <!-- DatePicker style -->
         <item name="datePickerStyle">@style/Widget.DeviceDefault.Light.DatePicker</item>
     </style>
+    <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
     <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Holo.Light.NoActionBar" >
 
     </style>
+    <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar -->
     <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Holo.Light.NoActionBar.Fullscreen" >
 
     </style>
+    <!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
+    floating (not fill the entire screen), and puts a frame around its contents. You can set this
+    theme on an activity if you would like to make an activity that looks like a Dialog. -->
     <style name="Theme.DeviceDefault.Dialog" parent="Theme.Holo.Dialog" >
         <item name="android:windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault</item>
         <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Dialog</item>
@@ -338,15 +365,23 @@
         <item name="textAppearance">@android:style/TextAppearance.DeviceDefault</item>
         <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Inverse</item>
     </style>
+    <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
+    regular dialog. -->
     <style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Holo.Dialog.MinWidth" >
 
     </style>
+    <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
     <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Holo.Dialog.NoActionBar" >
 
     </style>
+    <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
+    for a regular dialog. -->
     <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Holo.Dialog.NoActionBar.MinWidth" >
 
     </style>
+    <!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
+    floating (not fill the entire screen), and puts a frame around its contents. You can set this
+    theme on an activity if you would like to make an activity that looks like a Dialog.-->
     <style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Holo.Light.Dialog" >
         <item name="android:windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault.Light</item>
         <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Dialog</item>
@@ -357,42 +392,71 @@
         <item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Light</item>
         <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Light.Inverse</item>
     </style>
+    <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a
+    regular dialog. -->
     <style name="Theme.DeviceDefault.Light.Dialog.MinWidth" parent="Theme.Holo.Light.Dialog.MinWidth" >
 
     </style>
+     <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
     <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar" parent="Theme.Holo.Light.Dialog.NoActionBar" >
 
     </style>
+    <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
+    width for a regular dialog. -->
     <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Holo.Light.Dialog.NoActionBar.MinWidth" >
 
     </style>
+    <!-- DeviceDefault theme for a window that will be displayed either full-screen on smaller
+    screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
     <style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Holo.DialogWhenLarge" >
 
     </style>
+    <!-- DeviceDefault theme for a window without an action bar that will be displayed either
+    full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
+    xlarge). -->
     <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Holo.DialogWhenLarge.NoActionBar" >
 
     </style>
+    <!-- DeviceDefault light theme for a window that will be displayed either full-screen on smaller
+    screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
     <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Holo.Light.DialogWhenLarge" >
 
     </style>
+    <!-- DeviceDefault light theme for a window without an action bar that will be displayed either
+    full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
+    xlarge). -->
     <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Holo.Light.DialogWhenLarge.NoActionBar" >
 
     </style>
+    <!-- DeviceDefault theme for panel windows. This removes all extraneous window
+    decorations, so you basically have an empty rectangle in which to place your content. It makes
+    the window floating, with a transparent background, and turns off dimming behind the window. -->
     <style name="Theme.DeviceDefault.Panel" parent="Theme.Holo.Panel" >
 
     </style>
+    <!-- DeviceDefault light theme for panel windows. This removes all extraneous window
+    decorations, so you basically have an empty rectangle in which to place your content. It makes
+    the window floating, with a transparent background, and turns off dimming behind the window. -->
     <style name="Theme.DeviceDefault.Light.Panel" parent="Theme.Holo.Light.Panel" >
 
     </style>
+    <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
+    behind them. -->
     <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Holo.Wallpaper" >
 
     </style>
+    <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
+    behind them and without an action bar. -->
     <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar" parent="Theme.Holo.Wallpaper.NoTitleBar" >
 
     </style>
+    <!-- DeviceDefault style for input methods, which is used by the
+         {@link android.inputmethodservice.InputMethodService} class.-->
     <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Holo.InputMethod" >
 
     </style>
+    <!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an
+    inverse color profile. -->
     <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Holo.Light.DarkActionBar" >
         <item name="android:actionBarStyle">@android:style/Widget.DeviceDefault.Light.ActionBar.Solid.Inverse</item>
 
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
index 3ffa085..7233e7f 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
@@ -46,7 +46,7 @@
     @Override
     public TestSuite getAllTests() {
         TestSuite suite = new InstrumentationTestSuite(this);
-        if (!UtilHelper.isWifiOnly()) {
+        if (!UtilHelper.isWifiOnly(getContext())) {
             suite.addTestSuite(WifiApStress.class);
             suite.addTestSuite(WifiStressTest.class);
         } else {
@@ -64,7 +64,7 @@
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-        if (!UtilHelper.isWifiOnly()) {
+        if (!UtilHelper.isWifiOnly(getContext())) {
             String valueStr = (String) icicle.get("softap_iterations");
             if (valueStr != null) {
                 int iteration = Integer.parseInt(valueStr);
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
index 20aae47..9819c54 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
@@ -40,7 +40,7 @@
     @Override
     public TestSuite getAllTests() {
         TestSuite suite = new InstrumentationTestSuite(this);
-        if (!UtilHelper.isWifiOnly()) {
+        if (!UtilHelper.isWifiOnly(getContext())) {
             suite.addTestSuite(ConnectivityManagerMobileTest.class);
         } else {
             // create a new test suite
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/UtilHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/UtilHelper.java
index 1b966bf..b9fe6ed 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/UtilHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/UtilHelper.java
@@ -16,12 +16,31 @@
 
 package com.android.connectivitymanagertest;
 
-import android.os.SystemProperties;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.util.Log;
 
 public class UtilHelper {
-    public static boolean isWifiOnly() {
-        return "wifi-only".equals(SystemProperties.get("ro.carrier"));
+
+    private static Boolean mIsWifiOnly = null;
+    private static final Object sLock = new Object();
+
+    /**
+     * Return true if device is a wifi only device.
+     */
+    public static boolean isWifiOnly(Context context) {
+        synchronized (sLock) {
+            // cache the result from pkgMgr statically. It will never change, since its a
+            // device configuration setting
+            if (mIsWifiOnly == null) {
+                PackageManager pkgMgr = context.getPackageManager();
+                mIsWifiOnly = Boolean.valueOf(!pkgMgr
+                        .hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
+                        && pkgMgr.hasSystemFeature(PackageManager.FEATURE_WIFI));
+                String deviceType = mIsWifiOnly ? "wifi-only" : "telephony";
+                Log.d("ConnectivityManagerTest", String.format("detected a %s device", deviceType));
+            }
+        }
+        return mIsWifiOnly;
     }
-
-
 }
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index b1f4bf1..52326d5 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -16,37 +16,31 @@
 
 package com.android.connectivitymanagertest.functional;
 
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
-import com.android.connectivitymanagertest.UtilHelper;
-
-import android.content.Intent;
 import android.content.Context;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.app.Instrumentation;
-import android.os.Handler;
-import android.os.Message;
-import android.provider.Settings;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.State;
-import android.net.NetworkInfo.DetailedState;
 import android.net.wifi.WifiManager;
-
-import android.test.suitebuilder.annotation.LargeTest;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.provider.Settings;
 import android.test.ActivityInstrumentationTestCase2;
-import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
-import com.android.connectivitymanagertest.NetworkState;
+import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
-public class ConnectivityManagerMobileTest
-    extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
+import com.android.connectivitymanagertest.NetworkState;
+import com.android.connectivitymanagertest.UtilHelper;
+
+public class ConnectivityManagerMobileTest extends
+        ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
     private static final String LOG_TAG = "ConnectivityManagerMobileTest";
-    private static final String PKG_NAME = "com.android.connectivitymanagertest";
 
     private String TEST_ACCESS_POINT;
     private ConnectivityManagerTestActivity cmActivity;
     private WakeLock wl;
+    private boolean mIsWifiOnlyDevice;
 
     public ConnectivityManagerMobileTest() {
         super(ConnectivityManagerTestActivity.class);
@@ -69,7 +63,8 @@
             log("airplane is not disabled, disable it.");
             cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
         }
-        if (!UtilHelper.isWifiOnly()) {
+        mIsWifiOnlyDevice = UtilHelper.isWifiOnly(mRunner.getTargetContext());
+        if (!mIsWifiOnlyDevice) {
             if (!cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
                     ConnectivityManagerTestActivity.LONG_TIMEOUT)) {
                 // Note: When the test fails in setUp(), tearDown is not called. In that case,
@@ -166,7 +161,7 @@
     public void testConnectToWifi() {
         assertNotNull("SSID is null", TEST_ACCESS_POINT);
         NetworkInfo networkInfo;
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             //Prepare for connectivity verification
             networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
             cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
@@ -185,7 +180,7 @@
         log("wifi state is enabled");
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
                 ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
                     State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
         }
@@ -197,7 +192,7 @@
                     cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
             assertTrue(false);
         }
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
                 log("Mobile state transition validation failed.");
                 log("reason: " +
@@ -232,13 +227,13 @@
                 ConnectivityManagerTestActivity.LONG_TIMEOUT));
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
                 State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
                     State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
         }
 
         NetworkInfo networkInfo;
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             //Prepare for connectivity state verification
             networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
             cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
@@ -258,7 +253,7 @@
         // Wait for Wifi to be connected and mobile to be disconnected
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
                 ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
                     State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
         }
@@ -288,7 +283,7 @@
         sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
 
         NetworkInfo networkInfo;
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
             cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
                                                   networkInfo.getState(),
@@ -304,7 +299,7 @@
 
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
                 ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
                     State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
         }
@@ -316,7 +311,7 @@
                     cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
             assertTrue(false);
         }
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
                 log("Mobile state transition validation failed.");
                 log("reason: " +
@@ -393,7 +388,7 @@
         cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
 
         NetworkInfo networkInfo;
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
                     State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
             networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
@@ -419,7 +414,7 @@
                     cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
             assertTrue("State validation failed", false);
         }
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
                 log("state validation for Mobile failed");
                 log("reason: " +
@@ -471,7 +466,7 @@
 
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
                             ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
                     State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
         }
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index 2069789..feb63cd 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -16,10 +16,6 @@
 
 package com.android.connectivitymanagertest.stress;
 
-import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
-import com.android.connectivitymanagertest.UtilHelper;
-
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo.State;
@@ -31,15 +27,15 @@
 import android.net.wifi.WifiManager;
 import android.os.Environment;
 import android.os.PowerManager;
-import android.os.IPowerManager;
-import android.os.SystemClock;
-import android.os.ServiceManager;
 import android.provider.Settings;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.LargeTest;
-
 import android.util.Log;
 
+import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
+import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.UtilHelper;
+
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileWriter;
@@ -79,6 +75,7 @@
     private String mPassword;
     private ConnectivityManagerStressTestRunner mRunner;
     private BufferedWriter mOutputWriter = null;
+    private boolean mIsWifiOnlyDevice;
 
     public WifiStressTest() {
         super(ConnectivityManagerTestActivity.class);
@@ -100,6 +97,7 @@
         mOutputWriter = new BufferedWriter(new FileWriter(new File(
                 Environment.getExternalStorageDirectory(), OUTPUT_FILE), true));
         mAct.turnScreenOn();
+        mIsWifiOnlyDevice = UtilHelper.isWifiOnly(mRunner.getTargetContext());
         if (!mAct.mWifiManager.isWifiEnabled()) {
             log("Enable wi-fi before stress tests.");
             if (!mAct.enableWifi()) {
@@ -271,7 +269,7 @@
             assertTrue("Wait for Wi-Fi to idle timeout",
                     mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
                     6 * ConnectivityManagerTestActivity.SHORT_TIMEOUT));
-            if (!UtilHelper.isWifiOnly()) {
+            if (!mIsWifiOnlyDevice) {
                 // use long timeout as the pppd startup may take several retries.
                 assertTrue("Wait for cellular connection timeout",
                         mAct.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
@@ -282,7 +280,7 @@
             assertEquals("Wi-Fi is reconnected", State.DISCONNECTED,
                     mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState());
 
-            if (!UtilHelper.isWifiOnly()) {
+            if (!mIsWifiOnlyDevice) {
                 assertEquals("Cellular connection is down", State.CONNECTED,
                              mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState());
                 assertTrue("Mobile is connected, but no data connection.", mAct.pingTest(null));
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
index a5e5ab0e..dfcbba9 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
@@ -146,10 +146,10 @@
                 Log.v("ConnectivityReceiver", "onReceive() called with " + intent);
                 return;
             }
-            if (intent.hasExtra(ConnectivityManager.EXTRA_NETWORK_INFO)) {
-                mNetworkInfo = (NetworkInfo)
-                        intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
-            }
+
+            final ConnectivityManager connManager = (ConnectivityManager) context
+                    .getSystemService(Context.CONNECTIVITY_SERVICE);
+            mNetworkInfo = connManager.getActiveNetworkInfo();
 
             if (intent.hasExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO)) {
                 mOtherNetworkInfo = (NetworkInfo)
diff --git a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivity.java b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivity.java
index b4a0581..a9f144b 100644
--- a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivity.java
+++ b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivity.java
@@ -14,12 +14,12 @@
 
 package android.accessibilityservice;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.view.View;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Activity for testing the accessibility APIs for "interrogation" of
  * the screen content. These APIs allow exploring the screen and
diff --git a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
index 259a094..fa48093 100644
--- a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
+++ b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
@@ -14,26 +14,21 @@
 
 package android.accessibilityservice;
 
-import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_FOCUS;
-import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_SELECTION;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_FOCUS;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_FOCUS;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_SELECT;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_SELECTION;
 
-import android.content.Context;
 import android.graphics.Rect;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
-import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityInteractionClient;
-import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.IAccessibilityManager;
 
 import com.android.frameworks.coretests.R;
+import com.android.internal.util.Predicate;
 
 import java.util.ArrayList;
 import java.util.LinkedList;
@@ -48,21 +43,15 @@
  */
 public class InterrogationActivityTest
         extends ActivityInstrumentationTestCase2<InterrogationActivity> {
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
     private static String LOG_TAG = "InterrogationActivityTest";
 
-    // Timeout before give up wait for the system to process an accessibility setting change.       
-    private static final int TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING = 2000;
-
     // Timeout for the accessibility state of an Activity to be fully initialized.
-    private static final int TIMEOUT_ACCESSIBLITY_STATE_INITIALIZED_MILLIS = 100;
+    private static final int TIMEOUT_PROPAGATE_ACCESSIBILITY_EVENT_MILLIS = 5000;
 
     // Handle to a connection to the AccessibilityManagerService
-    private static int sConnectionId = View.NO_ID;
-
-    // The last received accessibility event
-    private volatile AccessibilityEvent mLastAccessibilityEvent;
+    private UiTestAutomationBridge mUiTestAutomationBridge;
 
     public InterrogationActivityTest() {
         super(InterrogationActivity.class);
@@ -70,16 +59,39 @@
 
     @Override
     public void setUp() throws Exception {
-        ensureConnection();
-        bringUpActivityWithInitalizedAccessbility();
+        super.setUp();
+        mUiTestAutomationBridge = new UiTestAutomationBridge();
+        mUiTestAutomationBridge.connect();
+        mUiTestAutomationBridge.executeCommandAndWaitForAccessibilityEvent(new Runnable() {
+                // wait for the first accessibility event
+                @Override
+                public void run() {
+                    // bring up the activity
+                    getActivity();
+                }
+            },
+            new Predicate<AccessibilityEvent>() {
+                @Override
+                public boolean apply(AccessibilityEvent event) {
+                    return (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
+                            && event.getPackageName().equals(getActivity().getPackageName()));
+                }
+            },
+            TIMEOUT_PROPAGATE_ACCESSIBILITY_EVENT_MILLIS);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mUiTestAutomationBridge.disconnect();
+        super.tearDown();
     }
 
     @LargeTest
     public void testFindAccessibilityNodeInfoByViewId() throws Exception {
         final long startTimeMillis = SystemClock.uptimeMillis();
         try {
-            AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            AccessibilityNodeInfo button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertNotNull(button);
             assertEquals(0, button.getChildCount());
 
@@ -125,8 +137,8 @@
         final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // find a view by text
-            List<AccessibilityNodeInfo> buttons =  AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfosByTextInActiveWindow(sConnectionId, "butto");
+            List<AccessibilityNodeInfo> buttons = mUiTestAutomationBridge
+                .findAccessibilityNodeInfosByTextInActiveWindow("butto");
             assertEquals(9, buttons.size());
         } finally {
             if (DEBUG) {
@@ -141,12 +153,9 @@
     public void testFindAccessibilityNodeInfoByViewTextContentDescription() throws Exception {
         final long startTimeMillis = SystemClock.uptimeMillis();
         try {
-            bringUpActivityWithInitalizedAccessbility();
-
             // find a view by text
-            List<AccessibilityNodeInfo> buttons =  AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfosByTextInActiveWindow(sConnectionId,
-                        "contentDescription");
+            List<AccessibilityNodeInfo> buttons = mUiTestAutomationBridge
+                .findAccessibilityNodeInfosByTextInActiveWindow("contentDescription");
             assertEquals(1, buttons.size());
         } finally {
             if (DEBUG) {
@@ -177,8 +186,8 @@
             classNameAndTextList.add("android.widget.ButtonButton8");
             classNameAndTextList.add("android.widget.ButtonButton9");
 
-            AccessibilityNodeInfo root = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.root);
+            AccessibilityNodeInfo root = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.root);
             assertNotNull("We must find the existing root.", root);
 
             Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
@@ -216,16 +225,16 @@
         final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // find a view and make sure it is not focused
-            AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            AccessibilityNodeInfo button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isFocused());
 
             // focus the view
             assertTrue(button.performAction(ACTION_FOCUS));
 
             // find the view again and make sure it is focused
-            button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            button = mUiTestAutomationBridge
+                    .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertTrue(button.isFocused());
         } finally {
             if (DEBUG) {
@@ -240,24 +249,24 @@
         final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // find a view and make sure it is not focused
-            AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            AccessibilityNodeInfo button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isFocused());
 
             // focus the view
             assertTrue(button.performAction(ACTION_FOCUS));
 
             // find the view again and make sure it is focused
-            button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertTrue(button.isFocused());
 
             // unfocus the view
             assertTrue(button.performAction(ACTION_CLEAR_FOCUS));
 
             // find the view again and make sure it is not focused
-            button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isFocused());
         } finally {
             if (DEBUG) {
@@ -273,16 +282,16 @@
         final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // find a view and make sure it is not selected
-            AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            AccessibilityNodeInfo button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isSelected());
 
             // select the view
             assertTrue(button.performAction(ACTION_SELECT));
 
             // find the view again and make sure it is selected
-            button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertTrue(button.isSelected());
         } finally {
             if (DEBUG) {
@@ -297,24 +306,24 @@
         final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // find a view and make sure it is not selected
-            AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            AccessibilityNodeInfo button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isSelected());
 
             // select the view
             assertTrue(button.performAction(ACTION_SELECT));
 
             // find the view again and make sure it is selected
-            button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertTrue(button.isSelected());
 
             // unselect the view
             assertTrue(button.performAction(ACTION_CLEAR_SELECTION));
 
             // find the view again and make sure it is not selected
-            button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isSelected());
         } finally {
             if (DEBUG) {
@@ -330,23 +339,33 @@
         final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // find a view and make sure it is not focused
-            AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
-            assertFalse(button.isSelected());
+            final AccessibilityNodeInfo button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
+            assertFalse(button.isFocused());
 
-            // focus the view
-            assertTrue(button.performAction(ACTION_FOCUS));
-
-            synchronized (this) {
-                try {
-                    wait(TIMEOUT_ACCESSIBLITY_STATE_INITIALIZED_MILLIS);
-                } catch (InterruptedException ie) {
-                    /* ignore */
+            AccessibilityEvent event = mUiTestAutomationBridge
+                    .executeCommandAndWaitForAccessibilityEvent(new Runnable() {
+                @Override
+                public void run() {
+                    // focus the view
+                    assertTrue(button.performAction(ACTION_FOCUS));
                 }
-            }
+            },
+            new Predicate<AccessibilityEvent>() {
+                @Override
+                public boolean apply(AccessibilityEvent event) {
+                    return (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED
+                            && event.getPackageName().equals(getActivity().getPackageName())
+                            && event.getText().get(0).equals(button.getText()));
+                }
+            },
+            TIMEOUT_PROPAGATE_ACCESSIBILITY_EVENT_MILLIS);
+
+            // check the last event
+            assertNotNull(event);
 
             // check that last event source
-            AccessibilityNodeInfo source = mLastAccessibilityEvent.getSource();
+            AccessibilityNodeInfo source = event.getSource();
             assertNotNull(source);
 
             // bounds
@@ -389,8 +408,9 @@
         final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // find a view and make sure it is not focused
-            AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            AccessibilityNodeInfo button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
+            assertNotNull(button);
             AccessibilityNodeInfo parent = button.getParent();
             final int childCount = parent.getChildCount();
             for (int i = 0; i < childCount; i++) {
@@ -410,71 +430,4 @@
             }
         }
     }
-
-    private void bringUpActivityWithInitalizedAccessbility() {
-        mLastAccessibilityEvent = null;
-        // bring up the activity
-        getActivity();
-
-        final long startTimeMillis = SystemClock.uptimeMillis();
-        while (true) {
-            if (mLastAccessibilityEvent != null) {
-                final int eventType = mLastAccessibilityEvent.getEventType();
-                if (eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
-                    return;
-                }
-            }
-            final long remainingTimeMillis = TIMEOUT_ACCESSIBLITY_STATE_INITIALIZED_MILLIS
-                    - (SystemClock.uptimeMillis() - startTimeMillis);
-            if (remainingTimeMillis <= 0) {
-                return;
-            }
-            synchronized (this) {
-                try {
-                    wait(remainingTimeMillis);
-                } catch (InterruptedException e) {
-                    /* ignore */
-                }
-            }
-        }
-    }
-
-    private void ensureConnection() throws Exception {
-        if (sConnectionId == View.NO_ID) {
-            IEventListener listener = new IEventListener.Stub() {
-                public void setConnection(IAccessibilityServiceConnection connection,
-                        int connectionId) {
-                    sConnectionId = connectionId;
-                    if (connection != null) {
-                        AccessibilityInteractionClient.getInstance().addConnection(connectionId,
-                                connection);
-                    } else {
-                        AccessibilityInteractionClient.getInstance().removeConnection(connectionId);
-                    }
-                    synchronized (this) {
-                        notifyAll();
-                    }
-                }
-
-                public void onInterrupt() {}
-
-                public void onAccessibilityEvent(AccessibilityEvent event) {
-                    mLastAccessibilityEvent = AccessibilityEvent.obtain(event);
-                    synchronized (this) {
-                        notifyAll();
-                    }
-                }
-            };
-
-            AccessibilityManager accessibilityManager =
-                AccessibilityManager.getInstance(getInstrumentation().getContext());
-
-            synchronized (this) {
-                IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
-                        ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
-                manager.registerEventListener(listener);
-                wait(TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING);
-            }
-        }
-    }
 }
diff --git a/core/tests/coretests/src/android/widget/focus/RequestFocus.java b/core/tests/coretests/src/android/widget/focus/RequestFocus.java
index af9ee17..21d762a 100644
--- a/core/tests/coretests/src/android/widget/focus/RequestFocus.java
+++ b/core/tests/coretests/src/android/widget/focus/RequestFocus.java
@@ -21,9 +21,7 @@
 import android.app.Activity;
 import android.os.Bundle;
 import android.os.Handler;
-import android.widget.LinearLayout;
 import android.widget.Button;
-import android.view.View;
 
 /**
  * Exercises cases where elements of the UI are requestFocus()ed.
diff --git a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
index a78b0c9..baf587e 100644
--- a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
+++ b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
@@ -16,21 +16,27 @@
 
 package android.widget.focus;
 
-import android.widget.focus.RequestFocus;
-import com.android.frameworks.coretests.R;
-
 import android.os.Handler;
-import android.test.ActivityInstrumentationTestCase;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.Button;
 import android.util.AndroidRuntimeException;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
+import android.widget.Button;
+
+import com.android.frameworks.coretests.R;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * {@link RequestFocusTest} is set up to exercise cases where the views that
  * have focus become invisible or GONE.
  */
-public class RequestFocusTest extends ActivityInstrumentationTestCase<RequestFocus> {
+public class RequestFocusTest extends ActivityInstrumentationTestCase2<RequestFocus> {
 
     private Button mTopLeftButton;
     private Button mBottomLeftButton;
@@ -39,7 +45,7 @@
     private Handler mHandler;
 
     public RequestFocusTest() {
-        super("com.android.frameworks.coretests", RequestFocus.class);
+        super(RequestFocus.class);
     }
 
     @Override
@@ -94,4 +100,145 @@
                          e.getClass().getName());
         }
     }
+
+    /**
+     * This tests checks the case in which the first focusable View clears focus.
+     * In such a case the framework tries to give the focus to another View starting
+     * from the top. Hence, the framework will try to give focus to the view that
+     * wants to clear its focus. From a client perspective, the view does not loose
+     * focus after the call, therefore no callback for focus change should be invoked.
+     *
+     * @throws Exception If an error occurs.
+     */
+    @UiThreadTest
+    public void testOnFocusChangeNotCalledIfFocusDoesNotMove() throws Exception {
+        // Get the first focusable.
+        Button button = mTopLeftButton;
+
+        // Make sure that the button is the first focusable and focus it.
+        button.getRootView().requestFocus(View.FOCUS_DOWN);
+        assertTrue(button.hasFocus());
+
+        // Attach on focus change listener that should not be called.
+        button.setOnFocusChangeListener(new OnFocusChangeListener() {
+            @Override
+            public void onFocusChange(View v, boolean hasFocus) {
+                throw new IllegalStateException("Unexpeced call to"
+                        + "OnFocusChangeListener#onFocusChange");
+            }
+        });
+
+        // Attach on global focus change listener that should not be called.
+        button.getViewTreeObserver().addOnGlobalFocusChangeListener(
+                new OnGlobalFocusChangeListener() {
+            @Override
+            public void onGlobalFocusChanged(View oldFocus, View newFocus) {
+                throw new IllegalStateException("Unexpeced call to"
+                        + "OnFocusChangeListener#onFocusChange");
+            }
+        });
+
+        // Try to clear focus.
+        button.clearFocus();
+    }
+
+    /**
+     * This tests check whether the on focus change callbacks are invoked in
+     * the proper order when a View loses focus and the framework gives it to
+     * the fist focusable one.
+     *
+     * @throws Exception
+     */
+    @UiThreadTest
+    public void testOnFocusChangeCallbackOrder() throws Exception {
+        // Get the first focusable.
+        Button clearingFocusButton = mTopRightButton;
+        Button gainingFocusButton = mTopLeftButton;
+
+        // Make sure that the clearing focus is not the first focusable.
+        View focusCandidate = clearingFocusButton.getRootView().getParent().focusSearch(null,
+                View.FOCUS_FORWARD);
+        assertNotSame("The clearing focus button is not the first focusable.",
+                clearingFocusButton, focusCandidate);
+        assertSame("The gaining focus button is the first focusable.",
+                gainingFocusButton, focusCandidate);
+
+        // Focus the clearing focus button.
+        clearingFocusButton.requestFocus();
+        assertTrue(clearingFocusButton.hasFocus());
+
+        // Register the invocation order checker.
+        CallbackOrderChecker checker = new CallbackOrderChecker(clearingFocusButton,
+                gainingFocusButton);
+        clearingFocusButton.setOnFocusChangeListener(checker);
+        gainingFocusButton.setOnFocusChangeListener(checker);
+        clearingFocusButton.getViewTreeObserver().addOnGlobalFocusChangeListener(checker);
+
+        // Try to clear focus.
+        clearingFocusButton.clearFocus();
+
+        // Check that no callback was invoked since focus did not move.
+        checker.verify();
+    }
+
+    /**
+     * This class check whether the focus change callback are invoked in order.
+     */
+    private class CallbackOrderChecker implements OnFocusChangeListener,
+            OnGlobalFocusChangeListener {
+
+        private class CallbackInvocation {
+            final String mMethodName;
+            final Object[] mArguments;
+
+            CallbackInvocation(String methodName, Object[] arguments) {
+                mMethodName = methodName;
+                mArguments = arguments;
+            }
+        }
+
+        private final View mClearingFocusView;
+        private final View mGainingFocusView;
+
+        private final List<CallbackInvocation> mInvocations = new ArrayList<CallbackInvocation>();
+
+        public CallbackOrderChecker(View clearingFocusView, View gainingFocusView) {
+            mClearingFocusView = clearingFocusView;
+            mGainingFocusView = gainingFocusView;
+        }
+
+        @Override
+        public void onFocusChange(View view, boolean hasFocus) {
+            CallbackInvocation invocation = new CallbackInvocation(
+                    "OnFocusChangeListener#onFocusChange", new Object[] {view, hasFocus});
+            mInvocations.add(invocation);
+        }
+
+        @Override
+        public void onGlobalFocusChanged(View oldFocus, View newFocus) {
+            CallbackInvocation invocation = new CallbackInvocation(
+                    "OnFocusChangeListener#onFocusChange", new Object[] {oldFocus, newFocus});
+            mInvocations.add(invocation);
+        }
+
+        public void verify() {
+            assertSame("All focus change callback should be invoked.", 3, mInvocations.size());
+            assertInvioked("Callback for View clearing focus explected.", 0,
+                    "OnFocusChangeListener#onFocusChange",
+                    new Object[] {mClearingFocusView, false});
+            assertInvioked("Callback for View global focus change explected.", 1,
+                    "OnFocusChangeListener#onFocusChange", new Object[] {mClearingFocusView,
+                    mGainingFocusView});
+            assertInvioked("Callback for View gaining focus explected.", 2,
+                    "OnFocusChangeListener#onFocusChange", new Object[] {mGainingFocusView, true});
+        }
+
+        private void assertInvioked(String message, int order, String methodName,
+                Object[] arguments) {
+            CallbackInvocation invocation = mInvocations.get(order);
+            assertEquals(message, methodName, invocation.mMethodName);
+            assertEquals(message, arguments[0], invocation.mArguments[0]);
+            assertEquals(message, arguments[1], invocation.mArguments[1]);
+        }
+    }
 }
diff --git a/docs/html/guide/appendix/market-filters.jd b/docs/html/guide/appendix/market-filters.jd
index 07b9370..d9b2155 100644
--- a/docs/html/guide/appendix/market-filters.jd
+++ b/docs/html/guide/appendix/market-filters.jd
@@ -165,10 +165,10 @@
 
     <p><strong>Example 1</strong><br />
     The manifest declares <code>&lt;uses-sdk android:minSdkVersion="3"&gt;</code>
-    and does not does not include a <code>&lt;supports-screens&gt;</code> element.
-    <strong>Result</strong>: Android Market will not show the app to a user of a
-    small-screen device, but will show it to users of normal and large-screen
-    devices,  users, unless  other filters apply. </p>
+    and does not include a <code>&lt;supports-screens&gt;</code> element.
+    <strong>Result</strong>: Android Market does not show the app to a user of a
+    small-screen device, but does show it to users of normal and large-screen
+    devices, unless  other filters also exclude those devices. </p>
     <p><strong>Example 2<br />
     </strong>The manifest declares <code>&lt;uses-sdk android:minSdkVersion="3"
     android:targetSdkVersion="4"&gt;</code> and does not include a
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 4e5badd..4a9a684 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -8,15 +8,16 @@
 <ul>
 
   <li>
-    <h2><span class="en">Android Basics</span>
-        <span class="de" style="display:none">Einführung in Android</span>
-        <span class="es" style="display:none">Información básica sobre Android</span>
-        <span class="fr" style="display:none">Présentation d'Android</span>
-        <span class="it" style="display:none">Nozioni di base su Android</span>
-        <span class="ja" style="display:none">Android の基本</span>
-        <span class="zh-CN" style="display:none">Android 基础知识</span>
-        <span class="zh-TW" style="display:none">Android 簡介</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Android Basics</span>
+      <span class="de" style="display:none">Einführung in Android</span>
+      <span class="es" style="display:none">Información básica sobre Android</span>
+      <span class="fr" style="display:none">Présentation d'Android</span>
+      <span class="it" style="display:none">Nozioni di base su Android</span>
+      <span class="ja" style="display:none">Android の基本</span>
+      <span class="zh-CN" style="display:none">Android 基础知识</span>
+      <span class="zh-TW" style="display:none">Android 簡介</span>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>guide/basics/what-is-android.html">
         <span class="en">What Is Android?</span>
@@ -46,7 +47,7 @@
   </li>
 
   <li>
-    <h2>
+    <span class="heading">
       <span class="en">Framework Topics</span>
       <span class="de" style="display:none">Framework-Themen</span>
       <span class="es" style="display:none">Temas sobre el framework</span>
@@ -55,7 +56,7 @@
       <span class="ja" style="display:none">フレームワーク トピック</span>
       <span class="zh-CN" style="display:none">框架主题</span>
       <span class="zh-TW" style="display:none">架構主題</span>
-    </h2>
+    </span>
     <ul>
       <li class="toggle-list">
         <div><a href="<?cs var:toroot ?>guide/topics/fundamentals/activities.html">
@@ -130,7 +131,7 @@
               </a></li>
           <li><a href="<?cs var:toroot ?>guide/topics/ui/menus.html">
                <span class="en">Menus</span>
-              </a></li>
+              </a> <span class="new">updated</span></li>
           <li><a href="<?cs var:toroot ?>guide/topics/ui/actionbar.html">
                <span class="en">Action Bar</span>
               </a></li>
@@ -443,9 +444,9 @@
   </li>
 
   <li>
-    <h2>
+    <span class="heading">
       <span class="en">Android Market Topics</span>
-    </h2>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>guide/publishing/publishing.html">
           <span class="en">Publishing on Android Market</span>
@@ -489,15 +490,16 @@
 
 
   <li>
-    <h2><span class="en">Developing</span>
-               <span class="de" style="display:none">Entwicklung</span>
-               <span class="es" style="display:none">Desarrollo</span>
-               <span class="fr" style="display:none">Développement</span>
-               <span class="it" style="display:none">Sviluppo</span>
-               <span class="ja" style="display:none">開発</span>
-               <span class="zh-CN" style="display:none">开发</span>
-               <span class="zh-TW" style="display:none">開發</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Developing</span>
+      <span class="de" style="display:none">Entwicklung</span>
+      <span class="es" style="display:none">Desarrollo</span>
+      <span class="fr" style="display:none">Développement</span>
+      <span class="it" style="display:none">Sviluppo</span>
+      <span class="ja" style="display:none">開発</span>
+      <span class="zh-CN" style="display:none">开发</span>
+      <span class="zh-TW" style="display:none">開發</span>
+    </span>
     <ul>
   <!--<li><a href="">Developing for Android</a></li>
       signing, upgrading, selecting a package name, select device profile, touch, trackball, dpad available, etc. -->
@@ -683,15 +685,16 @@
   </li>
 
   <li>
-    <h2><span class="en">Publishing</span>
-        <span class="de" style="display:none">Veröffentlichung</span>
-        <span class="es" style="display:none">Publicación</span>
-        <span class="fr" style="display:none">Publication</span>
-        <span class="it" style="display:none">Pubblicazione</span>
-        <span class="ja" style="display:none">公開</span>
-        <span class="zh-CN" style="display:none">发布</span>
-        <span class="zh-TW" style="display:none">發佈</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Publishing</span>
+      <span class="de" style="display:none">Veröffentlichung</span>
+      <span class="es" style="display:none">Publicación</span>
+      <span class="fr" style="display:none">Publication</span>
+      <span class="it" style="display:none">Pubblicazione</span>
+      <span class="ja" style="display:none">公開</span>
+      <span class="zh-CN" style="display:none">发布</span>
+      <span class="zh-TW" style="display:none">發佈</span>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>guide/publishing/publishing_overview.html">
             <span class="en">Publishing Overview</span>
@@ -733,15 +736,16 @@
   </li>
 
   <li>
-    <h2><span class="en">Best Practices</span>
-               <span class="de" style="display:none">Bewährte Verfahren</span>
-               <span class="es" style="display:none">Prácticas recomendadas</span>
-               <span class="fr" style="display:none">Meilleures pratiques</span>
-               <span class="it" style="display:none">Best practice</span>
-               <span class="ja" style="display:none">ベスト プラクティス</span>
-               <span class="zh-CN" style="display:none">最佳实践</span>
-               <span class="zh-TW" style="display:none">最佳實務</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Best Practices</span>
+      <span class="de" style="display:none">Bewährte Verfahren</span>
+      <span class="es" style="display:none">Prácticas recomendadas</span>
+      <span class="fr" style="display:none">Meilleures pratiques</span>
+      <span class="it" style="display:none">Best practice</span>
+      <span class="ja" style="display:none">ベスト プラクティス</span>
+      <span class="zh-CN" style="display:none">最佳实践</span>
+      <span class="zh-TW" style="display:none">最佳實務</span>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>guide/practices/compatibility.html">
             <span class="en">Compatibility</span>
@@ -837,8 +841,9 @@
   </li>
 
   <li>
-    <h2><span class="en">Web Applications</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Web Applications</span>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>guide/webapps/index.html">
             <span class="en">Web Apps Overview</span>
@@ -859,15 +864,16 @@
   </li>
 
   <li>
-    <h2><span class="en">Appendix</span>
-               <span class="de" style="display:none">Anhang</span>
-               <span class="es" style="display:none">Apéndice</span>
-               <span class="fr" style="display:none">Annexes</span>
-               <span class="it" style="display:none">Appendice</span>
-               <span class="ja" style="display:none">付録</span>
-               <span class="zh-CN" style="display:none">附录</span>
-               <span class="zh-TW" style="display:none">附錄</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Appendix</span>
+      <span class="de" style="display:none">Anhang</span>
+      <span class="es" style="display:none">Apéndice</span>
+      <span class="fr" style="display:none">Annexes</span>
+      <span class="it" style="display:none">Appendice</span>
+      <span class="ja" style="display:none">付録</span>
+      <span class="zh-CN" style="display:none">附录</span>
+      <span class="zh-TW" style="display:none">附錄</span>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>guide/appendix/api-levels.html">
             <span class="en">Android API Levels</span>
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index b83bde7..e59fa0f 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -113,9 +113,10 @@
 href="{@docRoot}guide/topics/ui/menus.html#OptionsMenu">options menu</a> directly in the action bar,
 as "action items." Action items can also provide an "action view," which provides an embedded
 widget for even more immediate action behaviors. Menu items that are not promoted
-to an action item are available in the overflow menu, revealed by either the device MENU button
+to an action item are available in the overflow menu, revealed by either the device <em>Menu</em>
+button
 (when available) or by an "overflow menu" button in the action bar (when the device does not
-include a MENU button).</p>
+include a <em>Menu</em> button).</p>
 </li>
 </ul>
 
@@ -125,6 +126,10 @@
 landscape handset), showing the logo on the left, navigation tabs, and an action item on the
 right (plus the overflow menu button).</p>
 
+<p class="note"><strong>Note:</strong> If you're looking for information about the contextual
+action bar for displaying contextual action items, see the <a
+href="{@docRoot}guide/topics/ui/menus.html#context-menu">Menu</a> guide.</p>
+
 
 <div class="design-announce">
 <p><strong>Action Bar Design</strong></p>
@@ -225,9 +230,10 @@
 href="{@docRoot}guide/topics/ui/menus.html#OptionsMenu">options menu</a>. To do this, you can
 declare that the menu item should appear in the action bar as an "action item." An action item can
 include an icon and/or a text title. If a menu item does not appear as an action item, then the
-system places it in the overflow menu. The overflow menu is revealed either by the device MENU
+system places it in the overflow menu. The overflow menu is revealed either by the device
+<em>Menu</em>
 button (if provided by the device) or an additional button in the action bar (if the device does not
-provide the MENU button).</p>
+provide the <em>Menu</em> button).</p>
 
 <div class="figure" style="width:359px">
   <img src="{@docRoot}images/ui/actionbar-item-withtext.png" height="57" alt="" />
@@ -1421,7 +1427,7 @@
     &lt;/style>
 
     &lt;!-- style for the action bar tab text -->
-    &lt;style name="CustomTabTextStyle">
+    &lt;style name="CustomTabTextStyle" parent="@android:style/TextAppearance.Holo">
         &lt;item name="android:textColor">#2456c2&lt;/item>
     &lt;/style>
 &lt;/resources>
@@ -1437,8 +1443,7 @@
 manifest file like this:</p>
 
 <pre>
-&lt;application android:theme="&#64;style/CustomActivityTheme"
-             ... />
+&lt;application android:theme="&#64;style/CustomActivityTheme" ... />
 </pre>
 
 <p>For more information about using style and theme resources in your application, read <a
@@ -1457,7 +1462,7 @@
 parent action bar style such as {@link android.R.style#Widget_Holo_ActionBar
 Widget.Holo.ActionBar}.</p>
 
-<p>For example, if you want to change the action bar's background, you could use the following
+<p>For example, if you want to change the action bar's background, you can use the following
 styles:</p>
 
 <pre>
@@ -1465,14 +1470,15 @@
 &lt;resources>
     &lt;!-- the theme applied to the application or activity -->
     &lt;style name="CustomActivityTheme" parent="@android:style/Theme.Holo">
-        &lt;item name="android:actionBarTabTextStyle">@style/customTabTextStyle&lt;/item>
+        &lt;item name="android:actionBarStyle">@style/MyActionBar&lt;/item>
         &lt;!-- other activity and action bar styles here -->
     &lt;/style>
 
-    &lt;!-- style for the action bar, simply to change the background -->
-    &lt;style parent="@android:style/Widget.Holo.ActionBar">
+    &lt;!-- style for the action bar backgrounds -->
+    &lt;style name="MyActionBar" parent="@android:style/Widget.Holo.ActionBar">
         &lt;item name="android:background">@drawable/ab_background&lt;/item>
-        &lt;item name="android:backgroundSplit">@drawable/ab_background&lt;/item>
+        &lt;item name="android:backgroundStacked">@drawable/ab_background&lt;/item>
+        &lt;item name="android:backgroundSplit">@drawable/ab_split_background&lt;/item>
     &lt;/style>
 &lt;/resources>
 </pre>
diff --git a/docs/html/guide/topics/ui/how-android-draws.jd b/docs/html/guide/topics/ui/how-android-draws.jd
index 3a57afa..6a8cd86 100644
--- a/docs/html/guide/topics/ui/how-android-draws.jd
+++ b/docs/html/guide/topics/ui/how-android-draws.jd
@@ -62,7 +62,7 @@
 
    <p>
    The measure pass uses two classes to communicate dimensions. The
-   {@link android.view.View.MeasureSpec} class is used by Views to tell their parents how they
+   {@link android.view.ViewGroup.LayoutParams} class is used by Views to tell their parents how they
    want to be measured and positioned. The base LayoutParams class just
    describes how big the View wants to be for both width and height. For each
    dimension, it can specify one of:</p>
diff --git a/docs/html/guide/topics/ui/menus.jd b/docs/html/guide/topics/ui/menus.jd
index 7b5b3dc..a2313b3 100644
--- a/docs/html/guide/topics/ui/menus.jd
+++ b/docs/html/guide/topics/ui/menus.jd
@@ -6,77 +6,129 @@
 <div id="qv-wrapper">
 <div id="qv">
   <h2>In this document</h2>
-  <ol>
-    <li><a href="#xml">Creating a Menu Resource</a></li>
-    <li><a href="#Inflating">Inflating a Menu Resource</a>
-    <li><a href="#options-menu">Creating an Options Menu</a>
-      <ol>
-        <li><a href="#ChangingTheMenu">Changing menu items at runtime</a></li>
-      </ol>
-    </li>
-    <li><a href="#context-menu">Creating a Context Menu</a></li>
-    <li><a href="#submenu">Creating a Submenu</a></li>
-    <li><a href="#features">Other Menu Features</a>
-      <ol>
-        <li><a href="#groups">Menu groups</a></li>
-        <li><a href="#checkable">Checkable menu items</a></li>
-        <li><a href="#shortcuts">Shortcut keys</a></li>
-        <li><a href="#intents">Dynamically adding menu intents</a></li>
-      </ol>
-    </li>
-  </ol>
+<ol>
+  <li><a href="#xml">Defining a Menu in XML</a></li>
+  <li><a href="#options-menu">Creating an Options Menu</a>
+    <ol>
+      <li><a href="#RespondingOptionsMenu">Handling click events</a></li>
+      <li><a href="#ChangingTheMenu">Changing menu items at runtime</a></li>
+    </ol>
+  </li>
+  <li><a href="#context-menu">Creating Contextual Menus</a>
+    <ol>
+      <li><a href="#FloatingContextMenu">Creating a floating context menu</a></li>
+      <li><a href="#CAB">Using the contextual action bar</a></li>
+    </ol>
+  </li>
+  <li><a href="#PopupMenu">Creating a Popup Menu</a>
+    <ol>
+      <li><a href="#PopupEvents">Handling click events</a></li>
+    </ol>
+  </li>
+  <li><a href="#groups">Creating Menu Groups</a>
+    <ol>
+      <li><a href="#checkable">Using checkable menu items</a></li>
+    </ol>
+  </li>
+  <li><a href="#intents">Adding Menu Items Based on an Intent</a>
+    <ol>
+      <li><a href="#AllowingToAdd">Allowing your activity to be added to other menus</a></li>
+    </ol>
+  </li>
+</ol>
 
   <h2>Key classes</h2>
   <ol>
     <li>{@link android.view.Menu}</li>
     <li>{@link android.view.MenuItem}</li>
     <li>{@link android.view.ContextMenu}</li>
-    <li>{@link android.view.SubMenu}</li>
+    <li>{@link android.view.ActionMode}</li>
   </ol>
 
   <h2>See also</h2>
   <ol>
     <li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a></li>
     <li><a href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a></li>
+    <li><a
+href="http://android-developers.blogspot.com/2012/01/say-goodbye-to-menu-button.html">Say
+Goodbye to the Menu Button</a></li>
   </ol>
 </div>
 </div>
 
-<p>Menus are an important part of an activity's user interface, which provide users a familiar
-way to perform actions. Android offers a simple framework for you to add standard
-menus to your application.</p>
+<p>Menus are a common user interface component in many types of applications. To provide a familiar
+and consistent user experience, you should use the {@link android.view.Menu} APIs to present user
+actions and other options in your activities.</p>
 
-<p>There are three types of application menus:</p>
+<p>Beginning with Android 3.0 (API level 11), Android-powered devices are no longer required to
+provide a dedicated <em>Menu</em> button. With this change, Android apps should migrate away from a
+dependence on the traditional 6-item menu panel and instead provide an action bar to present common
+user actions.</p>
+
+<p>Although the design and user experience for some menu items have changed, the semantics to define
+a set of actions and options is still based on the {@link android.view.Menu} APIs. This
+guide shows how to create the three fundamental types of menus or action presentations on all
+versions of Android:</p>
+
 <dl>
-  <dt><strong>Options Menu</strong></dt>
-    <dd>The primary collection of menu items for an activity, which appears when the user touches
-the MENU button. When your application is running on Android 3.0 or later, you can provide
-quick access to select menu items by placing them directly in the <a
-href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>, as "action items."</dd>
-  <dt><strong>Context Menu</strong></dt>
-    <dd>A floating list of menu items that appears when the user touches and holds a view
-that's registered to provide a context menu.
+  <dt><strong>Options menu and action bar</strong></dt>
+    <dd>The <a href="#options-menu">options menu</a> is the primary collection of menu items for an
+activity. It's where you should place actions that have a global impact on the app, such as
+"Search," "Compose email," and "Settings."
+  <p>If you're developing for Android 2.3 or lower, users can
+reveal the options menu panel by pressing the <em>Menu</em> button.</p>
+  <p>On Android 3.0 and higher, items from the options menu are presented by the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a> as a combination of on-screen action
+items and overflow options. Beginning with Android 3.0, the <em>Menu</em> button is deprecated (some
+devices
+don't have one), so you should migrate toward using the action bar to provide access to actions and
+other options.</p>
+  <p>See the section about <a href="#options-menu">Creating an Options Menu</a>.</p>
+    </dd>
+    
+  <dt><strong>Context menu and contextual action mode</strong></dt>
+  
+   <dd>A context menu is a <a href="#FloatingContextMenu">floating menu</a> that appears when the
+user performs a long-click on an element. It provides actions that affect the selected content or
+context frame.
+  <p>When developing for Android 3.0 and higher, you should instead use the <a
+href="#CAB">contextual action mode</a> to enable actions on selected content. This mode displays
+action items that affect the selected content in a bar at the top of the screen and allows the user
+to select multiple items.</p>
+  <p>See the section about <a href="#context-menu">Creating Contextual Menus</a>.</p>
 </dd>
-  <dt><strong>Submenu</strong></dt>
-    <dd>A floating list of menu items that appears when the user touches a menu item that contains
-a nested menu.</dd>
+    
+  <dt><strong>Popup menu</strong></dt>
+    <dd>A popup menu displays a list of items in a vertical list that's anchored to the view that
+invoked the menu. It's good for providing an overflow of actions that relate to specific content or
+to provide options for a second part of a command. Actions in a popup menu should
+<strong>not</strong> directly affect the corresponding content&mdash;that's what contextual actions
+are for. Rather, the popup menu is for extended actions that relate to regions of content in your
+activity.
+  <p>See the section about <a href="#PopupMenu">Creating a Popup Menu</a>.</p>
+</dd>
 </dl>
 
-<p>This document shows you how to create each type of menu, using XML to define the content of
-the menu and callback methods in your activity to respond when the user selects an item.</p>
 
 
+<h2 id="xml">Defining a Menu in XML</h2>
 
-<h2 id="xml">Creating a Menu Resource</h2>
+<p>For all menu types, Android provides a standard XML format to define menu items.
+Instead of building a menu in your activity's code, you should define a menu and all its items in an
+XML <a href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>. You can then
+inflate the menu resource (load it as a {@link android.view.Menu} object) in your activity or
+fragment.</p>
 
-<p>Instead of instantiating a {@link android.view.Menu} in your application code, you should
-define a menu and all its items in an XML <a
-href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>, then inflate the menu
-resource (load it as a programmable object) in your application code. Using a menu resource to
-define your menu is a good practice because it separates the content for the menu from your
-application code. It's also easier to visualize the structure and content of a menu in XML.</p>
+<p>Using a menu resource is a good practice for a few reasons:</p>
+<ul>
+  <li>It's easier to visualize the menu structure in XML.</li>
+  <li>It separates the content for the menu from your application's behavioral code.</li>
+  <li>It allows you to create alternative menu configurations for different platform versions,
+screen sizes, and other configurations by leveraging the <a
+href="{@docRoot}guide/topics/resources/index.html">app resources</a> framework.</li>
+</ul>
 
-<p>To create a menu resource, create an XML file inside your project's <code>res/menu/</code>
+<p>To define the menu, create an XML file inside your project's <code>res/menu/</code>
 directory and build the menu with the following elements:</p>
 <dl>
   <dt><code>&lt;menu></code></dt>
@@ -90,8 +142,8 @@
     
   <dt><code>&lt;group></code></dt>
     <dd>An optional, invisible container for {@code &lt;item&gt;} elements. It allows you to
-categorize menu items so they share properties such as active state and visibility. See the
-section about <a href="#groups">Menu groups</a>.</dd>
+categorize menu items so they share properties such as active state and visibility. For more
+information, see the section about <a href="#groups">Creating Menu Groups</a>.</dd>
 </dl>
 
 
@@ -101,14 +153,17 @@
 &lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
     &lt;item android:id="@+id/new_game"
           android:icon="@drawable/ic_new_game"
-          android:title="@string/new_game" /&gt;
+          android:title="@string/new_game"
+          android:showAsAction="ifRoom"/&gt;
     &lt;item android:id="@+id/help"
           android:icon="@drawable/ic_help"
           android:title="@string/help" /&gt;
 &lt;/menu&gt;
 </pre>
 
-<p>This example defines a menu with two items. Each item includes the attributes:</p>
+<p>The <code>&lt;item></code> element supports several attributes you can use to define an item's
+appearance and behavior. The items in the above menu include the following attributes:</p>
+
 <dl>
   <dt>{@code android:id}</dt>
     <dd>A resource ID that's unique to the item, which allows the application can recognize the item
@@ -117,312 +172,24 @@
     <dd>A reference to a drawable to use as the item's icon.</dd>
   <dt>{@code android:title}</dt>
     <dd>A reference to a string to use as the item's title.</dd>
+  <dt>{@code android:showAsAction}</dt>
+    <dd>Specifies when and how this item should appear as an action item in the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>.</dd>
 </dl>
 
-<p>There are many more attributes you can include in an {@code &lt;item&gt;}, including some that
- specify how the item may appear in the <a
-href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>. For more information about the XML
-syntax and attributes for a menu resource, see the <a
-href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a> reference.</p>
+<p>These are the most important attributes you should use, but there are many more available.
+For information about all the supported attributes, see the <a
+href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a> document.</p>
 
-
-
-<h2 id="Inflating">Inflating a Menu Resource</h2>
-
-<p>From your application code, you can inflate a menu resource (convert the XML resource into a
-programmable object) using
-{@link android.view.MenuInflater#inflate(int,Menu) MenuInflater.inflate()}. For
-example, the following code inflates the <code>game_menu.xml</code> file defined above, during the
-{@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} callback method, to
-use the menu as the activity's Options Menu:</p>
-
-<pre>
-&#64;Override
-public boolean onCreateOptionsMenu(Menu menu) {
-    MenuInflater inflater = getMenuInflater();
-    inflater.inflate(R.menu.game_menu, menu);
-    return true;
-}
-</pre>
-
-<p>The {@link android.app.Activity#getMenuInflater()} method returns a {@link
-android.view.MenuInflater} for the activity. With this object, you can call {@link
-android.view.MenuInflater#inflate(int,Menu) inflate()}, which inflates a menu resource into a
-{@link android.view.Menu} object. In this example, the menu resource defined by
-<code>game_menu.xml</code>
-is inflated into the {@link android.view.Menu} that was passed into {@link
-android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()}. (This callback method for
-the Options Menu is discussed more in the next section.)</p>
-
-
-
-<h2 id="options-menu">Creating an Options Menu</h2>
-
-<div class="figure" style="width:200px">
-  <img src="{@docRoot}images/options_menu.png" height="333" alt="" />
-  <p class="img-caption"><strong>Figure 1.</strong> Screenshot of the Options Menu in the
-Browser.</p>
-</div>
-
-<p>The Options Menu is where you should include basic activity actions and necessary navigation
-items (for example, a button to open the application settings). Items in the Options Menu are
-accessible in two distinct ways: the MENU button or in the <a
-href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> (on devices running Android 3.0
-or higher).</p>
-
-<p>When running on a device with Android 2.3 and lower, the Options Menu appears at the bottom of
-the screen, as shown in figure 1. When opened, the first visible portion of the Options Menu is
-the icon menu. It holds the first six menu items. If you add more than six items to the
-Options Menu, Android places the sixth item and those after it into the overflow menu, which the
-user can open by touching the "More" menu item.</p>
-
-<p>On Android 3.0 and higher, items from the Options Menu is placed in the Action Bar, which appears
-at the top of the activity in place of the traditional title bar. By default all items from the
-Options Menu are placed in the overflow menu, which the user can open by touching the menu icon
-on the right side of the Action Bar. However, you can place select menu items directly in the
-Action Bar as "action items," for instant access, as shown in figure 2.</p>
-
-<p>When the Android system creates the Options Menu for the first time, it calls your
-activity's {@link android.app.Activity#onCreateOptionsMenu(Menu)
-onCreateOptionsMenu()} method. Override this method in your activity
-and populate the {@link android.view.Menu} that is passed into the method,
-{@link android.view.Menu} by inflating a menu resource as described above in <a
-href="#Inflating">Inflating a Menu Resource</a>. For example:</p>
-
-<pre>
-&#64;Override
-public boolean onCreateOptionsMenu(Menu menu) {
-    MenuInflater inflater = getMenuInflater();
-    inflater.inflate(R.menu.game_menu, menu);
-    return true;
-}
-</pre>
-
-<div class="figure" style="width:450px">
-<img src="{@docRoot}images/ui/actionbar.png" alt="" />
-<p class="img-caption"><strong>Figure 2.</strong> Action bar from the <a
-href="{@docRoot}resources/samples/HoneycombGallery/index.html">Honeycomb Gallery</a> app, including
-navigation tabs and a camera action item (plus the overflow menu button).</p>
-</div>
-
-<p>You can also populate the menu in code, using {@link android.view.Menu#add(int,int,int,int)
-add()} to add items to the {@link android.view.Menu}.</p>
-
-<p class="note"><strong>Note:</strong> On Android 2.3 and lower, the system calls {@link
-android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} to create the Options Menu
-when the user opens it for the first time, but on Android 3.0 and greater, the system creates it as
-soon as the activity is created, in order to populate the Action Bar.</p>
-
-
-<h3 id="RespondingOptionsMenu">Responding to user action</h3>
-
-<p>When the user selects a menu item from the Options Menu (including action items in the
-Action Bar), the system calls your activity's
-{@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}
-method. This method passes the
-{@link android.view.MenuItem} that the user selected. You can identify the menu item by calling
-{@link android.view.MenuItem#getItemId()}, which returns the unique ID for the menu
-item (defined by the {@code android:id} attribute in the menu resource or with an integer
-given to the {@link android.view.Menu#add(int,int,int,int) add()} method). You can match this ID
-against known menu items and perform the appropriate action. For example:</p>
-
-<pre>
-&#64;Override
-public boolean onOptionsItemSelected(MenuItem item) {
-    // Handle item selection
-    switch (item.getItemId()) {
-    case R.id.new_game:
-        newGame();
-        return true;
-    case R.id.help:
-        showHelp();
-        return true;
-    default:
-        return super.onOptionsItemSelected(item);
-    }
-}
-</pre>
-
-<p>In this example, {@link android.view.MenuItem#getItemId()} queries the ID for the selected menu
-item and the switch statement compares the ID against the resource IDs that were assigned to menu
-items in the XML resource. When a switch case successfully handles the menu item, it
-returns {@code true} to indicate that the item selection was handled. Otherwise, the default
-statement passes the menu item to the super class, in
-case it can handle the item selected. (If you've directly extended the {@link android.app.Activity}
-class, then the super class returns {@code false}, but it's a good practice to
-pass unhandled menu items to the super class instead of directly returning {@code false}.)</p>
-
-<p>Additionally, Android 3.0 adds the ability for you to define the on-click behavior for a menu
-item in the <a href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a> XML,
-using the {@code android:onClick} attribute. So you don't need to implement {@link
-android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}. Using the {@code
-android:onClick} attribute, you can specify a method to call when the user selects the menu item.
-Your activity must then implement the method specified in the {@code android:onClick} attribute so 
-that it accepts a single {@link android.view.MenuItem} parameter&mdash;when the system calls this
-method, it passes the menu item selected.</p>
-
-<p class="note"><strong>Tip:</strong> If your application contains multiple activities and
-some of them provide the same Options Menu, consider creating
-an activity that implements nothing except the {@link android.app.Activity#onCreateOptionsMenu(Menu)
-onCreateOptionsMenu()} and {@link android.app.Activity#onOptionsItemSelected(MenuItem)
-onOptionsItemSelected()} methods. Then extend this class for each activity that should share the
-same Options Menu. This way, you have to manage only one set of code for handling menu
-actions and each descendant class inherits the menu behaviors.<br/><br/>
-If you want to add menu items to one of your descendant activities,
-override {@link android.app.Activity#onCreateOptionsMenu(Menu)
-onCreateOptionsMenu()} in that activity. Call {@code super.onCreateOptionsMenu(menu)} so the
-original menu items are created, then add new menu items with {@link
-android.view.Menu#add(int,int,int,int) menu.add()}. You can also override the super class's
-behavior for individual menu items.</p>
-
-
-<h3 id="ChangingTheMenu">Changing menu items at runtime</h3>
-
-<p>Once the activity is created, the {@link android.app.Activity#onCreateOptionsMenu(Menu)
-onCreateOptionsMenu()} method is
-called only once, as described above. The system keeps and re-uses the {@link
-android.view.Menu} you define in this method until your activity is destroyed. If you want to change
-the Options Menu any time after it's first created, you must override the
-{@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()} method. This passes
-you the {@link android.view.Menu} object as it currently exists. This is useful if you'd like to
-remove, add, disable, or enable menu items depending on the current state of your application.</p>
-
-<p>On Android 2.3 and lower, the system calls {@link android.app.Activity#onPrepareOptionsMenu(Menu)
-onPrepareOptionsMenu()} each time the user opens the Options Menu.</p>
-
-<p>On Android 3.0 and higher, you must call {@link android.app.Activity#invalidateOptionsMenu
-invalidateOptionsMenu()} when you want to update the menu, because the menu is always open. The
-system will then call {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()}
-so you can update the menu items.</p>
-
-<p class="note"><strong>Note:</strong> 
-You should never change items in the Options Menu based on the {@link android.view.View} currently
-in focus. When in touch mode (when the user is not using a trackball or d-pad), views
-cannot take focus, so you should never use focus as the basis for modifying
-items in the Options Menu. If you want to provide menu items that are context-sensitive to a {@link
-android.view.View}, use a <a href="#context-menu">Context Menu</a>.</p>
-
-<p>If you're developing for Android 3.0 or higher, be sure to also read the <a
-href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> developer guide.</p>
-
-
-
-
-<h2 id="context-menu">Creating a Context Menu</h2>
-
-<p>A context menu is conceptually similar to the menu displayed when the user performs a
-"right-click" on a PC. You should use a context menu to provide the user access to
-actions that pertain to a specific item in the user interface. On Android, a context menu is
-displayed when the user performs a "long press" (press and hold) on an item.</p>
-
-<p>You can create a context menu for any View, though context menus are most often used for items in
-a {@link android.widget.ListView}. When the user performs a long-press on an item in a ListView and
-the list is registered to provide a context menu, the list item signals to the user that a context
-menu is available by animating its background color&mdash;it transitions from
-orange to white before opening the context menu. (The Contacts application demonstrates this
-feature.)</p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h3>Register a ListView</h3>
-<p>If your activity uses a {@link android.widget.ListView} and
-you want all list items to provide a context menu, register all items for a context
-menu by passing the {@link android.widget.ListView} to {@link
-android.app.Activity#registerForContextMenu(View) registerForContextMenu()}. For
-example, if you're using a {@link android.app.ListActivity}, register all list items like this:</p>
-<p><code>registerForContextMenu({@link android.app.ListActivity#getListView()});</code></p>
-</div>
-</div>
-
-<p>In order for a View to provide a context menu, you must "register" the view for a context
-menu. Call {@link android.app.Activity#registerForContextMenu(View) registerForContextMenu()} and
-pass it the {@link android.view.View} you want to give a context menu. When this View then
-receives a long-press, it displays a context menu.</p>
-
-<p>To define the context menu's appearance and behavior, override your activity's context menu
-callback methods, {@link android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenuInfo)
-onCreateContextMenu()} and
-{@link android.app.Activity#onContextItemSelected(MenuItem) onContextItemSelected()}.</p>
-
-<p>For example, here's an {@link
-android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenuInfo)
-onCreateContextMenu()} that uses the {@code context_menu.xml} menu resource:</p>
-<pre>
-&#64;Override
-public void onCreateContextMenu(ContextMenu menu, View v,
-                                ContextMenuInfo menuInfo) {
-  super.onCreateContextMenu(menu, v, menuInfo);
-  MenuInflater inflater = getMenuInflater();
-  inflater.inflate(R.menu.context_menu, menu);
-}
-</pre>
-
-<p>{@link android.view.MenuInflater} is used to inflate the context menu from a <a
-href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>. (You can also use
-{@link android.view.Menu#add(int,int,int,int) add()} to add menu items.) The callback method
-parameters include the {@link android.view.View}
-that the user selected and a {@link android.view.ContextMenu.ContextMenuInfo} object that provides
-additional information about the item selected. You might use these parameters to determine
-which context menu should be created, but in this example, all context menus for the activity are
-the same.</p>
-
-<p>Then when the user selects an item from the context menu, the system calls {@link
-android.app.Activity#onContextItemSelected(MenuItem) onContextItemSelected()}. Here is an example
-of how you can handle selected items:</p>
-
-<pre>
-&#64;Override
-public boolean onContextItemSelected(MenuItem item) {
-  AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
-  switch (item.getItemId()) {
-  case R.id.edit:
-    editNote(info.id);
-    return true;
-  case R.id.delete:
-    deleteNote(info.id);
-    return true;
-  default:
-    return super.onContextItemSelected(item);
-  }
-}
-</pre>
-
-<p>The structure of this code is similar to the example for <a href="#options-menu">Creating an
-Options Menu</a>, in which {@link android.view.MenuItem#getItemId()} queries the ID for the selected
-menu item and a switch statement matches the item to the IDs that are defined in the menu resource.
-And like the options menu example, the default statement calls the super class in case it
-can handle menu items not handled here, if necessary.</p>
-
-<p>In this example, the selected item is an item from a {@link android.widget.ListView}. To
-perform an action on the selected item, the application needs to know the list
-ID for the selected item (it's position in the ListView). To get the ID, the application calls
-{@link android.view.MenuItem#getMenuInfo()}, which returns a {@link
-android.widget.AdapterView.AdapterContextMenuInfo} object that includes the list ID for the
-selected item in the {@link android.widget.AdapterView.AdapterContextMenuInfo#id id} field. The
-local methods <code>editNote()</code> and <code>deleteNote()</code> methods accept this list ID to
-perform an action on the data specified by the list ID.</p>
-
-<p class="note"><strong>Note:</strong> Items in a context menu do not support icons or shortcut
-keys.</p>
-
-
-
-<h2 id="submenu">Creating Submenus</h2>
-
-<p>A submenu is a menu that the user can open by selecting an item in another menu. You can add a
-submenu to any menu (except a submenu). Submenus are useful when your application has a lot of
-functions that can be organized into topics, like items in a PC application's menu bar (File, Edit,
-View, etc.).</p>
-
-<p>When creating your <a href="{@docRoot}guide/topics/resources/menu-resource.html">menu
-resource</a>, you can create a submenu by adding a {@code &lt;menu&gt;} element as the child of an
-{@code &lt;item&gt;}. For example:</p>
+<p>You can add a submenu to an item in any menu (except a submenu) by adding a {@code &lt;menu&gt;}
+element as the child of an {@code &lt;item&gt;}. Submenus are useful when your application has a lot
+of functions that can be organized into topics, like items in a PC application's menu bar (File,
+Edit, View, etc.). For example:</p>
 
 <pre>
 &lt;?xml version="1.0" encoding="utf-8"?&gt;
 &lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
     &lt;item android:id="@+id/file"
-          android:icon="@drawable/file"
           android:title="@string/file" &gt;
         &lt;!-- "file" submenu --&gt;
         &lt;menu&gt;
@@ -435,23 +202,625 @@
 &lt;/menu&gt;
 </pre>
 
-<p>When the user selects an item from a submenu, the parent menu's respective on-item-selected
-callback method receives the event. For instance, if the above menu is applied as an Options Menu,
-then the {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} method
-is called when a submenu item is selected.</p>
-
-<p>You can also use {@link android.view.Menu#addSubMenu(int,int,int,int) addSubMenu()} to
-dynamically add a {@link android.view.SubMenu} to an existing {@link android.view.Menu}. This
-returns the new {@link android.view.SubMenu} object, to which you can add
-submenu items, using {@link android.view.Menu#add(int,int,int,int) add()}</p>
+<p>To use the menu in your activity, you need to inflate the menu resource (convert the XML
+resource into a programmable object) using {@link android.view.MenuInflater#inflate(int,Menu)
+MenuInflater.inflate()}. In the following sections, you'll see how to inflate a menu for each
+menu type.</p>
 
 
 
-<h2 id="features">Other Menu Features</h2>
+<h2 id="options-menu">Creating an Options Menu</h2>
 
-<p>Here are some other features that you can apply to most menu items.</p>
+<div class="figure" style="width:200px;margin:0">
+  <img src="{@docRoot}images/options_menu.png" height="333" alt="" />
+  <p class="img-caption"><strong>Figure 1.</strong> Options menu in the
+Browser, on Android 2.3.</p>
+</div>
 
-<h3 id="groups">Menu groups</h3>
+<p>The options menu is where you should include actions and other options that are relevant to the
+current activity context, such as "Search," "Compose email," and "Settings."</p>
+
+<p>Where the items in your options menu appear on the screen depends on the version for which you've
+developed your application:</p>
+
+<ul>
+  <li>If you've developed your application for <strong>Android 2.3.x (API level 10) or
+lower</strong>, the contents of your options menu appear at the bottom of the screen when the user
+presses the <em>Menu</em> button, as shown in figure 1. When opened, the first visible portion is
+the icon
+menu, which holds up to six menu items. If your menu includes more than six items, Android places
+the sixth item and the rest into the overflow menu, which the user can open by selecting
+<em>More</em>.</li>
+
+  <li>If you've developed your application for <strong>Android 3.0 (API level 11) and
+higher</strong>, items from the options menu are available in the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>. By default, the system
+places all items in the action overflow, which the user can reveal with the action overflow icon on
+the right side of the action bar (or by pressing the device <em>Menu</em> button, if available). To
+enable
+quick access to important actions, you can promote a few items to appear in the action bar by adding
+{@code android:showAsAction="ifRoom"} to the corresponding {@code &lt;item&gt;} elements (see figure
+2). <p>For more information about action items and other action bar behaviors, see the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> guide. </p>
+<p class="note"><strong>Note:</strong> Even if you're <em>not</em> developing for Android 3.0 or
+higher, you can build your own action bar layout for a similar effect. For an example of how you can
+support older versions of Android with an action bar, see the <a
+href="{@docRoot}resources/samples/ActionBarCompat/index.html">Action Bar Compatibility</a>
+sample.</p>
+</li>
+</ul>
+
+<img src="{@docRoot}images/ui/actionbar.png" alt="" />
+<p class="img-caption"><strong>Figure 2.</strong> Action bar from the <a
+href="{@docRoot}resources/samples/HoneycombGallery/index.html">Honeycomb Gallery</a> app, showing
+navigation tabs and a camera action item (plus the action overflow button).</p>
+
+<p>You can declare items for the options menu from either your {@link android.app.Activity}
+subclass or a {@link android.app.Fragment} subclass. If both your activity and fragment(s)
+declare items for the options menu, they are combined in the UI. The activity's items appear
+first, followed by those of each fragment in the order in which each fragment is added to the
+activity. If necessary, you can re-order the menu items with the {@code android:orderInCategory}
+attribute in each {@code &lt;item&gt;} you need to move.</p>
+
+<p>To specify the options menu for an activity, override {@link
+android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} (fragments provide their
+own {@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()} callback). In this
+method, you can inflate your menu resource (<a href="#xml">defined in XML</a>) into the {@link
+android.view.Menu} provided in the callback. For example:</p>
+
+<pre>
+&#64;Override
+public boolean onCreateOptionsMenu(Menu menu) {
+    MenuInflater inflater = {@link android.app.Activity#getMenuInflater()};
+    inflater.inflate(R.menu.game_menu, menu);
+    return true;
+}
+</pre>
+
+<p>You can also add menu items using {@link android.view.Menu#add(int,int,int,int)
+add()} and retrieve items with {@link android.view.Menu#findItem findItem()} to revise their
+properties with {@link android.view.MenuItem} APIs.</p>
+
+<p>If you've developed your application for Android 2.3.x and lower, the system calls {@link
+android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} to create the options menu
+when the user opens the menu for the first time. If you've developed for Android 3.0 and higher, the
+system calls {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} when
+starting the activity, in order to show items to the action bar.</p>
+
+
+
+<h3 id="RespondingOptionsMenu">Handling click events</h3>
+
+<p>When the user selects an item from the options menu (including action items in the action bar),
+the system calls your activity's {@link android.app.Activity#onOptionsItemSelected(MenuItem)
+onOptionsItemSelected()} method. This method passes the {@link android.view.MenuItem} selected. You
+can identify the item by calling {@link android.view.MenuItem#getItemId()}, which returns the unique
+ID for the menu item (defined by the {@code android:id} attribute in the menu resource or with an
+integer given to the {@link android.view.Menu#add(int,int,int,int) add()} method). You can match
+this ID against known menu items to perform the appropriate action. For example:</p>
+
+<pre>
+&#64;Override
+public boolean onOptionsItemSelected(MenuItem item) {
+    // Handle item selection
+    switch (item.getItemId()) {
+        case R.id.new_game:
+            newGame();
+            return true;
+        case R.id.help:
+            showHelp();
+            return true;
+        default:
+            return super.onOptionsItemSelected(item);
+    }
+}
+</pre>
+
+<p>When you successfully handle a menu item, return {@code true}. If you don't handle the menu
+item, you should call the superclass implementation of {@link
+android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} (the default
+implementation returns false).</p>
+
+<p>If your activity includes fragments, the system first calls {@link
+android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} for the activity then
+for each fragment (in the order each fragment was added) until one returns
+{@code true} or all fragments have been called.</p>
+
+<p class="note"><strong>Tip:</strong> Android 3.0 adds the ability for you to define the on-click
+behavior for a menu item in XML, using the {@code android:onClick} attribute. The value for the
+attribute must be the name of a method defined by the activity using the menu. The method
+must be public and accept a single {@link android.view.MenuItem} parameter&mdash;when the system
+calls this method, it passes the menu item selected. For more information and an example, see the <a
+href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a> document.</p>
+
+<p class="note"><strong>Tip:</strong> If your application contains multiple activities and
+some of them provide the same options menu, consider creating
+an activity that implements nothing except the {@link android.app.Activity#onCreateOptionsMenu(Menu)
+onCreateOptionsMenu()} and {@link android.app.Activity#onOptionsItemSelected(MenuItem)
+onOptionsItemSelected()} methods. Then extend this class for each activity that should share the
+same options menu. This way, you can manage one set of code for handling menu
+actions and each descendant class inherits the menu behaviors.
+If you want to add menu items to one of the descendant activities,
+override {@link android.app.Activity#onCreateOptionsMenu(Menu)
+onCreateOptionsMenu()} in that activity. Call {@code super.onCreateOptionsMenu(menu)} so the
+original menu items are created, then add new menu items with {@link
+android.view.Menu#add(int,int,int,int) menu.add()}. You can also override the super class's
+behavior for individual menu items.</p>
+
+
+<h3 id="ChangingTheMenu">Changing menu items at runtime</h3>
+
+<p>After the system calls {@link android.app.Activity#onCreateOptionsMenu(Menu)
+onCreateOptionsMenu()}, it retains an instance of the {@link android.view.Menu} you populate and
+will not call {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()}
+again unless the menu is invalidated for some reason. However, you should use {@link
+android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} only to create the initial
+menu state and not to make changes during the activity lifecycle.</p>
+
+<p>If you want to modify the options menu based on 
+events that occur during the activity lifecycle, you can do so in
+the {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()} method. This
+method passes you the {@link android.view.Menu} object as it currently exists so you can modify it,
+such as add, remove, or disable items. (Fragments also provide an {@link
+android.app.Fragment#onPrepareOptionsMenu onPrepareOptionsMenu()} callback.)</p>
+
+<p>On Android 2.3.x and lower, the system calls {@link
+android.app.Activity#onPrepareOptionsMenu(Menu)
+onPrepareOptionsMenu()} each time the user opens the options menu (presses the <em>Menu</em>
+button).</p>
+
+<p>On Android 3.0 and higher, the options menu is considered to always be open when menu items are
+presented in the action bar. When an event occurs and you want to perform a menu update, you must
+call {@link android.app.Activity#invalidateOptionsMenu invalidateOptionsMenu()} to request that the
+system call {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()}.</p>
+
+<p class="note"><strong>Note:</strong> 
+You should never change items in the options menu based on the {@link android.view.View} currently
+in focus. When in touch mode (when the user is not using a trackball or d-pad), views
+cannot take focus, so you should never use focus as the basis for modifying
+items in the options menu. If you want to provide menu items that are context-sensitive to a {@link
+android.view.View}, use a <a href="#context-menu">Context Menu</a>.</p>
+
+
+
+
+<h2 id="context-menu">Creating Contextual Menus</h2>
+
+<div class="figure" style="width:420px;margin-top:-1em">
+  <img src="{@docRoot}images/ui/menu-context.png" alt="" />
+  <p class="img-caption"><strong>Figure 3.</strong> Screenshots of a floating context menu (left)
+and the contextual action bar (right).</p>
+</div>
+
+<p>A contextual menu offers actions that affect a specific item or context frame in the UI. You
+can provide a context menu for any view, but they are most often used for items in a {@link
+android.widget.ListView}, {@link android.widget.GridView}, or other view collections in which
+the user can perform direct actions on each item.</p>
+
+<p>There are two ways to provide contextual actions:</p>
+<ul>
+  <li>In a <a href="#FloatingContextMenu">floating context menu</a>. A menu appears as a
+floating list of menu items (similar to a dialog) when the user performs a long-click (press and
+hold) on a view that declares support for a context menu. Users can perform a contextual
+action on one item at a time.</li>
+
+  <li>In the <a href="#CAB">contextual action mode</a>. This mode is a system implementation of
+{@link android.view.ActionMode} that displays a <em>contextual action bar</em> at the top of the
+screen with action items that affect the selected item(s). When this mode is active, users
+can perform an action on multiple items at once (if your app allows it).</li>
+</ul>
+
+<p class="note"><strong>Note:</strong> The contextual action mode is available on Android 3.0 (API
+level 11) and higher and is the preferred technique for displaying contextual actions when
+available. If your app supports versions lower than 3.0 then you should fall back to a floating
+context menu on those devices.</p>
+
+
+<h3 id="FloatingContextMenu">Creating a floating context menu</h3>
+
+<p>To provide a floating context menu:</p>
+<ol>
+  <li>Register the {@link android.view.View} to which the context menu should be associated by
+calling {@link android.app.Activity#registerForContextMenu(View) registerForContextMenu()} and pass
+it the {@link android.view.View}.
+  <p>If your activity uses a {@link android.widget.ListView} or {@link android.widget.GridView} and
+you want each item to provide the same context menu, register all items for a context menu by
+passing the {@link android.widget.ListView} or {@link android.widget.GridView} to {@link
+android.app.Activity#registerForContextMenu(View) registerForContextMenu()}.</p>
+</li>
+
+  <li>Implement the {@link
+android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()} method
+in your {@link android.app.Activity} or {@link android.app.Fragment}.
+  <p>When the registered view receives a long-click event, the system calls your {@link
+android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()}
+method. This is where you define the menu items, usually by inflating a menu resource. For
+example:</p>
+<pre>
+&#64;Override
+public void onCreateContextMenu(ContextMenu menu, View v,
+                                ContextMenuInfo menuInfo) {
+    super.onCreateContextMenu(menu, v, menuInfo);
+    MenuInflater inflater = getMenuInflater();
+    inflater.inflate(R.menu.context_menu, menu);
+}
+</pre>
+
+<p>{@link android.view.MenuInflater} allows you to inflate the context menu from a <a
+href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>. The callback method
+parameters include the {@link android.view.View}
+that the user selected and a {@link android.view.ContextMenu.ContextMenuInfo} object that provides
+additional information about the item selected. If your activity has several views that each provide
+a different context menu, you might use these parameters to determine which context menu to
+inflate.</p>
+</li>
+
+<li>Implement {@link android.app.Activity#onContextItemSelected(MenuItem)
+onContextItemSelected()}.
+  <p>When the user selects a menu item, the system calls this method so you can perform the
+appropriate action. For example:</p>
+
+<pre>
+&#64;Override
+public boolean onContextItemSelected(MenuItem item) {
+    AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
+    switch (item.getItemId()) {
+        case R.id.edit:
+            editNote(info.id);
+            return true;
+        case R.id.delete:
+            deleteNote(info.id);
+            return true;
+        default:
+            return super.onContextItemSelected(item);
+    }
+}
+</pre>
+
+<p>The {@link android.view.MenuItem#getItemId()} method queries the ID for
+the selected menu item, which you should assign to each menu item in XML using the {@code
+android:id} attribute, as shown in the section about <a href="#xml">Defining a Menu in
+XML</a>.</p>
+
+<p>When you successfully handle a menu item, return {@code true}. If you don't handle the menu item,
+you should pass the menu item to the superclass implementation. If your activity includes fragments,
+the activity receives this callback first. By calling the superclass when unhandled, the system
+passes the event to the respective callback method in each fragment, one at a time (in the order
+each fragment was added) until {@code true} or {@code false} is returned. (The default
+implementation for {@link android.app.Activity} and {@code android.app.Fragment} return {@code
+false}, so you should always call the superclass when unhandled.)</p>
+</li>
+</ol>
+
+
+<h3 id="CAB">Using the contextual action mode</h3>
+
+<p>The contextual action mode is a system implementation of {@link android.view.ActionMode} that
+focuses user interaction toward performing contextual actions. When a
+user enables this mode by selecting an item, a <em>contextual action bar</em> appears at the top of
+the screen to present actions the user can perform on the currently selected item(s). While this
+mode is enabled, the user can select multiple items (if you allow it), deselect items, and continue
+to navigate within the activity (as much as you're willing to allow). The action mode is disabled
+and the contextual action bar disappears when the user deselects all items, presses the BACK button,
+or selects the <em>Done</em> action on the left side of the bar.</p>
+
+<p class="note"><strong>Note:</strong> The contextual action bar is not necessarily
+associated with the <a href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>. They operate
+independently, even though the contextual action bar visually overtakes the action bar
+position.</p>
+
+<p>If you're developing for Android 3.0 (API level 11) or higher, you
+should usually use the contextual action mode to present contextual actions, instead of the <a
+href="#FloatingContextMenu">floating context menu</a>.</p>
+
+<p>For views that provide contextual actions, you should usually invoke the contextual action mode
+upon one of two events (or both):</p>
+<ul>
+  <li>The user performs a long-click on the view.</li>
+  <li>The user selects a checkbox or similar UI component within the view.</li>
+</ul>
+
+<p>How your application invokes the contextual action mode and defines the behavior for each
+action depends on your design. There are basically two designs:</p>
+<ul>
+  <li>For contextual actions on individual, arbitrary views.</li>
+  <li>For batch contextual actions on groups of items in a {@link
+android.widget.ListView} or {@link android.widget.GridView} (allowing the user to select multiple
+items and perform an action on them all).</li>
+</ul>
+
+<p>The following sections describe the setup required for each scenario.</p>
+
+
+<h4 id="CABforViews">Enabling the contextual action mode for individual views</h4>
+
+<p>If you want to invoke the contextual action mode only when the user selects specific
+views, you should:</p>
+<ol>
+  <li>Implement the {@link android.view.ActionMode.Callback} interface. In its callback methods, you
+can specify the actions for the contextual action bar, respond to click events on action items, and
+handle other lifecycle events for the action mode.</li>
+  <li>Call {@link android.app.Activity#startActionMode startActionMode()} when you want to show the
+bar (such as when the user long-clicks the view).</li>
+</ol>
+
+<p>For example:</p>
+
+<ol>
+  <li>Implement the {@link android.view.ActionMode.Callback ActionMode.Callback} interface:
+<pre>
+private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
+
+    // Called when the action mode is created; startActionMode() was called
+    &#64;Override
+    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+        // Inflate a menu resource providing context menu items
+        MenuInflater inflater = mode.getMenuInflater();
+        inflater.inflate(R.menu.context_menu, menu);
+        return true;
+    }
+
+    // Called each time the action mode is shown. Always called after onCreateActionMode, but
+    // may be called multiple times if the mode is invalidated.
+    &#64;Override
+    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+        return false; // Return false if nothing is done
+    }
+
+    // Called when the user selects a contextual menu item
+    &#64;Override
+    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.menu_share:
+                shareCurrentItem();
+                mode.finish(); // Action picked, so close the CAB
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    // Called when the user exits the action mode
+    &#64;Override
+    public void onDestroyActionMode(ActionMode mode) {
+        mActionMode = null;
+    }
+};
+</pre>
+
+<p>Notice that these event callbacks are almost exactly the same as the callbacks for the <a
+href="#options-menu">options menu</a>, except each of these also pass the {@link
+android.view.ActionMode} object associated with the event. You can use {@link
+android.view.ActionMode} APIs to make various changes to the CAB, such as revise the title and
+subtitle with {@link android.view.ActionMode#setTitle setTitle()} and {@link
+android.view.ActionMode#setSubtitle setSubtitle()} (useful to indicate how many items are
+selected).</p>
+
+<p>Also notice that the above sample sets the {@code mActionMode} variable null when the
+action mode is destroyed. In the next step, you'll see how it's initialized and how saving
+the member variable in your activity or fragment can be useful.</p>
+</li>
+
+  <li>Call {@link android.app.Activity#startActionMode startActionMode()} to enable the contextual
+action mode when appropriate, such as in response to a long-click on a {@link
+android.view.View}:</p>
+
+<pre>
+someView.setOnLongClickListener(new View.OnLongClickListener() {
+    // Called when the user long-clicks on someView
+    public boolean onLongClick(View view) {
+        if (mActionMode != null) {
+            return false;
+        }
+
+        // Start the CAB using the ActionMode.Callback defined above
+        mActionMode = getActivity().startActionMode(mActionModeCallback);
+        view.setSelected(true);
+        return true;
+    }
+});
+</pre>
+
+<p>When you call {@link android.app.Activity#startActionMode startActionMode()}, the system returns
+the {@link android.view.ActionMode} created. By saving this in a member variable, you can
+make changes to the contextual action bar in response to other events. In the above sample, the
+{@link android.view.ActionMode} is used to ensure that the {@link android.view.ActionMode} instance
+is not recreated if it's already active, by checking whether the member is null before starting the
+action mode.</p>
+</li>
+</ol>
+
+
+
+<h4 id="CABforListView">Enabling batch contextual actions in a ListView or GridView</h4>
+
+<p>If you have a collection of items in a {@link android.widget.ListView} or {@link
+android.widget.GridView} (or another extension of {@link android.widget.AbsListView}) and want to
+allow users to perform batch actions, you should:</p>
+
+<ul>
+  <li>Implement the {@link android.widget.AbsListView.MultiChoiceModeListener} interface and set it
+for the view group with {@link android.widget.AbsListView#setMultiChoiceModeListener
+setMultiChoiceModeListener()}. In the listener's callback methods, you can specify the actions
+for the contextual action bar, respond to click events on action items, and handle other callbacks
+inherited from the {@link android.view.ActionMode.Callback} interface.</li>
+
+  <li>Call {@link android.widget.AbsListView#setChoiceMode setChoiceMode()} with the {@link
+android.widget.AbsListView#CHOICE_MODE_MULTIPLE_MODAL} argument.</li>
+</ul>
+
+<p>For example:</p>
+
+<pre>
+ListView listView = getListView();
+listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
+listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
+
+    &#64;Override
+    public void onItemCheckedStateChanged(ActionMode mode, int position,
+                                          long id, boolean checked) {
+        // Here you can do something when items are selected/de-selected,
+        // such as update the title in the CAB
+    }
+
+    &#64;Override
+    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+        // Respond to clicks on the actions in the CAB
+        switch (item.getItemId()) {
+            case R.id.menu_delete:
+                deleteSelectedItems();
+                mode.finish(); // Action picked, so close the CAB
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    &#64;Override
+    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+        // Inflate the menu for the CAB
+        MenuInflater inflater = mode.getMenuInflater();
+        inflater.inflate(R.menu.context, menu);
+        return true;
+    }
+
+    &#64;Override
+    public void onDestroyActionMode(ActionMode mode) {
+        // Here you can make any necessary updates to the activity when
+        // the CAB is removed. By default, selected items are deselected/unchecked.
+    }
+
+    &#64;Override
+    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+        // Here you can perform updates to the CAB due to
+        // an {@link android.view.ActionMode#invalidate} request
+        return false;
+    }
+});
+</pre>
+
+<p>That's it. Now when the user selects an item with a long-click, the system calls the {@link
+android.widget.AbsListView.MultiChoiceModeListener#onCreateActionMode onCreateActionMode()}
+method and displays the contextual action bar with the specified actions. While the contextual
+action bar is visible, users can select additional items.</p>
+
+<p>In some cases in which the contextual actions provide common action items, you might
+want to add a checkbox or a similar UI element that allows users to select items, because they
+might not discover the long-click behavior. When a user selects the checkbox, you
+can invoke the contextual action mode by setting the respective list item to the checked
+state with {@link android.widget.AbsListView#setItemChecked setItemChecked()}.</p>
+
+
+
+
+<h2 id="PopupMenu">Creating a Popup Menu</h2>
+
+<div class="figure" style="width:220px">
+<img src="{@docRoot}images/ui/popupmenu.png" alt="" />
+<p><strong>Figure 4.</strong> A popup menu in the Gmail app, anchored to the overflow
+button at the top-right.</p>
+</div>
+
+<p>A {@link android.widget.PopupMenu} is a modal menu anchored to a {@link android.view.View}.
+It appears below the anchor view if there is room, or above the view otherwise. It's useful for:</p>
+<ul>
+  <li>Providing an overflow-style menu for actions that <em>relate to</em> specific content (such as
+Gmail's email headers, shown in figure 4).
+    <p class="note"><strong>Note:</strong> This is not the same as a context menu, which is
+generally for actions that <em>affect</em> selected content. For actions that affect selected
+content, use the <a href="#CAB">contextual action mode</a> or <a
+href="#FloatingContextMenu">floating context menu</a>.</p></li>
+  <li>Providing a second part of a command sentence (such as a button marked "Add"
+that produces a popup menu with different "Add" options).</li>
+  <li>Providing a drop-down similar to {@link android.widget.Spinner} that does not retain
+a persistent selection.</li>
+</ul>
+
+
+<p class="note"><strong>Note:</strong> {@link android.widget.PopupMenu} is available with API
+level 11 and higher.</p>
+
+<p>If you <a href="#xml">define your menu in XML</a>, here's how you can show the popup menu:</p>
+<ol>
+  <li>Instantate a {@link android.widget.PopupMenu} with its constructor, which takes the
+current application {@link android.content.Context} and the {@link android.view.View} to which the
+menu should be anchored.</li>
+  <li>Use {@link android.view.MenuInflater} to inflate your menu resource into the {@link
+android.view.Menu} object returned by {@link
+android.widget.PopupMenu#getMenu() PopupMenu.getMenu()}. On API level 14 and above, you can use
+{@link android.widget.PopupMenu#inflate PopupMenu.inflate()} instead.</li>
+  <li>Call {@link android.widget.PopupMenu#show() PopupMenu.show()}.</li>
+</ol>
+
+<p>For example, here's a button with the {@link android.R.attr#onClick android:onClick} attribute
+that shows a popup menu:</p>
+
+<pre>
+&lt;ImageButton
+    android:layout_width="wrap_content" 
+    android:layout_height="wrap_content" 
+    android:src="@drawable/ic_overflow_holo_dark"
+    android:contentDescription="@string/descr_overflow_button"
+    android:onClick="showPopup" />
+</pre>
+
+<p>The activity can then show the popup menu like this:</p>
+
+<pre>
+public void showPopup(View v) {
+    PopupMenu popup = new PopupMenu(this, v);
+    MenuInflater inflater = popup.getMenuInflater();
+    inflater.inflate(R.menu.actions, popup.getMenu());
+    popup.show();
+}
+</pre>
+
+<p>In API level 14 and higher, you can combine the two lines that inflate the menu with {@link
+android.widget.PopupMenu#inflate PopupMenu.inflate()}.</p>
+
+<p>The menu is dismissed when the user selects an item or touches outside the menu
+area. You can listen for the dismiss event using {@link
+android.widget.PopupMenu.OnDismissListener}.</p>
+
+<h3 id="PopupEvents">Handling click events</h3>
+
+<p>To perform an
+action when the user selects a menu item, you must implement the {@link
+android.widget.PopupMenu.OnMenuItemClickListener} interface and register it with your {@link
+android.widget.PopupMenu} by calling {@link android.widget.PopupMenu#setOnMenuItemClickListener
+setOnMenuItemclickListener()}. When the user selects an item, the system calls the {@link
+android.widget.PopupMenu.OnMenuItemClickListener#onMenuItemClick onMenuItemClick()} callback in
+your interface.</p>
+
+<p>For example:</p>
+
+<pre>
+public void showMenu(View v) {
+    PopupMenu popup = new PopupMenu(this, v);
+
+    // This activity implements OnMenuItemClickListener
+    popup.setOnMenuItemClickListener(this);
+    popup.inflate(R.menu.actions);
+    popup.show();
+}
+
+&#64;Override
+public boolean onMenuItemClick(MenuItem item) {
+    switch (item.getItemId()) {
+        case R.id.archive:
+            archive(item);
+            return true;
+        case R.id.delete:
+            delete(item);
+            return true;
+        default:
+            return false;
+    }
+}
+</pre>
+
+
+<h2 id="groups">Creating Menu Groups</h2>
 
 <p>A menu group is a collection of menu items that share certain traits. With a group, you
 can:</p>
@@ -473,38 +842,41 @@
 <pre>
 &lt;?xml version="1.0" encoding="utf-8"?&gt;
 &lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
-    &lt;item android:id="@+id/item1"
-          android:icon="@drawable/item1"
-          android:title="@string/item1" /&gt;
+    &lt;item android:id="@+id/menu_save"
+          android:icon="@drawable/menu_save"
+          android:title="@string/menu_save" /&gt;
     &lt;!-- menu group --&gt;
-    &lt;group android:id="@+id/group1"&gt;
-        &lt;item android:id="@+id/groupItem1"
-              android:title="@string/groupItem1" /&gt;
-        &lt;item android:id="@+id/groupItem2"
-              android:title="@string/groupItem2" /&gt;
+    &lt;group android:id="@+id/group_delete"&gt;
+        &lt;item android:id="@+id/menu_archive"
+              android:title="@string/menu_archive" /&gt;
+        &lt;item android:id="@+id/menu_delete"
+              android:title="@string/menu_delete" /&gt;
     &lt;/group&gt;
 &lt;/menu&gt;
 </pre>
 
-<p>The items that are in the group appear the same as the first item that is not in a
-group&mdash;all three items in the menu are siblings. However, you can modify the traits of the two
-items in the group by referencing the group ID and using the methods listed above.</p>
+<p>The items that are in the group appear at the same level as the first item&mdash;all three items
+in the menu are siblings. However, you can modify the traits of the two
+items in the group by referencing the group ID and using the methods listed above. The system
+will also never separate grouped items. For example, if you declare {@code
+android:showAsAction="ifRoom"} for each item, they will either both appear in the action
+bar or both appear in the action overflow.</p>
 
 
-<h3 id="checkable">Checkable menu items</h3>
+<h3 id="checkable">Using checkable menu items</h3>
 
 <div class="figure" style="width:200px">
   <img src="{@docRoot}images/radio_buttons.png" height="333" alt="" />
-  <p class="img-caption"><strong>Figure 3.</strong> Screenshot of a submenu with checkable
+  <p class="img-caption"><strong>Figure 5.</strong> Screenshot of a submenu with checkable
 items.</p>
 </div>
 
 <p>A menu can be useful as an interface for turning options on and off, using a checkbox for
 stand-alone options, or radio buttons for groups of
-mutually exclusive options. Figure 2 shows a submenu with items that are checkable with radio
+mutually exclusive options. Figure 5 shows a submenu with items that are checkable with radio
 buttons.</p>
 
-<p class="note"><strong>Note:</strong> Menu items in the Icon Menu (from the Options Menu) cannot
+<p class="note"><strong>Note:</strong> Menu items in the Icon Menu (from the options menu) cannot
 display a checkbox or radio button. If you choose to make items in the Icon Menu checkable,
 you must manually indicate the checked state by swapping the icon and/or text
 each time the state changes.</p>
@@ -550,15 +922,15 @@
 <pre>
 &#64;Override
 public boolean onOptionsItemSelected(MenuItem item) {
-  switch (item.getItemId()) {
-  case R.id.vibrate:
-  case R.id.dont_vibrate:
-    if (item.isChecked()) item.setChecked(false);
-    else item.setChecked(true);
-    return true;
-  default:
-    return super.onOptionsItemSelected(item);
-  }
+    switch (item.getItemId()) {
+        case R.id.vibrate:
+        case R.id.dont_vibrate:
+            if (item.isChecked()) item.setChecked(false);
+            else item.setChecked(true);
+            return true;
+        default:
+            return super.onOptionsItemSelected(item);
+    }
 }
 </pre>
 
@@ -575,30 +947,8 @@
 href="{@docRoot}guide/topics/data/data-storage.html#pref">Shared Preferences</a>.</p>
 
 
-<h3 id="shortcuts">Shortcut keys</h3>
 
-<p>To facilitate quick access to items in the Options Menu when the user's device has a hardware
-keyboard, you can add quick-access shortcut keys using letters and/or numbers, with the
-{@code android:alphabeticShortcut} and {@code android:numericShortcut} attributes in the {@code
-&lt;item&gt;} element. You can also use the methods {@link
-android.view.MenuItem#setAlphabeticShortcut(char)} and {@link
-android.view.MenuItem#setNumericShortcut(char)}. Shortcut keys are <em>not</em>
-case sensitive.</p>
-
-<p>For example, if you apply the "s" character as an alphabetic shortcut to a "save" menu item, then
-when the menu is open (or while the user holds the MENU button) and the user presses the "s" key,
-the "save" menu item is selected.</p>
-
-<p>This shortcut key is displayed as a tip in the menu item, below the menu item name
-(except for items in the Icon Menu, which are displayed only if the user holds the MENU
-button).</p>
-
-<p class="note"><strong>Note:</strong> Shortcut keys for menu items only work on devices with a
-hardware keyboard. Shortcuts cannot be added to items in a Context Menu.</p>
-
-
-
-<h3 id="intents">Dynamically adding menu intents</h3>
+<h2 id="intents">Adding Menu Items Based on an Intent</h2>
 
 <p>Sometimes you'll want a menu item to launch an activity using an {@link android.content.Intent}
 (whether it's an activity in your application or another application). When you know the intent you
@@ -671,7 +1021,7 @@
 argument.</p>
 
 
-<h4>Allowing your activity to be added to other menus</h4>
+<h3 id="AllowingToAdd">Allowing your activity to be added to other menus</h3>
 
 <p>You can also offer the services of your activity to other applications, so your
 application can be included in the menu of others (reverse the roles described above).</p>
@@ -681,7 +1031,7 @@
 and/or {@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} values for the intent filter
 category. For example:</p>
 <pre>
-&lt;intent-filter label="Resize Image">
+&lt;intent-filter label="&#64;string/resize_image">
     ...
     &lt;category android:name="android.intent.category.ALTERNATIVE" />
     &lt;category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd
index 33b0fec..bef9671 100644
--- a/docs/html/guide/topics/ui/notifiers/notifications.jd
+++ b/docs/html/guide/topics/ui/notifiers/notifications.jd
@@ -245,31 +245,27 @@
 activity like this can cause it to be mixed with your normal application back stack
 in undesired ways.  To make it behave correctly, in the manifest declaration
 for the activity the attributes 
-<code>android:launchMode="singleInstance"</code> and
+<code>android:launchMode="singleTask"</code>,
+<code>android:taskAffinity=""</code> and
 <code>android:excludeFromRecents="true"</code>
 must be set.  The full activity declaration for this sample is:</p>
 
 {@sample development/samples/ApiDemos/AndroidManifest.xml interstitial_affinity}
 
-<p>Because of the use of <code>singleInstance</code>, you must be careful about launching
-any other activities from this one.  These activities will be launched
-in their own task, and care must be taken to make sure this interacts
-well with the current state of your application's task.  This is essentially
+<p>You must be careful when launching other activities from this initial activity,
+because this is not a top-level part of the application, does not appear in
+recents, and needs to be relaunched at any point from the notification with new data
+to show.  This best approach is to make sure any activity launched from it is
+launched in its own task.  When doing this care must be taken to make sure this
+new task interacts well with the current state of your exiting application's
+task.  This is essentially
 the same as switching to the main application as described for the Email style
 notification shown before.  Given the <code>makeMessageIntentStack()</code>
-method previously shown, handling a click here would look something like this:</p>
+method previously shown, handling a click then would look something like this:</p>
 
 {@sample development/samples/ApiDemos/src/com/example/android/apis/app/IncomingMessageInterstitial.java
   app_launch}
 
-<p>If you don't want to use the <code>singleInstance</code> launch mode for
-this activity, an alternative approach is to use <code>android:taskAffinity=""</code>.
-This tells Android that the activity should not be treated as part of the
-main application flow, so it will not get mixed together with that.  All of the
-other issues discussed here do still apply, though this would allow you to start
-additional activities that are part of this notification task instead of switching
-to and replacing the main application task.</p>
-
 <h2 id="ManageYourNotifications">Managing your Notifications</h2>
 
 <p>The {@link android.app.NotificationManager} is a system service that manages all
diff --git a/docs/html/images/ui/menu-context.png b/docs/html/images/ui/menu-context.png
new file mode 100644
index 0000000..f6975fb
--- /dev/null
+++ b/docs/html/images/ui/menu-context.png
Binary files differ
diff --git a/docs/html/images/ui/popupmenu.png b/docs/html/images/ui/popupmenu.png
new file mode 100644
index 0000000..5c99821
--- /dev/null
+++ b/docs/html/images/ui/popupmenu.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 9197b5d..b9d6758 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -1,4 +1,5 @@
 home=true
+page.metaDescription=The official site for Android developers. Provides the Android SDK and documentation for app developers and designers.
 @jd:body
 
 
@@ -142,6 +143,20 @@
 + "href='{@docRoot}sdk/api_diff/15/changes.html'>diff report</a>. If you're new to Android, "
 + "get started with the <a href='/sdk/index.html'>SDK starter package</a>.</p>"
     },
+    
+    'plus': {
+      'layout':"imgLeft",
+      'icon':"google-plus-small.png",
+      'name':"Google+ Page",
+      'img':"google-plus.png",
+      'title':"Android Developers on Google+",
+      'desc': "<p>We now have a Google+ page for <a "
++ "href='https://plus.google.com/108967384991768947849'>+Android Developers</a>. "
++ "We'll use it to host Hangouts for developers, talk about the latest releases, "
++ "development and design tips, and much more.</p>"
++ "<div style='margin:.7em 0 0 -1.2em'><g:plus href='https://plus.google.com/108967384991768947849' "
++ "size=\"smallbadge\" width=\"275\"></g:plus></div>"
+    },
 
     'tv': {
       'layout':"imgLeft",
@@ -186,5 +201,16 @@
 </script>
 <script type="text/javascript" src="{@docRoot}assets/carousel.js"></script>
 <script type="text/javascript">
-  initCarousel("sdk");
+  initCarousel("plus");
 </script>
+
+<script type="text/javascript" src="https://plus.google.com/108967384991768947849"
+rel="publisher"></script>
+<script type="text/javascript">
+window.___gcfg = {lang: 'en'};
+(function() 
+{var po = document.createElement("script");
+po.type = "text/javascript"; po.async = true;po.src = "https://apis.google.com/js/plusone.js";
+var s = document.getElementsByTagName("script")[0];
+s.parentNode.insertBefore(po, s);
+})();</script>
diff --git a/docs/html/resources/community-more.jd b/docs/html/resources/community-more.jd
index df72926..3089d45 100644
--- a/docs/html/resources/community-more.jd
+++ b/docs/html/resources/community-more.jd
@@ -1,5 +1,5 @@
 community=true
-page.title=IRC and Twitter
+page.title=IRC, G+, Twitter
 @jd:body
 
 <p>In addition to the <a href="community-groups.html">Android developer forums</a>, you can participate in the Android developer community through IRC and you can follow us on Twitter. </p>
@@ -45,8 +45,27 @@
 </li>
 </ul>
 
+
+<h3 id="gplus">Google+</h3>
+<p>We use a Google+ page to host Hangouts for developers, talk about the latest
+releases, development and design tips, and much more.</p>
+
+<div style='margin-top:1em'><g:plus href='https://plus.google.com/108967384991768947849'
+size='badge'></g:plus></div>
+
+
 <h3 id="twitter">Twitter</h3>
 <p>You can follow us on Twitter at this account:</p>
 
 <p style="margin-left:2em;"><a href="http://twitter.com/androiddev">http://twitter.com/androiddev</a></p>
 
+<script type="text/javascript" src="https://plus.google.com/108967384991768947849"
+rel="publisher"></script>
+<script type="text/javascript">
+window.___gcfg = {lang: 'en'};
+(function() 
+{var po = document.createElement("script");
+po.type = "text/javascript"; po.async = true;po.src = "https://apis.google.com/js/plusone.js";
+var s = document.getElementsByTagName("script")[0];
+s.parentNode.insertBefore(po, s);
+})();</script>
\ No newline at end of file
diff --git a/docs/html/resources/dashboard/opengl.jd b/docs/html/resources/dashboard/opengl.jd
index 357c1ea..d55ab2b 100644
--- a/docs/html/resources/dashboard/opengl.jd
+++ b/docs/html/resources/dashboard/opengl.jd
@@ -57,7 +57,7 @@
 <div class="dashboard-panel">
 
 <img alt="" width="400" height="250"
-src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1|GL%202.0%20%26%201.1&chd=t%3A9.5,90.5" />
+src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1%20only|GL%202.0%20%26%201.1&chd=t%3A10.7,89.3" />
 
 <table>
 <tr>
@@ -65,15 +65,15 @@
 <th scope="col">Distribution</th>
 </tr>
 <tr>
-<td>1.1</th>
-<td>9.5%</td>
+<td>1.1 only</th>
+<td>10.7%</td>
 </tr>
 <tr>
-<td>2.0</th>
-<td>90.5%</td>
+<td>2.0 &amp; 1.1</th>
+<td>89.3%</td>
 </tr>
 </table>
 
-<p><em>Data collected during a 7-day period ending on January 3, 2012</em></p>
+<p><em>Data collected during a 7-day period ending on February 1, 2012</em></p>
 </div>
 
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index 2618a04..4ea52af 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,7 +52,7 @@
 <div class="dashboard-panel">
 
 <img alt="" height="250" width="470"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.6,1.1,8.5,30.4,0.6,54.9,0.1,1.5,1.7,0.3,0.3&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0|Android%203.1|Android%203.2|Android%204.0|Android%204.0.3&chco=c4df9b,6fad0c" />
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.6,1.0,7.6,27.8,0.5,58.1,0.1,1.4,1.9,0.3,0.7&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0|Android%203.1|Android%203.2|Android%204.0|Android%204.0.3&chco=c4df9b,6fad0c" />
 
 <table>
 <tr>
@@ -62,24 +62,24 @@
   <th>Distribution</th>
 </tr>
 <tr><td><a href="{@docRoot}sdk/android-1.5.html">Android 1.5</a></td><td>Cupcake</td>  <td>3</td><td>0.6%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-1.6.html">Android 1.6</a></td><td>Donut</td>    <td>4</td><td>1.1%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-2.1.html">Android 2.1</a></td><td>Eclair</td>   <td>7</td><td>8.5%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-2.2.html">Android 2.2</a></td><td>Froyo</td>    <td>8</td><td>30.4%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-1.6.html">Android 1.6</a></td><td>Donut</td>    <td>4</td><td>1.0%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-2.1.html">Android 2.1</a></td><td>Eclair</td>   <td>7</td><td>7.6%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-2.2.html">Android 2.2</a></td><td>Froyo</td>    <td>8</td><td>27.8%</td></tr>
 <tr><td><a href="{@docRoot}sdk/android-2.3.html">Android 2.3 -<br/>
-                             Android 2.3.2</a></td><td rowspan="2">Gingerbread</td>    <td>9</td><td>0.6%</td></tr>
+                             Android 2.3.2</a></td><td rowspan="2">Gingerbread</td>    <td>9</td><td>0.5%</td></tr>
 <tr><td><a href="{@docRoot}sdk/android-2.3.3.html">Android 2.3.3 -<br/>
-      Android 2.3.7</a></td><!-- Gingerbread -->                                       <td>10</td><td>54.9%</td></tr>
+      Android 2.3.7</a></td><!-- Gingerbread -->                                       <td>10</td><td>58.1%</td></tr>
 <tr><td><a href="{@docRoot}sdk/android-3.0.html">Android 3.0</a></td>
                                                    <td rowspan="3">Honeycomb</td>      <td>11</td><td>0.1%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-3.1.html">Android 3.1</a></td><!-- Honeycomb --><td>12</td><td>1.5%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-3.2.html">Android 3.2</a></td><!-- Honeycomb --><td>13</td><td>1.7%</td></tr> 
+<tr><td><a href="{@docRoot}sdk/android-3.1.html">Android 3.1</a></td><!-- Honeycomb --><td>12</td><td>1.4%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-3.2.html">Android 3.2</a></td><!-- Honeycomb --><td>13</td><td>1.9%</td></tr> 
 <tr><td><a href="{@docRoot}sdk/android-4.0.html">Android 4.0 -<br/>
                                                Android 4.0.2</a></td>
                                                 <td rowspan="2">Ice Cream Sandwich</td><td>14</td><td>0.3%</td></tr> 
-<tr><td><a href="{@docRoot}sdk/android-4.0.3.html">Android 4.0.3</a></td><!-- ICS     --><td>15</td><td>0.3%</td></tr> 
+<tr><td><a href="{@docRoot}sdk/android-4.0.3.html">Android 4.0.3</a></td><!-- ICS     --><td>15</td><td>0.7%</td></tr> 
 </table>
 
-<p><em>Data collected during a 14-day period ending on January 3, 2012</em></p>
+<p><em>Data collected during a 14-day period ending on February 1, 2012</em></p>
 <!--
 <p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
 -->
@@ -108,9 +108,9 @@
 <div class="dashboard-panel">
 
 <img alt="" height="250" width="660" style="padding:5px;background:#fff"
-src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C07/01%7C07/15%7C08/01%7C08/15%7C09/01%7C09/15%7C10/01%7C10/15%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C1%3A%7C2011%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C2012%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:99.2,99.0,98.8,98.7,98.5,98.5,98.2,98.1,98.0,99.9,99.9,99.7,99.2|97.7,97.6,97.5,97.5,97.5,97.5,97.1,97.1,97.0,99.1,99.1,99.0,98.6|95.5,95.5,95.5,95.6,95.7,95.8,95.6,95.9,95.7,97.7,97.8,97.8,97.5|77.6,79.0,80.2,81.1,82.4,83.3,83.8,84.9,85.1,87.5,88.2,88.6,89.0|17.8,20.6,24.3,27.5,31.2,34.7,38.3,41.3,44.0,48.9,52.9,55.7,58.5|16.8,20.0,23.7,26.9,30.6,34.1,37.8,40.8,43.5,48.4,52.4,55.2,57.9|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.0,2.3,2.6,3.2|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.2,1.3,1.7&chm=b,c3df9b,0,1,0|b,b8dc82,1,2,0|tAndroid 2.1,608920,2,0,15,,t::-5|b,addb67,2,3,0|tAndroid 2.2,517617,3,0,15,,t::-5|b,a3db4b,3,4,0|b,98dc2e,4,5,0|tAndroid 2.3.3,334d0a,5,0,15,,t::-5|b,8cd41b,5,6,0|b,7ec113,6,7,0|B,6fad0c,7,8,0&chg=7,25&chdl=Android 1.5|Android 1.6|Android 2.1|Android 2.2|Android 2.3|Android 2.3.3|Android 3.1|Android 3.2&chco=add274,a2d15a,97d13e,8bcb28,7dba1e,6ea715,5f920e,507d08" />
+src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C08/01%7C08/15%7C09/01%7C09/15%7C10/01%7C10/15%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C01/15%7C02/01%7C1%3A%7C2011%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C2012%7C%7C2012%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:98.2,98.1,97.9,97.9,97.7,97.6,97.5,99.4,99.4,99.2,98.6,98.4,98.5|96.9,96.9,96.9,96.9,96.6,96.6,96.5,98.6,98.6,98.5,98.0,97.8,97.9|94.9,95.0,95.1,95.2,95.1,95.4,95.2,97.2,97.3,97.3,96.9,96.8,96.9|79.6,80.5,81.8,82.7,83.3,84.4,84.6,87.0,87.7,88.1,88.4,88.8,89.2|23.7,26.9,30.6,34.1,37.8,40.8,43.5,48.4,52.4,55.2,57.9,59.7,61.3|0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.0,2.3,2.6,3.2,3.2,3.3|0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.2,1.3,1.7,1.8,1.9&chm=b,c3df9b,0,1,0|b,b6dc7d,1,2,0|tAndroid%202.1,5b831d,2,0,15,,t::-5|b,aadb5e,2,3,0|tAndroid%202.2,496c13,3,0,15,,t::-5|b,9ddb3d,3,4,0|tAndroid%202.3.3,38540b,4,0,15,,t::-5|b,91da1e,4,5,0|b,80c414,5,6,0|B,6fad0c,6,7,0&chg=7,25&chdl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3.3|Android%203.1|Android%203.2&chco=add274,a0d155,94d134,84c323,73ad18,62960f,507d08" />
 
-<p><em>Last historical dataset collected during a 14-day period ending on January 3, 2012</em></p>
+<p><em>Last historical dataset collected during a 14-day period ending on February 1, 2012</em></p>
 
 
 </div><!-- end dashboard-panel -->
diff --git a/docs/html/resources/dashboard/screens.jd b/docs/html/resources/dashboard/screens.jd
index 79d59d9..ae5cdc7 100644
--- a/docs/html/resources/dashboard/screens.jd
+++ b/docs/html/resources/dashboard/screens.jd
@@ -60,7 +60,7 @@
 <div class="dashboard-panel">
 
 <img alt="" width="400" height="250"
-src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=Xlarge%20/%20mdpi|Large%20/%20ldpi|Large%20/%20mdpi|Normal%20/%20hdpi|Normal%20/%20ldpi|Normal%20/%20mdpi|Small%20/%20hdpi|Small%20/%20ldpi&chd=t%3A3.1,0.1,3.1,71.0,1.0,17.5,2.9,1.3" />
+src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=Xlarge%20/%20mdpi|Large%20/%20ldpi|Large%20/%20mdpi|Normal%20/%20hdpi|Normal%20/%20ldpi|Normal%20/%20mdpi|Normal%20/%20xhdpi|Small%20/%20hdpi|Small%20/%20ldpi&chd=t%3A4.8,0.2,2.9,67.1,0.7,18.4,1.8,2.5,1.6" />
 
 <table>
 <tr>
@@ -71,31 +71,31 @@
 <th scope="col">xhdpi</th>
 </tr>
 <tr><th scope="row">small</th> 
-<td>1.3%</td>     <!-- small/ldpi -->
+<td>1.6%</td>     <!-- small/ldpi -->
 <td></td>     <!-- small/mdpi -->
-<td>2.9%</td> <!-- small/hdpi -->
+<td>2.5%</td> <!-- small/hdpi -->
 <td></td>     <!-- small/xhdpi -->
 </tr> 
 <tr><th scope="row">normal</th> 
-<td>1.0%</td>  <!-- normal/ldpi -->
-<td>17.5%</td> <!-- normal/mdpi -->
-<td>71%</td> <!-- normal/hdpi -->
-<td></td>      <!-- normal/xhdpi -->
+<td>0.7%</td>  <!-- normal/ldpi -->
+<td>18.4%</td> <!-- normal/mdpi -->
+<td>67.1%</td> <!-- normal/hdpi -->
+<td>1.8%</td>      <!-- normal/xhdpi -->
 </tr> 
 <tr><th scope="row">large</th> 
-<td>0.1%</td>     <!-- large/ldpi -->
-<td>3.1%</td> <!-- large/mdpi -->
+<td>0.2%</td>     <!-- large/ldpi -->
+<td>2.9%</td> <!-- large/mdpi -->
 <td></td>     <!-- large/hdpi -->
 <td></td>     <!-- large/xhdpi -->
 </tr> 
 <tr><th scope="row">xlarge</th> 
 <td></td>     <!-- xlarge/ldpi -->
-<td>3.1%</td> <!-- xlarge/mdpi -->
+<td>4.8%</td> <!-- xlarge/mdpi -->
 <td></td>     <!-- xlarge/hdpi -->
 <td></td>     <!-- xlarge/xhdpi -->
 </tr> 
 </table>
 
-<p><em>Data collected during a 7-day period ending on December 1, 2011</em></p>
+<p><em>Data collected during a 7-day period ending on February 1, 2012</em></p>
 </div>
 
diff --git a/docs/html/resources/resources_toc.cs b/docs/html/resources/resources_toc.cs
index 8df419f..8483037 100644
--- a/docs/html/resources/resources_toc.cs
+++ b/docs/html/resources/resources_toc.cs
@@ -1,7 +1,8 @@
 <ul>
   <li>
-    <h2><span class="en">Android Training</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Android Training</span>
+    </span>
     <ul>
       
       <li><a href="<?cs var:toroot ?>training/index.html">
@@ -237,8 +238,9 @@
       
       
   <li>
-    <h2><span class="en">Technical Resources</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Technical Resources</span>
+    </span>
     <ul>
       <li class="toggle-list">
         <div><a href="<?cs var:toroot ?>resources/browser.html?tag=sample">
@@ -288,29 +290,31 @@
     </ul>
   </li>
   <li>
-    <h2><span class="en">Community</span>
-               <span style="display:none" class="de"></span>
-               <span style="display:none" class="es">Comunidad</span>
-               <span style="display:none" class="fr">Communauté</span>
-               <span style="display:none" class="it"></span>
-               <span style="display:none" class="ja">コミュニティ</span>
-               <span style="display:none" class="zh-CN">社区</span>
-               <span style="display:none" class="zh-TW">社群</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Community</span>
+      <span style="display:none" class="de"></span>
+      <span style="display:none" class="es">Comunidad</span>
+      <span style="display:none" class="fr">Communauté</span>
+      <span style="display:none" class="it"></span>
+      <span style="display:none" class="ja">コミュニティ</span>
+      <span style="display:none" class="zh-CN">社区</span>
+      <span style="display:none" class="zh-TW">社群</span>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>resources/community-groups.html">
             <span class="en">Developer Forums</span>
           </a></li>
       <li><a href="<?cs var:toroot ?>resources/community-more.html">
-            <span class="en">IRC, Twitter</span>
+            <span class="en">IRC, G+, Twitter</span>
           </a></li>
     </ul>
   </li>
 <?cs
   if:android.whichdoc == "online" ?>
   <li>
-    <h2><span class="en">Device Dashboard</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Device Dashboard</span>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>resources/dashboard/platform-versions.html">
             <span class="en">Platform Versions</span>
@@ -327,7 +331,9 @@
 ?>
 
   <li>
-   <h2><span class="en">More</span></h2>
+    <span class="heading">
+      <span class="en">More</span>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>resources/faq/commontasks.html">
             <span class="en">Common Tasks </span>
diff --git a/docs/html/resources/tutorials/hello-world.jd b/docs/html/resources/tutorials/hello-world.jd
index 9afab6a..cc8cb3e 100644
--- a/docs/html/resources/tutorials/hello-world.jd
+++ b/docs/html/resources/tutorials/hello-world.jd
@@ -24,7 +24,7 @@
 management to greatly speed up your development cycles.</p>
 
 <p>This tutorial assumes that you're using Eclipse. If you're using the command line, see
-<a href="{@docRoot}/guide/developing/building/building-cmdline.html">Building and Running from the
+<a href="{@docRoot}guide/developing/building/building-cmdline.html">Building and Running from the
 Command Line</a>. You can then return to this tutorial and ignore anything about Eclipse.</p>
 
 <p>Before you start, you should already have the SDK installed, and if you're
diff --git a/docs/html/sdk/android-2.3.3.jd b/docs/html/sdk/android-2.3.3.jd
index 7a5b044..023e2e4 100644
--- a/docs/html/sdk/android-2.3.3.jd
+++ b/docs/html/sdk/android-2.3.3.jd
@@ -336,7 +336,7 @@
 <li>English, New Zealand (en_NZ)</li>
 <li>English, Singapore(en_SG)</li>
 <li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
 <li>Spanish (es_ES)</li>
 <li>Spanish, US (es_US)</li>
 <li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/android-2.3.4.jd b/docs/html/sdk/android-2.3.4.jd
index 4cb44b9..eeaa69a 100644
--- a/docs/html/sdk/android-2.3.4.jd
+++ b/docs/html/sdk/android-2.3.4.jd
@@ -296,7 +296,7 @@
 <li>English, New Zealand (en_NZ)</li>
 <li>English, Singapore(en_SG)</li>
 <li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
 <li>Spanish (es_ES)</li>
 <li>Spanish, US (es_US)</li>
 <li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/android-2.3.jd b/docs/html/sdk/android-2.3.jd
index e7aa0fa..fc4f5aa 100644
--- a/docs/html/sdk/android-2.3.jd
+++ b/docs/html/sdk/android-2.3.jd
@@ -859,7 +859,7 @@
 <li>English, New Zealand (en_NZ)</li>
 <li>English, Singapore(en_SG)</li>
 <li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
 <li>Spanish (es_ES)</li>
 <li>Spanish, US (es_US)</li>
 <li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/android-3.0.jd b/docs/html/sdk/android-3.0.jd
index 96b92d9..49fefee 100644
--- a/docs/html/sdk/android-3.0.jd
+++ b/docs/html/sdk/android-3.0.jd
@@ -1119,7 +1119,7 @@
 <li>English, New Zealand (en_NZ)</li>
 <li>English, Singapore(en_SG)</li>
 <li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
 <li>Spanish (es_ES)</li>
 <li>Spanish, US (es_US)</li>
 <li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/android-3.1.jd b/docs/html/sdk/android-3.1.jd
index 78f265d..b9cf969 100644
--- a/docs/html/sdk/android-3.1.jd
+++ b/docs/html/sdk/android-3.1.jd
@@ -1040,7 +1040,7 @@
 <li>English, New Zealand (en_NZ)</li>
 <li>English, Singapore(en_SG)</li>
 <li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
 <li>Spanish (es_ES)</li>
 <li>Spanish, US (es_US)</li>
 <li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/android-4.0.3.jd b/docs/html/sdk/android-4.0.3.jd
index 1fca8df..809c83c 100644
--- a/docs/html/sdk/android-4.0.3.jd
+++ b/docs/html/sdk/android-4.0.3.jd
@@ -435,7 +435,7 @@
 <li>English, New Zealand (en_NZ)</li>
 <li>English, Singapore(en_SG)</li>
 <li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
 <li>Spanish (es_ES)</li>
 <li>Spanish, US (es_US)</li>
 <li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/android-4.0.jd b/docs/html/sdk/android-4.0.jd
index 5f55947..2cad86b 100644
--- a/docs/html/sdk/android-4.0.jd
+++ b/docs/html/sdk/android-4.0.jd
@@ -1963,7 +1963,7 @@
 <li>English, New Zealand (en_NZ)</li>
 <li>English, Singapore(en_SG)</li>
 <li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
 <li>Spanish (es_ES)</li>
 <li>Spanish, US (es_US)</li>
 <li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index f15da78..30825ee 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -42,7 +42,7 @@
 
 <p>Developing in Eclipse with ADT is highly recommended and is the fastest way
 to get started. With the guided project setup it provides, as well as tools
-integration, custom XML editors, and debug ouput pane, ADT gives you an
+integration, custom XML editors, and debug output pane, ADT gives you an
 incredible boost in developing Android applications. </p>
 
 <p>This document provides step-by-step instructions on how to download the ADT
@@ -1104,7 +1104,7 @@
 <h3 id="downloading">Downloading the ADT Plugin</h3>
 
 <p>Use the Update Manager feature of your Eclipse installation to install the latest
-revision of ADT on your development computer.<>
+revision of ADT on your development computer.</p>
 
 <p>Assuming that you have a compatible version of the Eclipse IDE installed, as
 described in <a href="#preparing">Preparing for Installation</a>, above, follow
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 65a1f46..5cf05e0 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -1,4 +1,5 @@
 page.title=Android SDK
+page.metaDescription=Download the official Android SDK to develop apps for Android-powered devices.
 sdk.redirect=0
 
 sdk.win_installer=installer_r16-windows.exe
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 5f6a57f..0de477a 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -1,7 +1,7 @@
 <?cs if:!sdk.redirect ?>
 <ul>
   <li>
-    <h2>
+    <span class="heading">
       <span class="en">Android SDK Starter Package</span>
       <span style="display:none" class="de">Aktuelle SDK-Version</span>
       <span style="display:none" class="es">Versión actual del SDK</span>
@@ -10,7 +10,7 @@
       <span style="display:none" class="ja">現在リリースされている SDK</span>
       <span style="display:none" class="zh-CN">当前的 SDK 版本</span>
       <span style="display:none" class="zh-TW">目前 SDK 發行版本</span>
-    </h2>
+    </span>
     <ul><?cs
   if:android.whichdoc == "online" ?>
       <li><a href="<?cs var:toroot ?>sdk/index.html">
@@ -37,7 +37,8 @@
     </ul>
   </li><?cs
   if:sdk.preview ?>
-  <li><h2>Android 3.0 Preview SDK</h2>
+  <li>
+    <span class="heading">Android 3.0 Preview SDK</span>
     <ul>
       <li><a href="<?cs var:toroot ?>sdk/preview/start.html">Getting Started</a> <span
 class="new">new!</span></li>
@@ -46,13 +47,14 @@
   /if ?>
   <?cs
   if:sdk.preview ?>
-  <li><h2>Android x.x Preview</h2>
+  <li>
+    <span class="heading">Android x.x Preview</span>
     <ul>
     </ul>
   </li><?cs
   /if ?>
   <li>
-    <h2>
+    <span class="heading">
       <span class="en">Downloadable SDK Components</span>
       <span style="display:none" class="de"></span>
       <span style="display:none" class="es"></span>
@@ -61,7 +63,7 @@
       <span style="display:none" class="ja"></span>
       <span style="display:none" class="zh-CN"></span>
       <span style="display:none" class="zh-TW"></span>
-    </h2>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>sdk/adding-components.html">
       <span class="en">Adding SDK Components</span>
@@ -158,7 +160,7 @@
     </ul>
   </li>
   <li>
-      <h2>
+    <span class="heading">
       <span class="en">ADT Plugin for Eclipse</span>
       <span style="display:none" class="de"></span>
       <span style="display:none" class="es"></span>
@@ -167,7 +169,7 @@
       <span style="display:none" class="ja"></span>
       <span style="display:none" class="zh-CN"></span>
       <span style="display:none" class="zh-TW"></span>
-      </h2>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 16.0.1
       <span style="display:none" class="de"></span>
@@ -182,7 +184,8 @@
     </ul>
   </li>
   <li>
-    <h2><span class="en">Native Development Tools</span>
+    <span class="heading">
+      <span class="en">Native Development Tools</span>
       <span style="display:none" class="de"></span>
       <span style="display:none" class="es"></span>
       <span style="display:none" class="fr"></span>
@@ -190,7 +193,7 @@
       <span style="display:none" class="ja"></span>
       <span style="display:none" class="zh-CN"></span>
       <span style="display:none" class="zh-TW"></span>
-    </h2>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r7</a>
         <span class="new">new!</span>
@@ -200,7 +203,7 @@
   </li>
 
   <li>
-    <h2>
+    <span class="heading">
       <span class="en">More Information</span>
       <span style="display:none" class="de"></span>
       <span style="display:none" class="es"></span>
@@ -209,7 +212,7 @@
       <span style="display:none" class="ja"></span>
       <span style="display:none" class="zh-CN"></span>
       <span style="display:none" class="zh-TW"></span>
-    </h2>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>sdk/oem-usb.html">
         <span class="en">OEM USB Drivers</span>
diff --git a/graphics/java/android/graphics/LinearGradient.java b/graphics/java/android/graphics/LinearGradient.java
index 82ed199..96a71e3 100644
--- a/graphics/java/android/graphics/LinearGradient.java
+++ b/graphics/java/android/graphics/LinearGradient.java
@@ -28,8 +28,8 @@
                             the the colors are distributed evenly along the gradient line.
         @param  tile        The Shader tiling mode
 	*/
-	public LinearGradient(float x0, float y0, float x1, float y1,
-                          int colors[], float positions[], TileMode tile) {
+	public LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[],
+            TileMode tile) {
         if (colors.length < 2) {
             throw new IllegalArgumentException("needs >= 2 number of colors");
         }
@@ -50,8 +50,8 @@
         @param  color1  The color at the end of the gradient line.
         @param  tile    The Shader tiling mode
 	*/
-	public LinearGradient(float x0, float y0, float x1, float y1,
-                          int color0, int color1, TileMode tile) {
+	public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,
+            TileMode tile) {
         native_instance = nativeCreate2(x0, y0, x1, y1, color0, color1, tile.nativeInt);
         native_shader = nativePostCreate2(native_instance, x0, y0, x1, y1, color0, color1,
                 tile.nativeInt);
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index 7830224..0ada1fb 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -76,13 +76,21 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
-        Rect r = (Rect) obj;
-        if (r != null) {
-            return left == r.left && top == r.top && right == r.right
-                    && bottom == r.bottom;
-        }
-        return false;
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Rect r = (Rect) o;
+        return left == r.left && top == r.top && right == r.right && bottom == r.bottom;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = left;
+        result = 31 * result + top;
+        result = 31 * result + right;
+        result = 31 * result + bottom;
+        return result;
     }
 
     @Override
diff --git a/graphics/java/android/graphics/RectF.java b/graphics/java/android/graphics/RectF.java
index 00e9609..293dfcc 100644
--- a/graphics/java/android/graphics/RectF.java
+++ b/graphics/java/android/graphics/RectF.java
@@ -79,6 +79,24 @@
         bottom = r.bottom;
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Rect r = (Rect) o;
+        return left == r.left && top == r.top && right == r.right && bottom == r.bottom;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = (left != +0.0f ? Float.floatToIntBits(left) : 0);
+        result = 31 * result + (top != +0.0f ? Float.floatToIntBits(top) : 0);
+        result = 31 * result + (right != +0.0f ? Float.floatToIntBits(right) : 0);
+        result = 31 * result + (bottom != +0.0f ? Float.floatToIntBits(bottom) : 0);
+        return result;
+    }
+
     public String toString() {
         return "RectF(" + left + ", " + top + ", "
                       + right + ", " + bottom + ")";
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 50964d5..5b50beb 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -173,9 +173,20 @@
     }
 
     /**
-     * Specify radii for each of the 4 corners. For each corner, the array
-     * contains 2 values, [X_radius, Y_radius]. The corners are ordered
-     * top-left, top-right, bottom-right, bottom-left
+     * <p>Specify radii for each of the 4 corners. For each corner, the array
+     * contains 2 values, <code>[X_radius, Y_radius]</code>. The corners are ordered
+     * top-left, top-right, bottom-right, bottom-left. This property
+     * is honored only when the shape is of type {@link #RECTANGLE}.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param radii 4 pairs of X and Y radius for each corner, specified in pixels.
+     *              The length of this array must be >= 8
+     *
+     * @see #mutate()
+     * @see #setCornerRadii(float[])
+     * @see #setShape(int)
      */
     public void setCornerRadii(float[] radii) {
         mGradientState.setCornerRadii(radii);
@@ -184,23 +195,57 @@
     }
     
     /**
-     * Specify radius for the corners of the gradient. If this is > 0, then the
-     * drawable is drawn in a round-rectangle, rather than a rectangle.
+     * <p>Specify radius for the corners of the gradient. If this is > 0, then the
+     * drawable is drawn in a round-rectangle, rather than a rectangle. This property
+     * is honored only when the shape is of type {@link #RECTANGLE}.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param radius The radius in pixels of the corners of the rectangle shape
+     *
+     * @see #mutate()
+     * @see #setCornerRadii(float[])
+     * @see #setShape(int) 
      */
     public void setCornerRadius(float radius) {
         mGradientState.setCornerRadius(radius);
         mPathIsDirty = true;
         invalidateSelf();
     }
-    
+
     /**
-     * Set the stroke width and color for the drawable. If width is zero,
-     * then no stroke is drawn.
+     * <p>Set the stroke width and color for the drawable. If width is zero,
+     * then no stroke is drawn.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param width The width in pixels of the stroke
+     * @param color The color of the stroke
+     *
+     * @see #mutate()
+     * @see #setStroke(int, int, float, float) 
      */
     public void setStroke(int width, int color) {
         setStroke(width, color, 0, 0);
     }
-    
+
+    /**
+     * <p>Set the stroke width and color for the drawable. If width is zero,
+     * then no stroke is drawn. This method can also be used to dash the stroke.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param width The width in pixels of the stroke
+     * @param color The color of the stroke
+     * @param dashWidth The length in pixels of the dashes, set to 0 to disable dashes 
+     * @param dashGap The gap in pixels between dashes
+     *
+     * @see #mutate()
+     * @see #setStroke(int, int) 
+     */
     public void setStroke(int width, int color, float dashWidth, float dashGap) {
         mGradientState.setStroke(width, color, dashWidth, dashGap);
 
@@ -218,13 +263,37 @@
         mStrokePaint.setPathEffect(e);
         invalidateSelf();
     }
-    
+
+
+    /**
+     * <p>Sets the size of the shape drawn by this drawable.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param width The width of the shape used by this drawable
+     * @param height The height of the shape used by this drawable
+     *
+     * @see #mutate()
+     * @see #setGradientType(int)
+     */
     public void setSize(int width, int height) {
         mGradientState.setSize(width, height);
         mPathIsDirty = true;
         invalidateSelf();
     }
-    
+
+    /**
+     * <p>Sets the type of shape used to draw the gradient.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param shape The desired shape for this drawable: {@link #LINE},
+     *              {@link #OVAL}, {@link #RECTANGLE} or {@link #RING}
+     *
+     * @see #mutate()
+     */
     public void setShape(int shape) {
         mRingPath = null;
         mPathIsDirty = true;
@@ -232,24 +301,73 @@
         invalidateSelf();
     }
 
+    /**
+     * <p>Sets the type of gradient used by this drawable..</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param gradient The type of the gradient: {@link #LINEAR_GRADIENT},
+     *                 {@link #RADIAL_GRADIENT} or {@link #SWEEP_GRADIENT}
+     *
+     * @see #mutate()
+     */
     public void setGradientType(int gradient) {
         mGradientState.setGradientType(gradient);
         mRectIsDirty = true;
         invalidateSelf();
     }
 
+    /**
+     * <p>Sets the center location of the gradient. The radius is honored only when 
+     * the gradient type is set to {@link #RADIAL_GRADIENT} or {@link #SWEEP_GRADIENT}.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param x The x coordinate of the gradient's center
+     * @param y The y coordinate of the gradient's center
+     *
+     * @see #mutate()
+     * @see #setGradientType(int)
+     */
     public void setGradientCenter(float x, float y) {
         mGradientState.setGradientCenter(x, y);
         mRectIsDirty = true;
         invalidateSelf();
     }
 
+    /**
+     * <p>Sets the radius of the gradient. The radius is honored only when the
+     * gradient type is set to {@link #RADIAL_GRADIENT}.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param gradientRadius The radius of the gradient in pixels
+     *
+     * @see #mutate()
+     * @see #setGradientType(int) 
+     */
     public void setGradientRadius(float gradientRadius) {
         mGradientState.setGradientRadius(gradientRadius);
         mRectIsDirty = true;
         invalidateSelf();
     }
 
+    /**
+     * <p>Sets whether or not this drawable will honor its <code>level</code>
+     * property.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param useLevel True if this drawable should honor its level, false otherwise
+     *
+     * @see #mutate()
+     * @see #setLevel(int) 
+     * @see #getLevel() 
+     */
     public void setUseLevel(boolean useLevel) {
         mGradientState.mUseLevel = useLevel;
         mRectIsDirty = true;
@@ -261,6 +379,47 @@
         return alpha * scale >> 8;
     }
 
+    /**
+     * Returns the orientation of the gradient defined in this drawable.
+     */
+    public Orientation getOrientation() {
+        return mGradientState.mOrientation;
+    }
+
+    /**
+     * <p>Changes the orientation of the gradient defined in this drawable.</p>
+     * <p><strong>Note</strong>: changing orientation will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing the orientation.</p>
+     * 
+     * @param orientation The desired orientation (angle) of the gradient
+     *                    
+     * @see #mutate() 
+     */
+    public void setOrientation(Orientation orientation) {
+        mGradientState.mOrientation = orientation;
+        mRectIsDirty = true;
+        invalidateSelf();
+    }
+
+    /**
+     * <p>Sets the colors used to draw the gradient. Each color is specified as an
+     * ARGB integer and the array must contain at least 2 colors.</p>
+     * <p><strong>Note</strong>: changing orientation will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing the orientation.</p>
+     *
+     * @param colors 2 or more ARGB colors
+     *
+     * @see #mutate()
+     * @see #setColor(int) 
+     */
+    public void setColors(int[] colors) {
+        mGradientState.setColors(colors);
+        mRectIsDirty = true;
+        invalidateSelf();
+    }
+
     @Override
     public void draw(Canvas canvas) {
         if (!ensureValidRect()) {
@@ -442,6 +601,17 @@
         return ringPath;
     }
 
+    /**
+     * <p>Changes this drawbale to use a single color instead of a gradient.</p>
+     * <p><strong>Note</strong>: changing orientation will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing the orientation.</p>
+     *
+     * @param argb The color used to fill the shape
+     *
+     * @see #mutate()
+     * @see #setColors(int[]) 
+     */
     public void setColor(int argb) {
         mGradientState.setSolidColor(argb);
         mFillPaint.setColor(argb);
@@ -450,10 +620,9 @@
 
     @Override
     public int getChangingConfigurations() {
-        return super.getChangingConfigurations()
-                | mGradientState.mChangingConfigurations;
+        return super.getChangingConfigurations() | mGradientState.mChangingConfigurations;
     }
-    
+
     @Override
     public void setAlpha(int alpha) {
         if (alpha != mAlpha) {
@@ -480,7 +649,6 @@
 
     @Override
     public int getOpacity() {
-        // XXX need to figure out the actual opacity...
         return PixelFormat.TRANSLUCENT;
     }
 
@@ -911,11 +1079,6 @@
         private float mGradientRadius = 0.5f;
         private boolean mUseLevel;
         private boolean mUseLevelForShape;
-        
-        
-        GradientState() {
-            mOrientation = Orientation.TOP_BOTTOM;
-        }
 
         GradientState(Orientation orientation, int[] colors) {
             mOrientation = orientation;
@@ -987,6 +1150,11 @@
             mCenterY = y;
         }
 
+        public void setColors(int[] colors) {
+            mHasSolidColor = false;
+            mColors = colors;
+        }
+        
         public void setSolidColor(int argb) {
             mHasSolidColor = true;
             mSolidColor = argb;
@@ -1055,4 +1223,3 @@
         }
     }
 }
-
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index f285f5b..11c2427 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -487,6 +487,7 @@
 
         final byte[] data = fp.getData();
         int eSize = mType.mElement.mElements[component_number].getSizeBytes();
+        eSize *= mType.mElement.mArraySizes[component_number];
 
         if (data.length != eSize) {
             throw new RSIllegalArgumentException("Field packer sizelength " + data.length +
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index ad10832..03ad5ae 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -837,7 +837,7 @@
                         mRS.mErrorCallback.mErrorNum = subID;
                         mRS.mErrorCallback.run();
                     } else {
-                        //throw new RSRuntimeException("Received error num " + subID + ", details: " + e);
+                        throw new RSRuntimeException("Received error num " + subID + ", details: " + e);
                     }
                     continue;
                 }
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index bc1db4d..07bf7bf 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2011-2012 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.
@@ -567,7 +567,7 @@
     jint len = _env->GetArrayLength(data);
     LOG_API("nAllocationElementData1D, con(%p), alloc(%p), offset(%i), comp(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, compIdx, len, sizeBytes);
     jbyte *ptr = _env->GetByteArrayElements(data, NULL);
-    rsAllocation1DElementData(con, (RsAllocation)alloc, offset, lod, ptr, compIdx, sizeBytes);
+    rsAllocation1DElementData(con, (RsAllocation)alloc, offset, lod, ptr, sizeBytes, compIdx);
     _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
 }
 
diff --git a/include/gui/DisplayEventReceiver.h b/include/gui/DisplayEventReceiver.h
index dccc164..7bca8d6 100644
--- a/include/gui/DisplayEventReceiver.h
+++ b/include/gui/DisplayEventReceiver.h
@@ -63,7 +63,9 @@
 public:
     /*
      * DisplayEventReceiver creates and registers an event connection with
-     * SurfaceFlinger. Events start being delivered immediately.
+     * SurfaceFlinger. VSync events are disabled by default. Call setVSyncRate
+     * or requestNextVsync to receive them.
+     * Other events start being delivered immediately.
      */
     DisplayEventReceiver();
 
@@ -93,6 +95,8 @@
      * should be destroyed and getEvents() shouldn't be called again.
      */
     ssize_t getEvents(Event* events, size_t count);
+    static ssize_t getEvents(const sp<BitTube>& dataChannel,
+            Event* events, size_t count);
 
     /*
      * setVsyncRate() sets the Event::VSync delivery rate. A value of
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 6b12c14..74a1e62 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -248,7 +248,7 @@
     static sp<IAudioPolicyService> gAudioPolicyService;
 
     // mapping between stream types and outputs
-    static DefaultKeyedVector<int, audio_io_handle_t> gStreamOutputMap;
+    static DefaultKeyedVector<audio_stream_type_t, audio_io_handle_t> gStreamOutputMap;
     // list of output descriptors containing cached parameters
     // (sampling rate, framecount, channel count...)
     static DefaultKeyedVector<audio_io_handle_t, OutputDescriptor *> gOutputs;
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index c4cc947..a295e9a 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -42,10 +42,10 @@
     typedef void *buffer_id;
     typedef void *node_id;
 
-    // Given the calling process' pid, returns true iff
+    // Given a node_id and the calling process' pid, returns true iff
     // the implementation of the OMX interface lives in the same
     // process.
-    virtual bool livesLocally(pid_t pid) = 0;
+    virtual bool livesLocally(node_id node, pid_t pid) = 0;
 
     struct ComponentInfo {
         String8 mName;
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index ffc546e..dd97ce4 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -76,7 +76,9 @@
                 // Left channel is in [0:15], right channel is in [16:31].
                 // Always read and write the combined pair atomically.
                 // For AudioTrack only, not used by AudioRecord.
-                uint32_t    volumeLR;
+private:
+                uint32_t    mVolumeLR;
+public:
 
                 uint32_t    sampleRate;
                 // NOTE: audio_track_cblk_t::frameSize is not equal to AudioTrack::frameSize() for
@@ -116,6 +118,17 @@
                 uint16_t    getSendLevel_U4_12() const {
                     return mSendLevel;
                 }
+
+                // for AudioTrack client only, caller must limit to 0 <= volumeLR <= 0x10001000
+                void        setVolumeLR(uint32_t volumeLR) {
+                    mVolumeLR = volumeLR;
+                }
+
+                // for AudioFlinger only; the return value must be validated by the caller
+                uint32_t    getVolumeLR() const {
+                    return mVolumeLR;
+                }
+
 };
 
 
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index b741ed6..c496da6 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -444,23 +444,31 @@
 
     void uninit();
 
+    // Return string entry as UTF16; if the pool is UTF8, the string will
+    // be converted before returning.
     inline const char16_t* stringAt(const ResStringPool_ref& ref, size_t* outLen) const {
         return stringAt(ref.index, outLen);
     }
     const char16_t* stringAt(size_t idx, size_t* outLen) const;
 
+    // Note: returns null if the string pool is not UTF8.
     const char* string8At(size_t idx, size_t* outLen) const;
 
+    // Return string whether the pool is UTF8 or UTF16.  Does not allow you
+    // to distinguish null.
+    const String8 string8ObjectAt(size_t idx) const;
+
     const ResStringPool_span* styleAt(const ResStringPool_ref& ref) const;
     const ResStringPool_span* styleAt(size_t idx) const;
 
     ssize_t indexOfString(const char16_t* str, size_t strLen) const;
 
     size_t size() const;
+    size_t styleCount() const;
+    size_t bytes() const;
 
-#ifndef HAVE_ANDROID_OS
+    bool isSorted() const;
     bool isUTF8() const;
-#endif
 
 private:
     status_t                    mError;
@@ -746,7 +754,9 @@
 /**
  * Header for a resource table.  Its data contains a series of
  * additional chunks:
- *   * A ResStringPool_header containing all table values.
+ *   * A ResStringPool_header containing all table values.  This string pool
+ *     contains all of the string values in the entire resource table (not
+ *     the names of entries or type identifiers however).
  *   * One or more ResTable_package chunks.
  *
  * Specific entries within a resource table can be uniquely identified
@@ -984,68 +994,15 @@
         uint32_t screenSizeDp;
     };
 
-    inline void copyFromDeviceNoSwap(const ResTable_config& o) {
-        const size_t size = dtohl(o.size);
-        if (size >= sizeof(ResTable_config)) {
-            *this = o;
-        } else {
-            memcpy(this, &o, size);
-            memset(((uint8_t*)this)+size, 0, sizeof(ResTable_config)-size);
-        }
-    }
+    void copyFromDeviceNoSwap(const ResTable_config& o);
     
-    inline void copyFromDtoH(const ResTable_config& o) {
-        copyFromDeviceNoSwap(o);
-        size = sizeof(ResTable_config);
-        mcc = dtohs(mcc);
-        mnc = dtohs(mnc);
-        density = dtohs(density);
-        screenWidth = dtohs(screenWidth);
-        screenHeight = dtohs(screenHeight);
-        sdkVersion = dtohs(sdkVersion);
-        minorVersion = dtohs(minorVersion);
-        smallestScreenWidthDp = dtohs(smallestScreenWidthDp);
-        screenWidthDp = dtohs(screenWidthDp);
-        screenHeightDp = dtohs(screenHeightDp);
-    }
+    void copyFromDtoH(const ResTable_config& o);
     
-    inline void swapHtoD() {
-        size = htodl(size);
-        mcc = htods(mcc);
-        mnc = htods(mnc);
-        density = htods(density);
-        screenWidth = htods(screenWidth);
-        screenHeight = htods(screenHeight);
-        sdkVersion = htods(sdkVersion);
-        minorVersion = htods(minorVersion);
-        smallestScreenWidthDp = htods(smallestScreenWidthDp);
-        screenWidthDp = htods(screenWidthDp);
-        screenHeightDp = htods(screenHeightDp);
-    }
-    
-    inline int compare(const ResTable_config& o) const {
-        int32_t diff = (int32_t)(imsi - o.imsi);
-        if (diff != 0) return diff;
-        diff = (int32_t)(locale - o.locale);
-        if (diff != 0) return diff;
-        diff = (int32_t)(screenType - o.screenType);
-        if (diff != 0) return diff;
-        diff = (int32_t)(input - o.input);
-        if (diff != 0) return diff;
-        diff = (int32_t)(screenSize - o.screenSize);
-        if (diff != 0) return diff;
-        diff = (int32_t)(version - o.version);
-        if (diff != 0) return diff;
-        diff = (int32_t)(screenLayout - o.screenLayout);
-        if (diff != 0) return diff;
-        diff = (int32_t)(uiMode - o.uiMode);
-        if (diff != 0) return diff;
-        diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp);
-        if (diff != 0) return diff;
-        diff = (int32_t)(screenSizeDp - o.screenSizeDp);
-        return (int)diff;
-    }
-    
+    void swapHtoD();
+
+    int compare(const ResTable_config& o) const;
+    int compareLogical(const ResTable_config& o) const;
+
     // Flags indicating a set of config values.  These flag constants must
     // match the corresponding ones in android.content.pm.ActivityInfo and
     // attrs_manifest.xml.
@@ -1068,158 +1025,10 @@
     
     // Compare two configuration, returning CONFIG_* flags set for each value
     // that is different.
-    inline int diff(const ResTable_config& o) const {
-        int diffs = 0;
-        if (mcc != o.mcc) diffs |= CONFIG_MCC;
-        if (mnc != o.mnc) diffs |= CONFIG_MNC;
-        if (locale != o.locale) diffs |= CONFIG_LOCALE;
-        if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION;
-        if (density != o.density) diffs |= CONFIG_DENSITY;
-        if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN;
-        if (((inputFlags^o.inputFlags)&(MASK_KEYSHIDDEN|MASK_NAVHIDDEN)) != 0)
-                diffs |= CONFIG_KEYBOARD_HIDDEN;
-        if (keyboard != o.keyboard) diffs |= CONFIG_KEYBOARD;
-        if (navigation != o.navigation) diffs |= CONFIG_NAVIGATION;
-        if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE;
-        if (version != o.version) diffs |= CONFIG_VERSION;
-        if (screenLayout != o.screenLayout) diffs |= CONFIG_SCREEN_LAYOUT;
-        if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE;
-        if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE;
-        if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE;
-        return diffs;
-    }
+    int diff(const ResTable_config& o) const;
     
     // Return true if 'this' is more specific than 'o'.
-    inline bool
-    isMoreSpecificThan(const ResTable_config& o) const {
-        // The order of the following tests defines the importance of one
-        // configuration parameter over another.  Those tests first are more
-        // important, trumping any values in those following them.
-        if (imsi || o.imsi) {
-            if (mcc != o.mcc) {
-                if (!mcc) return false;
-                if (!o.mcc) return true;
-            }
-
-            if (mnc != o.mnc) {
-                if (!mnc) return false;
-                if (!o.mnc) return true;
-            }
-        }
-
-        if (locale || o.locale) {
-            if (language[0] != o.language[0]) {
-                if (!language[0]) return false;
-                if (!o.language[0]) return true;
-            }
-
-            if (country[0] != o.country[0]) {
-                if (!country[0]) return false;
-                if (!o.country[0]) return true;
-            }
-        }
-
-        if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
-            if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
-                if (!smallestScreenWidthDp) return false;
-                if (!o.smallestScreenWidthDp) return true;
-            }
-        }
-
-        if (screenSizeDp || o.screenSizeDp) {
-            if (screenWidthDp != o.screenWidthDp) {
-                if (!screenWidthDp) return false;
-                if (!o.screenWidthDp) return true;
-            }
-
-            if (screenHeightDp != o.screenHeightDp) {
-                if (!screenHeightDp) return false;
-                if (!o.screenHeightDp) return true;
-            }
-        }
-
-        if (screenLayout || o.screenLayout) {
-            if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0) {
-                if (!(screenLayout & MASK_SCREENSIZE)) return false;
-                if (!(o.screenLayout & MASK_SCREENSIZE)) return true;
-            }
-            if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0) {
-                if (!(screenLayout & MASK_SCREENLONG)) return false;
-                if (!(o.screenLayout & MASK_SCREENLONG)) return true;
-            }
-        }
-
-        if (orientation != o.orientation) {
-            if (!orientation) return false;
-            if (!o.orientation) return true;
-        }
-
-        if (uiMode || o.uiMode) {
-            if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0) {
-                if (!(uiMode & MASK_UI_MODE_TYPE)) return false;
-                if (!(o.uiMode & MASK_UI_MODE_TYPE)) return true;
-            }
-            if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0) {
-                if (!(uiMode & MASK_UI_MODE_NIGHT)) return false;
-                if (!(o.uiMode & MASK_UI_MODE_NIGHT)) return true;
-            }
-        }
-
-        // density is never 'more specific'
-        // as the default just equals 160
-
-        if (touchscreen != o.touchscreen) {
-            if (!touchscreen) return false;
-            if (!o.touchscreen) return true;
-        }
-
-        if (input || o.input) {
-            if (((inputFlags^o.inputFlags) & MASK_KEYSHIDDEN) != 0) {
-                if (!(inputFlags & MASK_KEYSHIDDEN)) return false;
-                if (!(o.inputFlags & MASK_KEYSHIDDEN)) return true;
-            }
-
-            if (((inputFlags^o.inputFlags) & MASK_NAVHIDDEN) != 0) {
-                if (!(inputFlags & MASK_NAVHIDDEN)) return false;
-                if (!(o.inputFlags & MASK_NAVHIDDEN)) return true;
-            }
-
-            if (keyboard != o.keyboard) {
-                if (!keyboard) return false;
-                if (!o.keyboard) return true;
-            }
-
-            if (navigation != o.navigation) {
-                if (!navigation) return false;
-                if (!o.navigation) return true;
-            }
-        }
-
-        if (screenSize || o.screenSize) {
-            if (screenWidth != o.screenWidth) {
-                if (!screenWidth) return false;
-                if (!o.screenWidth) return true;
-            }
-
-            if (screenHeight != o.screenHeight) {
-                if (!screenHeight) return false;
-                if (!o.screenHeight) return true;
-            }
-        }
-
-        if (version || o.version) {
-            if (sdkVersion != o.sdkVersion) {
-                if (!sdkVersion) return false;
-                if (!o.sdkVersion) return true;
-            }
-
-            if (minorVersion != o.minorVersion) {
-                if (!minorVersion) return false;
-                if (!o.minorVersion) return true;
-            }
-        }
-        return false;
-    }
+    bool isMoreSpecificThan(const ResTable_config& o) const;
 
     // Return true if 'this' is a better match than 'o' for the 'requested'
     // configuration.  This assumes that match() has already been used to
@@ -1231,222 +1040,7 @@
     // they are not equal then one must be generic because only generic and
     // '==requested' will pass the match() call.  So if this is not generic,
     // it wins.  If this IS generic, o wins (return false).
-    inline bool
-    isBetterThan(const ResTable_config& o,
-            const ResTable_config* requested) const {
-        if (requested) {
-            if (imsi || o.imsi) {
-                if ((mcc != o.mcc) && requested->mcc) {
-                    return (mcc);
-                }
-
-                if ((mnc != o.mnc) && requested->mnc) {
-                    return (mnc);
-                }
-            }
-
-            if (locale || o.locale) {
-                if ((language[0] != o.language[0]) && requested->language[0]) {
-                    return (language[0]);
-                }
-
-                if ((country[0] != o.country[0]) && requested->country[0]) {
-                    return (country[0]);
-                }
-            }
-
-            if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
-                // The configuration closest to the actual size is best.
-                // We assume that larger configs have already been filtered
-                // out at this point.  That means we just want the largest one.
-                return smallestScreenWidthDp >= o.smallestScreenWidthDp;
-            }
-
-            if (screenSizeDp || o.screenSizeDp) {
-                // "Better" is based on the sum of the difference between both
-                // width and height from the requested dimensions.  We are
-                // assuming the invalid configs (with smaller dimens) have
-                // already been filtered.  Note that if a particular dimension
-                // is unspecified, we will end up with a large value (the
-                // difference between 0 and the requested dimension), which is
-                // good since we will prefer a config that has specified a
-                // dimension value.
-                int myDelta = 0, otherDelta = 0;
-                if (requested->screenWidthDp) {
-                    myDelta += requested->screenWidthDp - screenWidthDp;
-                    otherDelta += requested->screenWidthDp - o.screenWidthDp;
-                }
-                if (requested->screenHeightDp) {
-                    myDelta += requested->screenHeightDp - screenHeightDp;
-                    otherDelta += requested->screenHeightDp - o.screenHeightDp;
-                }
-                //ALOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d",
-                //    screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp,
-                //    requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta);
-                return (myDelta <= otherDelta);
-            }
-
-            if (screenLayout || o.screenLayout) {
-                if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0
-                        && (requested->screenLayout & MASK_SCREENSIZE)) {
-                    // A little backwards compatibility here: undefined is
-                    // considered equivalent to normal.  But only if the
-                    // requested size is at least normal; otherwise, small
-                    // is better than the default.
-                    int mySL = (screenLayout & MASK_SCREENSIZE);
-                    int oSL = (o.screenLayout & MASK_SCREENSIZE);
-                    int fixedMySL = mySL;
-                    int fixedOSL = oSL;
-                    if ((requested->screenLayout & MASK_SCREENSIZE) >= SCREENSIZE_NORMAL) {
-                        if (fixedMySL == 0) fixedMySL = SCREENSIZE_NORMAL;
-                        if (fixedOSL == 0) fixedOSL = SCREENSIZE_NORMAL;
-                    }
-                    // For screen size, the best match is the one that is
-                    // closest to the requested screen size, but not over
-                    // (the not over part is dealt with in match() below).
-                    if (fixedMySL == fixedOSL) {
-                        // If the two are the same, but 'this' is actually
-                        // undefined, then the other is really a better match.
-                        if (mySL == 0) return false;
-                        return true;
-                    }
-                    return fixedMySL >= fixedOSL;
-                }
-                if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0
-                        && (requested->screenLayout & MASK_SCREENLONG)) {
-                    return (screenLayout & MASK_SCREENLONG);
-                }
-            }
-
-            if ((orientation != o.orientation) && requested->orientation) {
-                return (orientation);
-            }
-
-            if (uiMode || o.uiMode) {
-                if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0
-                        && (requested->uiMode & MASK_UI_MODE_TYPE)) {
-                    return (uiMode & MASK_UI_MODE_TYPE);
-                }
-                if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0
-                        && (requested->uiMode & MASK_UI_MODE_NIGHT)) {
-                    return (uiMode & MASK_UI_MODE_NIGHT);
-                }
-            }
-
-            if (screenType || o.screenType) {
-                if (density != o.density) {
-                    // density is tough.  Any density is potentially useful
-                    // because the system will scale it.  Scaling down
-                    // is generally better than scaling up.
-                    // Default density counts as 160dpi (the system default)
-                    // TODO - remove 160 constants
-                    int h = (density?density:160);
-                    int l = (o.density?o.density:160);
-                    bool bImBigger = true;
-                    if (l > h) {
-                        int t = h;
-                        h = l;
-                        l = t;
-                        bImBigger = false;
-                    }
- 
-                    int reqValue = (requested->density?requested->density:160);
-                    if (reqValue >= h) {
-                        // requested value higher than both l and h, give h
-                        return bImBigger;
-                    }
-                    if (l >= reqValue) {
-                        // requested value lower than both l and h, give l
-                        return !bImBigger;
-                    }
-                    // saying that scaling down is 2x better than up
-                    if (((2 * l) - reqValue) * h > reqValue * reqValue) {
-                        return !bImBigger;
-                    } else { 
-                        return bImBigger;
-                    }
-                }
-
-                if ((touchscreen != o.touchscreen) && requested->touchscreen) {
-                    return (touchscreen);
-                }
-            }
-
-            if (input || o.input) {
-                const int keysHidden = inputFlags & MASK_KEYSHIDDEN;
-                const int oKeysHidden = o.inputFlags & MASK_KEYSHIDDEN;
-                if (keysHidden != oKeysHidden) {
-                    const int reqKeysHidden =
-                            requested->inputFlags & MASK_KEYSHIDDEN;
-                    if (reqKeysHidden) {
-
-                        if (!keysHidden) return false;
-                        if (!oKeysHidden) return true;
-                        // For compatibility, we count KEYSHIDDEN_NO as being
-                        // the same as KEYSHIDDEN_SOFT.  Here we disambiguate
-                        // these by making an exact match more specific.
-                        if (reqKeysHidden == keysHidden) return true;
-                        if (reqKeysHidden == oKeysHidden) return false;
-                    }
-                }
-
-                const int navHidden = inputFlags & MASK_NAVHIDDEN;
-                const int oNavHidden = o.inputFlags & MASK_NAVHIDDEN;
-                if (navHidden != oNavHidden) {
-                    const int reqNavHidden =
-                            requested->inputFlags & MASK_NAVHIDDEN;
-                    if (reqNavHidden) {
-
-                        if (!navHidden) return false;
-                        if (!oNavHidden) return true;
-                    }
-                }
-
-                if ((keyboard != o.keyboard) && requested->keyboard) {
-                    return (keyboard);
-                }
-
-                if ((navigation != o.navigation) && requested->navigation) {
-                    return (navigation);
-                }
-            }
-
-            if (screenSize || o.screenSize) {
-                // "Better" is based on the sum of the difference between both
-                // width and height from the requested dimensions.  We are
-                // assuming the invalid configs (with smaller sizes) have
-                // already been filtered.  Note that if a particular dimension
-                // is unspecified, we will end up with a large value (the
-                // difference between 0 and the requested dimension), which is
-                // good since we will prefer a config that has specified a
-                // size value.
-                int myDelta = 0, otherDelta = 0;
-                if (requested->screenWidth) {
-                    myDelta += requested->screenWidth - screenWidth;
-                    otherDelta += requested->screenWidth - o.screenWidth;
-                }
-                if (requested->screenHeight) {
-                    myDelta += requested->screenHeight - screenHeight;
-                    otherDelta += requested->screenHeight - o.screenHeight;
-                }
-                return (myDelta <= otherDelta);
-            }
-
-            if (version || o.version) {
-                if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) {
-                    return (sdkVersion > o.sdkVersion);
-                }
-
-                if ((minorVersion != o.minorVersion) &&
-                        requested->minorVersion) {
-                    return (minorVersion);
-                }
-            }
-
-            return false;
-        }
-        return isMoreSpecificThan(o);
-    }
+    bool isBetterThan(const ResTable_config& o, const ResTable_config* requested) const;
 
     // Return true if 'this' can be considered a match for the parameters in 
     // 'settings'.
@@ -1454,150 +1048,11 @@
     // but a request for the default should not match odd specifics
     // (ie, request with no mcc should not match a particular mcc's data)
     // settings is the requested settings
-    inline bool match(const ResTable_config& settings) const {
-        if (imsi != 0) {
-            if (mcc != 0 && mcc != settings.mcc) {
-                return false;
-            }
-            if (mnc != 0 && mnc != settings.mnc) {
-                return false;
-            }
-        }
-        if (locale != 0) {
-            if (language[0] != 0
-                && (language[0] != settings.language[0]
-                    || language[1] != settings.language[1])) {
-                return false;
-            }
-            if (country[0] != 0
-                && (country[0] != settings.country[0]
-                    || country[1] != settings.country[1])) {
-                return false;
-            }
-        }
-        if (screenConfig != 0) {
-            const int screenSize = screenLayout&MASK_SCREENSIZE;
-            const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE;
-            // Any screen sizes for larger screens than the setting do not
-            // match.
-            if (screenSize != 0 && screenSize > setScreenSize) {
-                return false;
-            }
-            
-            const int screenLong = screenLayout&MASK_SCREENLONG;
-            const int setScreenLong = settings.screenLayout&MASK_SCREENLONG;
-            if (screenLong != 0 && screenLong != setScreenLong) {
-                return false;
-            }
+    bool match(const ResTable_config& settings) const;
 
-            const int uiModeType = uiMode&MASK_UI_MODE_TYPE;
-            const int setUiModeType = settings.uiMode&MASK_UI_MODE_TYPE;
-            if (uiModeType != 0 && uiModeType != setUiModeType) {
-                return false;
-            }
+    void getLocale(char str[6]) const;
 
-            const int uiModeNight = uiMode&MASK_UI_MODE_NIGHT;
-            const int setUiModeNight = settings.uiMode&MASK_UI_MODE_NIGHT;
-            if (uiModeNight != 0 && uiModeNight != setUiModeNight) {
-                return false;
-            }
-
-            if (smallestScreenWidthDp != 0
-                    && smallestScreenWidthDp > settings.smallestScreenWidthDp) {
-                return false;
-            }
-        }
-        if (screenSizeDp != 0) {
-            if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) {
-                //ALOGI("Filtering out width %d in requested %d", screenWidthDp, settings.screenWidthDp);
-                return false;
-            }
-            if (screenHeightDp != 0 && screenHeightDp > settings.screenHeightDp) {
-                //ALOGI("Filtering out height %d in requested %d", screenHeightDp, settings.screenHeightDp);
-                return false;
-            }
-        }
-        if (screenType != 0) {
-            if (orientation != 0 && orientation != settings.orientation) {
-                return false;
-            }
-            // density always matches - we can scale it.  See isBetterThan
-            if (touchscreen != 0 && touchscreen != settings.touchscreen) {
-                return false;
-            }
-        }
-        if (input != 0) {
-            const int keysHidden = inputFlags&MASK_KEYSHIDDEN;
-            const int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN;
-            if (keysHidden != 0 && keysHidden != setKeysHidden) {
-                // For compatibility, we count a request for KEYSHIDDEN_NO as also
-                // matching the more recent KEYSHIDDEN_SOFT.  Basically
-                // KEYSHIDDEN_NO means there is some kind of keyboard available.
-                //ALOGI("Matching keysHidden: have=%d, config=%d\n", keysHidden, setKeysHidden);
-                if (keysHidden != KEYSHIDDEN_NO || setKeysHidden != KEYSHIDDEN_SOFT) {
-                    //ALOGI("No match!");
-                    return false;
-                }
-            }
-            const int navHidden = inputFlags&MASK_NAVHIDDEN;
-            const int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN;
-            if (navHidden != 0 && navHidden != setNavHidden) {
-                return false;
-            }
-            if (keyboard != 0 && keyboard != settings.keyboard) {
-                return false;
-            }
-            if (navigation != 0 && navigation != settings.navigation) {
-                return false;
-            }
-        }
-        if (screenSize != 0) {
-            if (screenWidth != 0 && screenWidth > settings.screenWidth) {
-                return false;
-            }
-            if (screenHeight != 0 && screenHeight > settings.screenHeight) {
-                return false;
-            }
-        }
-        if (version != 0) {
-            if (sdkVersion != 0 && sdkVersion > settings.sdkVersion) {
-                return false;
-            }
-            if (minorVersion != 0 && minorVersion != settings.minorVersion) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    void getLocale(char str[6]) const {
-        memset(str, 0, 6);
-        if (language[0]) {
-            str[0] = language[0];
-            str[1] = language[1];
-            if (country[0]) {
-                str[2] = '_';
-                str[3] = country[0];
-                str[4] = country[1];
-            }
-        }
-    }
-
-    String8 toString() const {
-        char buf[200];
-        sprintf(buf, "imsi=%d/%d lang=%c%c reg=%c%c orient=%d touch=%d dens=%d "
-                "kbd=%d nav=%d input=%d ssz=%dx%d sw%ddp w%ddp h%ddp sz=%d long=%d "
-                "ui=%d night=%d vers=%d.%d",
-                mcc, mnc,
-                language[0] ? language[0] : '-', language[1] ? language[1] : '-',
-                country[0] ? country[0] : '-', country[1] ? country[1] : '-',
-                orientation, touchscreen, density, keyboard, navigation, inputFlags,
-                screenWidth, screenHeight, smallestScreenWidthDp, screenWidthDp, screenHeightDp,
-                screenLayout&MASK_SCREENSIZE, screenLayout&MASK_SCREENLONG,
-                uiMode&MASK_UI_MODE_TYPE, uiMode&MASK_UI_MODE_NIGHT,
-                sdkVersion, minorVersion);
-        return String8(buf);
-    }
+    String8 toString() const;
 };
 
 /**
@@ -2056,8 +1511,14 @@
     const char16_t* getBasePackageName(size_t idx) const;
     uint32_t getBasePackageId(size_t idx) const;
 
+    // Return the number of resource tables that the object contains.
     size_t getTableCount() const;
+    // Return the values string pool for the resource table at the given
+    // index.  This string pool contains all of the strings for values
+    // contained in the resource table -- that is the item values themselves,
+    // but not the names their entries or types.
     const ResStringPool* getTableStringBlock(size_t index) const;
+    // Return unique cookie identifier for the given resource table.
     void* getTableCookie(size_t index) const;
 
     // Return the configurations (ResTable_config) that we know about
diff --git a/include/utils/threads.h b/include/utils/threads.h
index ab3e8cd..b4a8b7c 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -526,6 +526,12 @@
     // Do not call from this object's thread; will return WOULD_BLOCK in that case.
             status_t    join();
 
+#ifdef HAVE_ANDROID_OS
+    // Return the thread's kernel ID, same as the thread itself calling gettid() or
+    // androidGetTid(), or -1 if the thread is not running.
+            pid_t       getTid() const;
+#endif
+
 protected:
     // exitPending() returns true if requestExit() has been called.
             bool        exitPending() const;
@@ -551,8 +557,10 @@
     volatile bool           mExitPending;
     volatile bool           mRunning;
             sp<Thread>      mHoldSelf;
-#if HAVE_ANDROID_OS
-            int             mTid;
+#ifdef HAVE_ANDROID_OS
+    // legacy for debugging, not used by getTid() as it is set by the child thread
+    // and so is not initialized until the child reaches that point
+            pid_t           mTid;
 #endif
 };
 
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index 3b3ccaa..6a4763d 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -80,7 +80,13 @@
 
 ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events,
         size_t count) {
-    ssize_t size = mDataChannel->read(events, sizeof(events[0])*count);
+    return DisplayEventReceiver::getEvents(mDataChannel, events, count);
+}
+
+ssize_t DisplayEventReceiver::getEvents(const sp<BitTube>& dataChannel,
+        Event* events, size_t count)
+{
+    ssize_t size = dataChannel->read(events, sizeof(events[0])*count);
     ALOGE_IF(size<0,
             "DisplayEventReceiver::getEvents error (%s)",
             strerror(-size));
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 95e0a18..5ec3983 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -26,6 +26,7 @@
 		ShapeCache.cpp \
 		SkiaColorFilter.cpp \
 		SkiaShader.cpp \
+		Snapshot.cpp \
 		TextureCache.cpp \
 		TextDropShadowCache.cpp
 	
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index d1af1a3..0ef8469 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -55,6 +55,16 @@
 
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
 
+    if (extensions.hasDebugMarker()) {
+        eventMark = glInsertEventMarkerEXT;
+        startMark = glPushGroupMarkerEXT;
+        endMark = glPopGroupMarkerEXT;
+    } else {
+        eventMark = eventMarkNull;
+        startMark = startMarkNull;
+        endMark = endMarkNull;
+    }
+
     init();
 
     mDebugLevel = readDebugLevel();
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 409584f..f8c7bcc 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -240,7 +240,15 @@
     GammaFontRenderer fontRenderer;
     ResourceCache resourceCache;
 
+    PFNGLINSERTEVENTMARKEREXTPROC eventMark;
+    PFNGLPUSHGROUPMARKEREXTPROC startMark;
+    PFNGLPOPGROUPMARKEREXTPROC endMark;
+
 private:
+    static void eventMarkNull(GLsizei length, const GLchar *marker) { }
+    static void startMarkNull(GLsizei length, const GLchar *marker) { }
+    static void endMarkNull() { }
+
     GLuint mCurrentBuffer;
     GLuint mCurrentIndicesBuffer;
     void* mCurrentPositionPointer;
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 0ad0c2a..16a3d73 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -62,6 +62,9 @@
 // Turn on to display debug info about the layer renderer
 #define DEBUG_LAYER_RENDERER 0
 
+// Turn on to enable additional debugging in the font renderers
+#define DEBUG_FONT_RENDERER 0
+
 // Turn on to dump display list state
 #define DEBUG_DISPLAY_LIST 0
 
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index ee935e4..1a11fbc 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -19,9 +19,10 @@
 
 #include "DisplayListLogBuffer.h"
 #include "DisplayListRenderer.h"
-#include <utils/String8.h>
 #include "Caches.h"
 
+#include <utils/String8.h>
+
 namespace android {
 namespace uirenderer {
 
@@ -217,7 +218,7 @@
         indent[i] = ' ';
     }
     indent[count] = '\0';
-    ALOGD("%sStart display list (%p)", (char*) indent + 2, this);
+    ALOGD("%sStart display list (%p, %s)", (char*) indent + 2, this, mName.string());
 
     int saveCount = renderer.getSaveCount() - 1;
 
@@ -562,9 +563,11 @@
         indent[i] = ' ';
     }
     indent[count] = '\0';
-    DISPLAY_LIST_LOGD("%sStart display list (%p)", (char*) indent + 2, this);
+    DISPLAY_LIST_LOGD("%sStart display list (%p, %s)", (char*) indent + 2, this, mName.string());
 #endif
 
+    renderer.startMark(mName.string());
+
     DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
     int saveCount = renderer.getSaveCount() - 1;
     while (!mReader.eof()) {
@@ -575,7 +578,9 @@
             case DrawGLFunction: {
                 Functor *functor = (Functor *) getInt();
                 DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor);
+                renderer.startMark("GL functor");
                 needsInvalidate |= renderer.callDrawGLFunction(functor, dirty);
+                renderer.endMark();
             }
             break;
             case Save: {
@@ -934,6 +939,8 @@
         }
     }
 
+    renderer.endMark();
+
     DISPLAY_LIST_LOGD("%sDone, returning %d", (char*) indent + 2, needsInvalidate);
     return needsInvalidate;
 }
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 6fe4205..46506e4 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -28,6 +28,8 @@
 
 #include <cutils/compiler.h>
 
+#include <utils/String8.h>
+
 #include "DisplayListLogBuffer.h"
 #include "OpenGLRenderer.h"
 #include "utils/Functor.h"
@@ -128,6 +130,12 @@
         return mIsRenderable;
     }
 
+    void setName(const char* name) {
+        if (name) {
+            mName.setTo(name);
+        }
+    }
+
 private:
     void init();
 
@@ -224,6 +232,8 @@
     size_t mSize;
 
     bool mIsRenderable;
+
+    String8 mName;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 1069e3f..f11fecc 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -67,6 +67,7 @@
         mHasNPot = hasExtension("GL_OES_texture_npot");
         mHasFramebufferFetch = hasExtension("GL_NV_shader_framebuffer_fetch");
         mHasDiscardFramebuffer = hasExtension("GL_EXT_discard_framebuffer");
+        mHasDebugMarker = hasExtension("GL_EXT_debug_marker");
 
         const char* vendor = (const char*) glGetString(GL_VENDOR);
         EXT_LOGD("Vendor: %s", vendor);
@@ -82,6 +83,7 @@
     inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
     inline bool needsHighpTexCoords() const { return mNeedsHighpTexCoords; }
     inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; }
+    inline bool hasDebugMarker() const { return mHasDebugMarker; }
 
     bool hasExtension(const char* extension) const {
         const String8 s(extension);
@@ -101,6 +103,7 @@
     bool mNeedsHighpTexCoords;
     bool mHasFramebufferFetch;
     bool mHasDiscardFramebuffer;
+    bool mHasDebugMarker;
 }; // class Extensions
 
 }; // namespace uirenderer
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 74efda2..3df105b 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -151,10 +151,12 @@
     int32_t bX = 0, bY = 0;
     for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
         for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
+#if DEBUG_FONT_RENDERER
             if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
                 ALOGE("Skipping invalid index");
                 continue;
             }
+#endif
             uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
             bitmap[bY * bitmapW + bX] = tempCol;
         }
@@ -226,7 +228,7 @@
     };
     RenderGlyph render = gRenderGlyph[mode];
 
-    if (positions == NULL) {
+    if (CC_LIKELY(positions == NULL)) {
         SkFixed prevRsbDelta = 0;
 
         float penX = x;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index cc0e05e..afae70f 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -124,9 +124,25 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
+// Debug
+///////////////////////////////////////////////////////////////////////////////
+
+void OpenGLRenderer::startMark(const char* name) const {
+    mCaches.startMark(0, name);
+}
+
+void OpenGLRenderer::endMark() const {
+    mCaches.endMark();
+}
+
+///////////////////////////////////////////////////////////////////////////////
 // Setup
 ///////////////////////////////////////////////////////////////////////////////
 
+uint32_t OpenGLRenderer::getStencilSize() {
+    return STENCIL_BUFFER_SIZE;
+}
+
 void OpenGLRenderer::setViewport(int width, int height) {
     mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
 
@@ -738,7 +754,7 @@
 
     // TODO: See LayerRenderer.cpp::generateMesh() for important
     //       information about this implementation
-    if (!layer->region.isEmpty()) {
+    if (CC_LIKELY(!layer->region.isEmpty())) {
         size_t count;
         const android::Rect* rects = layer->region.getArray(&count);
 
@@ -1382,7 +1398,7 @@
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
-    if (bitmap->getConfig() == SkBitmap::kA8_Config) {
+    if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
         drawAlphaBitmap(texture, left, top, paint);
     } else {
         drawTextureRect(left, top, right, bottom, texture, paint);
@@ -1438,9 +1454,9 @@
     float bottom = FLT_MIN;
 
 #if RENDER_LAYERS_AS_REGIONS
-    bool hasActiveLayer = hasLayer();
+    const bool hasActiveLayer = hasLayer();
 #else
-    bool hasActiveLayer = false;
+    const bool hasActiveLayer = false;
 #endif
 
     // TODO: Support the colors array
@@ -1525,7 +1541,7 @@
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
 
-    if (mSnapshot->transform->isPureTranslate()) {
+    if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
         const float x = (int) floorf(dstLeft + mSnapshot->transform->getTranslateX() + 0.5f);
         const float y = (int) floorf(dstTop + mSnapshot->transform->getTranslateY() + 0.5f);
 
@@ -1571,7 +1587,7 @@
     const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(),
             right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors);
 
-    if (mesh && mesh->verticesCount > 0) {
+    if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
         const bool pureTranslate = mSnapshot->transform->isPureTranslate();
 #if RENDER_LAYERS_AS_REGIONS
         // Mark the current layer dirty where we are going to draw the patch
@@ -1581,7 +1597,7 @@
             const size_t count = mesh->quads.size();
             for (size_t i = 0; i < count; i++) {
                 const Rect& bounds = mesh->quads.itemAt(i);
-                if (pureTranslate) {
+                if (CC_LIKELY(pureTranslate)) {
                     const float x = (int) floorf(bounds.left + offsetX + 0.5f);
                     const float y = (int) floorf(bounds.top + offsetY + 0.5f);
                     dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
@@ -1593,7 +1609,7 @@
         }
 #endif
 
-        if (pureTranslate) {
+        if (CC_LIKELY(pureTranslate)) {
             const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f);
             const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f);
 
@@ -1621,7 +1637,7 @@
     float inverseScaleX = 1.0f;
     float inverseScaleY = 1.0f;
     // The quad that we use needs to account for scaling.
-    if (!mSnapshot->transform->isPureTranslate()) {
+    if (CC_UNLIKELY(!mSnapshot->transform->isPureTranslate())) {
         Matrix4 *mat = mSnapshot->transform;
         float m00 = mat->data[Matrix4::kScaleX];
         float m01 = mat->data[Matrix4::kSkewY];
@@ -1727,7 +1743,7 @@
         // The quad that we use for AA and hairlines needs to account for scaling. For hairlines
         // the line on the screen should always be one pixel wide regardless of scale. For
         // AA lines, we only want one pixel of translucent boundary around the quad.
-        if (!mSnapshot->transform->isPureTranslate()) {
+        if (CC_UNLIKELY(!mSnapshot->transform->isPureTranslate())) {
             Matrix4 *mat = mSnapshot->transform;
             float m00 = mat->data[Matrix4::kScaleX];
             float m01 = mat->data[Matrix4::kSkewY];
@@ -1735,8 +1751,8 @@
             float m10 = mat->data[Matrix4::kSkewX];
             float m11 = mat->data[Matrix4::kScaleX];
             float m12 = mat->data[6];
-            float scaleX = sqrt(m00*m00 + m01*m01);
-            float scaleY = sqrt(m10*m10 + m11*m11);
+            float scaleX = sqrtf(m00 * m00 + m01 * m01);
+            float scaleY = sqrtf(m10 * m10 + m11 * m11);
             inverseScaleX = (scaleX != 0) ? (inverseScaleX / scaleX) : 0;
             inverseScaleY = (scaleY != 0) ? (inverseScaleY / scaleY) : 0;
             if (inverseScaleX != 1.0f || inverseScaleY != 1.0f) {
@@ -1754,11 +1770,7 @@
     setupDrawColor(paint->getColor(), alpha);
     setupDrawColorFilter();
     setupDrawShader();
-    if (isAA) {
-        setupDrawBlending(true, mode);
-    } else {
-        setupDrawBlending(mode);
-    }
+    setupDrawBlending(isAA, mode);
     setupDrawProgram();
     setupDrawModelViewIdentity(true);
     setupDrawColorUniforms();
@@ -1776,7 +1788,7 @@
     Vertex* vertices = &lines[0];
     AAVertex wLines[verticesCount];
     AAVertex* aaVertices = &wLines[0];
-    if (!isAA) {
+    if (CC_UNLIKELY(!isAA)) {
         setupDrawVertices(vertices);
     } else {
         void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset;
@@ -2136,9 +2148,9 @@
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
 #if RENDER_LAYERS_AS_REGIONS
-    bool hasActiveLayer = hasLayer();
+    const bool hasActiveLayer = hasLayer();
 #else
-    bool hasActiveLayer = false;
+    const bool hasActiveLayer = false;
 #endif
 
     if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
@@ -2185,7 +2197,7 @@
     const float oldX = x;
     const float oldY = y;
     const bool pureTranslate = mSnapshot->transform->isPureTranslate();
-    if (pureTranslate) {
+    if (CC_LIKELY(pureTranslate)) {
         x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
         y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
     }
@@ -2202,7 +2214,7 @@
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
-    if (mHasShadow) {
+    if (CC_UNLIKELY(mHasShadow)) {
         mCaches.activeTexture(0);
 
         mCaches.dropShadowCache.setFontRenderer(fontRenderer);
@@ -2261,9 +2273,9 @@
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
 #if RENDER_LAYERS_AS_REGIONS
-    bool hasActiveLayer = hasLayer();
+    const bool hasActiveLayer = hasLayer();
 #else
-    bool hasActiveLayer = false;
+    const bool hasActiveLayer = false;
 #endif
 
     if (fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y,
@@ -2310,7 +2322,7 @@
     layer->setAlpha(alpha, mode);
 
 #if RENDER_LAYERS_AS_REGIONS
-    if (!layer->region.isEmpty()) {
+    if (CC_LIKELY(!layer->region.isEmpty())) {
         if (layer->region.isRect()) {
             composeLayerRect(layer, layer->regionRect);
         } else if (layer->mesh) {
@@ -2326,7 +2338,7 @@
             setupDrawPureColorUniforms();
             setupDrawColorFilterUniforms();
             setupDrawTexture(layer->getTexture());
-            if (mSnapshot->transform->isPureTranslate()) {
+            if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
                 x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
                 y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
 
@@ -2486,7 +2498,7 @@
                 break;
         }
 
-        if (underlineWidth > 0.0f) {
+        if (CC_LIKELY(underlineWidth > 0.0f)) {
             const float textSize = paintCopy.getTextSize();
             const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
 
@@ -2555,7 +2567,7 @@
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
 
-    if (mSnapshot->transform->isPureTranslate()) {
+    if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
         const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f);
         const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f);
 
@@ -2615,8 +2627,8 @@
         // the blending, turn blending off here
         // If the blend mode cannot be implemented using shaders, fall
         // back to the default SrcOver blend mode instead
-        if (mode > SkXfermode::kScreen_Mode) {
-            if (mCaches.extensions.hasFramebufferFetch()) {
+        if CC_UNLIKELY((mode > SkXfermode::kScreen_Mode)) {
+            if (CC_UNLIKELY(mCaches.extensions.hasFramebufferFetch())) {
                 description.framebufferMode = mode;
                 description.swapSrcDst = swapSrcDst;
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index ae355bb..3c2d09e 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -141,6 +141,11 @@
 
     SkPaint* filterPaint(SkPaint* paint);
 
+    ANDROID_API static uint32_t getStencilSize();
+
+    void startMark(const char* name) const;
+    void endMark() const;
+
 protected:
     /**
      * Compose the layer defined in the current snapshot with the layer
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 2eae0f1..7854729 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -37,6 +37,11 @@
 // Textures used by layers must have dimensions multiples of this number
 #define LAYER_SIZE 64
 
+// Defines the size in bits of the stencil buffer
+// Note: Only 1 bit is required for clipping but more bits are required
+// to properly implement the winding fill rule when rasterizing paths
+#define STENCIL_BUFFER_SIZE 0
+
 /**
  * Debug level for app developers.
  */
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
new file mode 100644
index 0000000..a85362d
--- /dev/null
+++ b/libs/hwui/Snapshot.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Snapshot.h"
+
+#include <SkCanvas.h>
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructors
+///////////////////////////////////////////////////////////////////////////////
+
+Snapshot::Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0),
+        invisible(false), empty(false) {
+
+    transform = &mTransformRoot;
+    clipRect = &mClipRectRoot;
+    region = NULL;
+}
+
+/**
+ * Copies the specified snapshot/ The specified snapshot is stored as
+ * the previous snapshot.
+ */
+Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags):
+        flags(0), previous(s), layer(NULL), fbo(s->fbo),
+        invisible(s->invisible), empty(false),
+        viewport(s->viewport), height(s->height) {
+
+    if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
+        mTransformRoot.load(*s->transform);
+        transform = &mTransformRoot;
+    } else {
+        transform = s->transform;
+    }
+
+    if (saveFlags & SkCanvas::kClip_SaveFlag) {
+        mClipRectRoot.set(*s->clipRect);
+        clipRect = &mClipRectRoot;
+    } else {
+        clipRect = s->clipRect;
+    }
+
+    if (s->flags & Snapshot::kFlagFboTarget) {
+        flags |= Snapshot::kFlagFboTarget;
+        region = s->region;
+    } else {
+        region = NULL;
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Clipping
+///////////////////////////////////////////////////////////////////////////////
+
+bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
+    Rect r(left, top, right, bottom);
+    transform->mapRect(r);
+    return clipTransformed(r, op);
+}
+
+bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) {
+    bool clipped = false;
+
+    // NOTE: The unimplemented operations require support for regions
+    // Supporting regions would require using a stencil buffer instead
+    // of the scissor. The stencil buffer itself is not too expensive
+    // (memory cost excluded) but on fillrate limited devices, managing
+    // the stencil might have a negative impact on the framerate.
+    switch (op) {
+        case SkRegion::kDifference_Op:
+            break;
+        case SkRegion::kIntersect_Op:
+            clipped = clipRect->intersect(r);
+            if (!clipped) {
+                clipRect->setEmpty();
+                clipped = true;
+            }
+            break;
+        case SkRegion::kUnion_Op:
+            clipped = clipRect->unionWith(r);
+            break;
+        case SkRegion::kXOR_Op:
+            break;
+        case SkRegion::kReverseDifference_Op:
+            break;
+        case SkRegion::kReplace_Op:
+            clipRect->set(r);
+            clipped = true;
+            break;
+    }
+
+    if (clipped) {
+        flags |= Snapshot::kFlagClipSet;
+    }
+
+    return clipped;
+}
+
+void Snapshot::setClip(float left, float top, float right, float bottom) {
+    clipRect->set(left, top, right, bottom);
+    flags |= Snapshot::kFlagClipSet;
+}
+
+const Rect& Snapshot::getLocalClip() {
+    mat4 inverse;
+    inverse.loadInverse(*transform);
+
+    mLocalClip.set(*clipRect);
+    inverse.mapRect(mLocalClip);
+
+    return mLocalClip;
+}
+
+void Snapshot::resetClip(float left, float top, float right, float bottom) {
+    clipRect = &mClipRectRoot;
+    clipRect->set(left, top, right, bottom);
+    flags |= Snapshot::kFlagClipSet;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Transforms
+///////////////////////////////////////////////////////////////////////////////
+
+void Snapshot::resetTransform(float x, float y, float z) {
+    transform = &mTransformRoot;
+    transform->loadTranslate(x, y, z);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Queries
+///////////////////////////////////////////////////////////////////////////////
+
+bool Snapshot::isIgnored() const {
+    return invisible || empty;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index aff7b93..c94af7e 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -23,7 +23,7 @@
 #include <utils/RefBase.h>
 #include <ui/Region.h>
 
-#include <SkCanvas.h>
+#include <SkRegion.h>
 
 #include "Layer.h"
 #include "Matrix.h"
@@ -43,43 +43,12 @@
  */
 class Snapshot: public LightRefBase<Snapshot> {
 public:
-    Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0), invisible(false), empty(false) {
-        transform = &mTransformRoot;
-        clipRect = &mClipRectRoot;
-        region = NULL;
-    }
+
+    Snapshot();
+    Snapshot(const sp<Snapshot>& s, int saveFlags);
 
     /**
-     * Copies the specified snapshot/ The specified snapshot is stored as
-     * the previous snapshot.
-     */
-    Snapshot(const sp<Snapshot>& s, int saveFlags):
-            flags(0), previous(s), layer(NULL), fbo(s->fbo),
-            invisible(s->invisible), empty(false), viewport(s->viewport), height(s->height) {
-        if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
-            mTransformRoot.load(*s->transform);
-            transform = &mTransformRoot;
-        } else {
-            transform = s->transform;
-        }
-
-        if (saveFlags & SkCanvas::kClip_SaveFlag) {
-            mClipRectRoot.set(*s->clipRect);
-            clipRect = &mClipRectRoot;
-        } else {
-            clipRect = s->clipRect;
-        }
-
-        if (s->flags & Snapshot::kFlagFboTarget) {
-            flags |= Snapshot::kFlagFboTarget;
-            region = s->region;
-        } else {
-            region = NULL;
-        }
-    }
-
-    /**
-     * Various flags set on #flags.
+     * Various flags set on ::flags.
      */
     enum Flags {
         /**
@@ -115,87 +84,41 @@
      * by this snapshot's trasnformation.
      */
     bool clip(float left, float top, float right, float bottom,
-            SkRegion::Op op = SkRegion::kIntersect_Op) {
-        Rect r(left, top, right, bottom);
-        transform->mapRect(r);
-        return clipTransformed(r, op);
-    }
+            SkRegion::Op op = SkRegion::kIntersect_Op);
 
     /**
      * Modifies the current clip with the new clip rectangle and
      * the specified operation. The specified rectangle is considered
      * already transformed.
      */
-    bool clipTransformed(const Rect& r, SkRegion::Op op = SkRegion::kIntersect_Op) {
-        bool clipped = false;
-
-        // NOTE: The unimplemented operations require support for regions
-        // Supporting regions would require using a stencil buffer instead
-        // of the scissor. The stencil buffer itself is not too expensive
-        // (memory cost excluded) but on fillrate limited devices, managing
-        // the stencil might have a negative impact on the framerate.
-        switch (op) {
-            case SkRegion::kDifference_Op:
-                break;
-            case SkRegion::kIntersect_Op:
-                clipped = clipRect->intersect(r);
-                if (!clipped) {
-                    clipRect->setEmpty();
-                    clipped = true;
-                }
-                break;
-            case SkRegion::kUnion_Op:
-                clipped = clipRect->unionWith(r);
-                break;
-            case SkRegion::kXOR_Op:
-                break;
-            case SkRegion::kReverseDifference_Op:
-                break;
-            case SkRegion::kReplace_Op:
-                clipRect->set(r);
-                clipped = true;
-                break;
-        }
-
-        if (clipped) {
-            flags |= Snapshot::kFlagClipSet;
-        }
-
-        return clipped;
-    }
+    bool clipTransformed(const Rect& r, SkRegion::Op op = SkRegion::kIntersect_Op);
 
     /**
      * Sets the current clip.
      */
-    void setClip(float left, float top, float right, float bottom) {
-        clipRect->set(left, top, right, bottom);
-        flags |= Snapshot::kFlagClipSet;
-    }
+    void setClip(float left, float top, float right, float bottom);
 
-    const Rect& getLocalClip() {
-        mat4 inverse;
-        inverse.loadInverse(*transform);
+    /**
+     * Returns the current clip in local coordinates. The clip rect is
+     * transformed by the inverse transform matrix.
+     */
+    const Rect& getLocalClip();
 
-        mLocalClip.set(*clipRect);
-        inverse.mapRect(mLocalClip);
+    /**
+     * Resets the clip to the specified rect.
+     */
+    void resetClip(float left, float top, float right, float bottom);
 
-        return mLocalClip;
-    }
+    /**
+     * Resets the current transform to a pure 3D translation.
+     */
+    void resetTransform(float x, float y, float z);
 
-    void resetTransform(float x, float y, float z) {
-        transform = &mTransformRoot;
-        transform->loadTranslate(x, y, z);
-    }
-
-    void resetClip(float left, float top, float right, float bottom) {
-        clipRect = &mClipRectRoot;
-        clipRect->set(left, top, right, bottom);
-        flags |= Snapshot::kFlagClipSet;
-    }
-
-    bool isIgnored() const {
-        return invisible || empty;
-    }
+    /**
+     * Indicates whether this snapshot should be ignored. A snapshot
+     * is typicalled ignored if its layer is invisible or empty.
+     */
+    bool isIgnored() const;
 
     /**
      * Dirty flags.
@@ -209,6 +132,8 @@
 
     /**
      * Only set when the flag kFlagIsLayer is set.
+     *
+     * This snapshot does not own the layer, this pointer must not be freed.
      */
     Layer* layer;
 
@@ -249,17 +174,26 @@
     /**
      * Local transformation. Holds the current translation, scale and
      * rotation values.
+     *
+     * This is a reference to a matrix owned by this snapshot or another
+     *  snapshot. This pointer must not be freed. See ::mTransformRoot.
      */
     mat4* transform;
 
     /**
      * Current clip region. The clip is stored in canvas-space coordinates,
      * (screen-space coordinates in the regular case.)
+     *
+     * This is a reference to a rect owned by this snapshot or another
+     * snapshot. This pointer must not be freed. See ::mClipRectRoot.
      */
     Rect* clipRect;
 
     /**
      * The ancestor layer's dirty region.
+     *
+     * This is a reference to a region owned by a layer. This pointer must
+     * not be freed.
      */
     Region* region;
 
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 20b1f52..6887b22 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -162,7 +162,7 @@
 	param uint32_t x
 	param uint32_t lod
 	param const void *data
-	param uint32_t comp_offset
+	param size_t comp_offset
 	}
 
 Allocation2DData {
@@ -183,7 +183,7 @@
 	param uint32_t lod
 	param RsAllocationCubemapFace face
 	param const void *data
-	param uint32_t element_offset
+	param size_t element_offset
 	}
 
 AllocationGenerateMipmaps {
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index 2773d5c..fd85b07 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2009-2012 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.
@@ -71,11 +71,11 @@
 }
 
 void Allocation::data(Context *rsc, uint32_t xoff, uint32_t lod,
-                         uint32_t count, const void *data, uint32_t sizeBytes) {
-    const uint32_t eSize = mHal.state.type->getElementSizeBytes();
+                         uint32_t count, const void *data, size_t sizeBytes) {
+    const size_t eSize = mHal.state.type->getElementSizeBytes();
 
     if ((count * eSize) != sizeBytes) {
-        ALOGE("Allocation::subData called with mismatched size expected %i, got %i",
+        ALOGE("Allocation::subData called with mismatched size expected %zu, got %zu",
              (count * eSize), sizeBytes);
         mHal.state.type->dumpLOGV("type info");
         return;
@@ -86,14 +86,14 @@
 }
 
 void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
-             uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) {
-    const uint32_t eSize = mHal.state.elementSizeBytes;
-    const uint32_t lineSize = eSize * w;
+             uint32_t w, uint32_t h, const void *data, size_t sizeBytes) {
+    const size_t eSize = mHal.state.elementSizeBytes;
+    const size_t lineSize = eSize * w;
 
     //ALOGE("data2d %p,  %i %i %i %i %i %i %p %i", this, xoff, yoff, lod, face, w, h, data, sizeBytes);
 
     if ((lineSize * h) != sizeBytes) {
-        ALOGE("Allocation size mismatch, expected %i, got %i", (lineSize * h), sizeBytes);
+        ALOGE("Allocation size mismatch, expected %zu, got %zu", (lineSize * h), sizeBytes);
         rsAssert(!"Allocation::subData called with mismatched size");
         return;
     }
@@ -104,12 +104,12 @@
 
 void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff,
                       uint32_t lod, RsAllocationCubemapFace face,
-                      uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) {
+                      uint32_t w, uint32_t h, uint32_t d, const void *data, size_t sizeBytes) {
 }
 
 void Allocation::elementData(Context *rsc, uint32_t x, const void *data,
-                                uint32_t cIdx, uint32_t sizeBytes) {
-    uint32_t eSize = mHal.state.elementSizeBytes;
+                                uint32_t cIdx, size_t sizeBytes) {
+    size_t eSize = mHal.state.elementSizeBytes;
 
     if (cIdx >= mHal.state.type->getElement()->getFieldCount()) {
         ALOGE("Error Allocation::subElementData component %i out of range.", cIdx);
@@ -124,8 +124,9 @@
     }
 
     const Element * e = mHal.state.type->getElement()->getField(cIdx);
-    if (sizeBytes != e->getSizeBytes()) {
-        ALOGE("Error Allocation::subElementData data size %i does not match field size %zu.", sizeBytes, e->getSizeBytes());
+    uint32_t elemArraySize = mHal.state.type->getElement()->getFieldArraySize(cIdx);
+    if (sizeBytes != e->getSizeBytes() * elemArraySize) {
+        ALOGE("Error Allocation::subElementData data size %zu does not match field size %zu.", sizeBytes, e->getSizeBytes());
         rsc->setError(RS_ERROR_BAD_VALUE, "subElementData bad size.");
         return;
     }
@@ -135,8 +136,8 @@
 }
 
 void Allocation::elementData(Context *rsc, uint32_t x, uint32_t y,
-                                const void *data, uint32_t cIdx, uint32_t sizeBytes) {
-    uint32_t eSize = mHal.state.elementSizeBytes;
+                                const void *data, uint32_t cIdx, size_t sizeBytes) {
+    size_t eSize = mHal.state.elementSizeBytes;
 
     if (x >= mHal.state.dimensionX) {
         ALOGE("Error Allocation::subElementData X offset %i out of range.", x);
@@ -157,9 +158,9 @@
     }
 
     const Element * e = mHal.state.type->getElement()->getField(cIdx);
-
-    if (sizeBytes != e->getSizeBytes()) {
-        ALOGE("Error Allocation::subElementData data size %i does not match field size %zu.", sizeBytes, e->getSizeBytes());
+    uint32_t elemArraySize = mHal.state.type->getElement()->getFieldArraySize(cIdx);
+    if (sizeBytes != e->getSizeBytes() * elemArraySize) {
+        ALOGE("Error Allocation::subElementData data size %zu does not match field size %zu.", sizeBytes, e->getSizeBytes());
         rsc->setError(RS_ERROR_BAD_VALUE, "subElementData bad size.");
         return;
     }
@@ -249,7 +250,7 @@
     delete[] sizeUnpadded;
 }
 
-void Allocation::unpackVec3Allocation(const void *data, uint32_t dataSize) {
+void Allocation::unpackVec3Allocation(const void *data, size_t dataSize) {
     const uint8_t *src = (const uint8_t*)data;
     uint8_t *dst = (uint8_t*)getPtr();
 
@@ -519,13 +520,13 @@
 }
 
 void rsi_Allocation2DElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t y, uint32_t lod, RsAllocationCubemapFace face,
-                                 const void *data, size_t eoff, uint32_t sizeBytes) { // TODO: this seems wrong, eoff and sizeBytes may be swapped
+                                 const void *data, size_t sizeBytes, size_t eoff) {
     Allocation *a = static_cast<Allocation *>(va);
     a->elementData(rsc, x, y, data, eoff, sizeBytes);
 }
 
 void rsi_Allocation1DElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t lod,
-                                 const void *data, size_t eoff, uint32_t sizeBytes) { // TODO: this seems wrong, eoff and sizeBytes may be swapped
+                                 const void *data, size_t sizeBytes, size_t eoff) {
     Allocation *a = static_cast<Allocation *>(va);
     a->elementData(rsc, x, data, eoff, sizeBytes);
 }
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
index 4ce863a..20201ca 100644
--- a/libs/rs/rsAllocation.h
+++ b/libs/rs/rsAllocation.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2009-2012 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.
@@ -80,16 +80,16 @@
     void resize1D(Context *rsc, uint32_t dimX);
     void resize2D(Context *rsc, uint32_t dimX, uint32_t dimY);
 
-    void data(Context *rsc, uint32_t xoff, uint32_t lod, uint32_t count, const void *data, uint32_t sizeBytes);
+    void data(Context *rsc, uint32_t xoff, uint32_t lod, uint32_t count, const void *data, size_t sizeBytes);
     void data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
-                 uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes);
+                 uint32_t w, uint32_t h, const void *data, size_t sizeBytes);
     void data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t lod, RsAllocationCubemapFace face,
-                 uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes);
+                 uint32_t w, uint32_t h, uint32_t d, const void *data, size_t sizeBytes);
 
     void elementData(Context *rsc, uint32_t x,
-                        const void *data, uint32_t elementOff, uint32_t sizeBytes);
+                     const void *data, uint32_t elementOff, size_t sizeBytes);
     void elementData(Context *rsc, uint32_t x, uint32_t y,
-                        const void *data, uint32_t elementOff, uint32_t sizeBytes);
+                     const void *data, uint32_t elementOff, size_t sizeBytes);
 
     void read(void *data);
 
@@ -138,7 +138,7 @@
 
     uint32_t getPackedSize() const;
     static void writePackedData(const Type *type, uint8_t *dst, const uint8_t *src, bool dstPadded);
-    void unpackVec3Allocation(const void *data, uint32_t dataSize);
+    void unpackVec3Allocation(const void *data, size_t dataSize);
     void packVec3Allocation(OStream *stream) const;
 };
 
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index afc8ba0..b4eb995 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -206,7 +206,6 @@
         return false;
     }
 
-    rsAssert(bcWrapper.getHeaderVersion() == 0);
     if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) {
         sdkVersion = bcWrapper.getTargetAPI();
     }
@@ -323,7 +322,7 @@
 
     if (!s->runCompiler(rsc, resName, cacheDir, (uint8_t *)text, text_length)) {
         // Error during compile, destroy s and return null.
-        delete s;
+        ObjectBase::checkDelete(s);
         return NULL;
     }
 
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 544ab74..24cf504 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -98,7 +98,8 @@
 
 LOCAL_C_INCLUDES += \
 		external/zlib \
-		external/icu4c/common
+		external/icu4c/common \
+		bionic/libc/private
 
 LOCAL_LDLIBS += -lpthread
 
@@ -114,7 +115,10 @@
 
 ifeq ($(TARGET_OS),linux)
 include $(CLEAR_VARS)
-LOCAL_C_INCLUDES += external/zlib external/icu4c/common
+LOCAL_C_INCLUDES += \
+		external/zlib \
+		external/icu4c/common \
+		bionic/libc/private
 LOCAL_LDLIBS := -lrt -ldl -lpthread
 LOCAL_MODULE := libutils
 LOCAL_SRC_FILES := $(commonSources) BackupData.cpp BackupHelpers.cpp
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 15b83bb..3fa562e 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -221,7 +221,7 @@
 static bool assertIdmapHeader(const uint32_t* map, size_t sizeBytes)
 {
     if (sizeBytes < ResTable::IDMAP_HEADER_SIZE_BYTES) {
-        ALOGW("idmap assertion failed: size=%d bytes\n", sizeBytes);
+        ALOGW("idmap assertion failed: size=%d bytes\n", (int)sizeBytes);
         return false;
     }
     if (*map != htodl(IDMAP_MAGIC)) { // htodl: map data expected to be in correct endianess
@@ -250,7 +250,7 @@
         return UNKNOWN_ERROR;
     }
     if (typeCount > size) {
-        ALOGW("Resource ID map: number of types=%d exceeds size of map=%d\n", typeCount, size);
+        ALOGW("Resource ID map: number of types=%d exceeds size of map=%d\n", typeCount, (int)size);
         return UNKNOWN_ERROR;
     }
     const uint32_t typeOffset = map[type];
@@ -260,7 +260,7 @@
     }
     if (typeOffset + 1 > size) {
         ALOGW("Resource ID map: type offset=%d exceeds reasonable value, size of map=%d\n",
-             typeOffset, size);
+             typeOffset, (int)size);
         return UNKNOWN_ERROR;
     }
     const uint32_t entryCount = map[typeOffset];
@@ -271,7 +271,7 @@
     }
     const uint32_t index = typeOffset + 2 + entry - entryOffset;
     if (index > size) {
-        ALOGW("Resource ID map: entry index=%d exceeds size of map=%d\n", index, size);
+        ALOGW("Resource ID map: entry index=%d exceeds size of map=%d\n", index, (int)size);
         *outValue = 0;
         return NO_ERROR;
     }
@@ -659,6 +659,16 @@
     return NULL;
 }
 
+const String8 ResStringPool::string8ObjectAt(size_t idx) const
+{
+    size_t len;
+    const char *str = (const char*)string8At(idx, &len);
+    if (str != NULL) {
+        return String8(str);
+    }
+    return String8(stringAt(idx, &len));
+}
+
 const ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const
 {
     return styleAt(ref.index);
@@ -738,12 +748,25 @@
     return (mError == NO_ERROR) ? mHeader->stringCount : 0;
 }
 
-#ifndef HAVE_ANDROID_OS
+size_t ResStringPool::styleCount() const
+{
+    return (mError == NO_ERROR) ? mHeader->styleCount : 0;
+}
+
+size_t ResStringPool::bytes() const
+{
+    return (mError == NO_ERROR) ? mHeader->header.size : 0;
+}
+
+bool ResStringPool::isSorted() const
+{
+    return (mHeader->flags&ResStringPool_header::SORTED_FLAG)!=0;
+}
+
 bool ResStringPool::isUTF8() const
 {
     return (mHeader->flags&ResStringPool_header::UTF8_FLAG)!=0;
 }
-#endif
 
 // --------------------------------------------------------------------
 // --------------------------------------------------------------------
@@ -1367,6 +1390,873 @@
 // --------------------------------------------------------------------
 // --------------------------------------------------------------------
 
+void ResTable_config::copyFromDeviceNoSwap(const ResTable_config& o) {
+    const size_t size = dtohl(o.size);
+    if (size >= sizeof(ResTable_config)) {
+        *this = o;
+    } else {
+        memcpy(this, &o, size);
+        memset(((uint8_t*)this)+size, 0, sizeof(ResTable_config)-size);
+    }
+}
+
+void ResTable_config::copyFromDtoH(const ResTable_config& o) {
+    copyFromDeviceNoSwap(o);
+    size = sizeof(ResTable_config);
+    mcc = dtohs(mcc);
+    mnc = dtohs(mnc);
+    density = dtohs(density);
+    screenWidth = dtohs(screenWidth);
+    screenHeight = dtohs(screenHeight);
+    sdkVersion = dtohs(sdkVersion);
+    minorVersion = dtohs(minorVersion);
+    smallestScreenWidthDp = dtohs(smallestScreenWidthDp);
+    screenWidthDp = dtohs(screenWidthDp);
+    screenHeightDp = dtohs(screenHeightDp);
+}
+
+void ResTable_config::swapHtoD() {
+    size = htodl(size);
+    mcc = htods(mcc);
+    mnc = htods(mnc);
+    density = htods(density);
+    screenWidth = htods(screenWidth);
+    screenHeight = htods(screenHeight);
+    sdkVersion = htods(sdkVersion);
+    minorVersion = htods(minorVersion);
+    smallestScreenWidthDp = htods(smallestScreenWidthDp);
+    screenWidthDp = htods(screenWidthDp);
+    screenHeightDp = htods(screenHeightDp);
+}
+
+int ResTable_config::compare(const ResTable_config& o) const {
+    int32_t diff = (int32_t)(imsi - o.imsi);
+    if (diff != 0) return diff;
+    diff = (int32_t)(locale - o.locale);
+    if (diff != 0) return diff;
+    diff = (int32_t)(screenType - o.screenType);
+    if (diff != 0) return diff;
+    diff = (int32_t)(input - o.input);
+    if (diff != 0) return diff;
+    diff = (int32_t)(screenSize - o.screenSize);
+    if (diff != 0) return diff;
+    diff = (int32_t)(version - o.version);
+    if (diff != 0) return diff;
+    diff = (int32_t)(screenLayout - o.screenLayout);
+    if (diff != 0) return diff;
+    diff = (int32_t)(uiMode - o.uiMode);
+    if (diff != 0) return diff;
+    diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp);
+    if (diff != 0) return diff;
+    diff = (int32_t)(screenSizeDp - o.screenSizeDp);
+    return (int)diff;
+}
+
+int ResTable_config::compareLogical(const ResTable_config& o) const {
+    if (mcc != o.mcc) {
+        return mcc < o.mcc ? -1 : 1;
+    }
+    if (mnc != o.mnc) {
+        return mnc < o.mnc ? -1 : 1;
+    }
+    if (language[0] != o.language[0]) {
+        return language[0] < o.language[0] ? -1 : 1;
+    }
+    if (language[1] != o.language[1]) {
+        return language[1] < o.language[1] ? -1 : 1;
+    }
+    if (country[0] != o.country[0]) {
+        return country[0] < o.country[0] ? -1 : 1;
+    }
+    if (country[1] != o.country[1]) {
+        return country[1] < o.country[1] ? -1 : 1;
+    }
+    if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
+        return smallestScreenWidthDp < o.smallestScreenWidthDp ? -1 : 1;
+    }
+    if (screenWidthDp != o.screenWidthDp) {
+        return screenWidthDp < o.screenWidthDp ? -1 : 1;
+    }
+    if (screenHeightDp != o.screenHeightDp) {
+        return screenHeightDp < o.screenHeightDp ? -1 : 1;
+    }
+    if (screenWidth != o.screenWidth) {
+        return screenWidth < o.screenWidth ? -1 : 1;
+    }
+    if (screenHeight != o.screenHeight) {
+        return screenHeight < o.screenHeight ? -1 : 1;
+    }
+    if (density != o.density) {
+        return density < o.density ? -1 : 1;
+    }
+    if (orientation != o.orientation) {
+        return orientation < o.orientation ? -1 : 1;
+    }
+    if (touchscreen != o.touchscreen) {
+        return touchscreen < o.touchscreen ? -1 : 1;
+    }
+    if (input != o.input) {
+        return input < o.input ? -1 : 1;
+    }
+    if (screenLayout != o.screenLayout) {
+        return screenLayout < o.screenLayout ? -1 : 1;
+    }
+    if (uiMode != o.uiMode) {
+        return uiMode < o.uiMode ? -1 : 1;
+    }
+    if (version != o.version) {
+        return version < o.version ? -1 : 1;
+    }
+    return 0;
+}
+
+int ResTable_config::diff(const ResTable_config& o) const {
+    int diffs = 0;
+    if (mcc != o.mcc) diffs |= CONFIG_MCC;
+    if (mnc != o.mnc) diffs |= CONFIG_MNC;
+    if (locale != o.locale) diffs |= CONFIG_LOCALE;
+    if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION;
+    if (density != o.density) diffs |= CONFIG_DENSITY;
+    if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN;
+    if (((inputFlags^o.inputFlags)&(MASK_KEYSHIDDEN|MASK_NAVHIDDEN)) != 0)
+            diffs |= CONFIG_KEYBOARD_HIDDEN;
+    if (keyboard != o.keyboard) diffs |= CONFIG_KEYBOARD;
+    if (navigation != o.navigation) diffs |= CONFIG_NAVIGATION;
+    if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE;
+    if (version != o.version) diffs |= CONFIG_VERSION;
+    if (screenLayout != o.screenLayout) diffs |= CONFIG_SCREEN_LAYOUT;
+    if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE;
+    if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE;
+    if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE;
+    return diffs;
+}
+
+bool ResTable_config::isMoreSpecificThan(const ResTable_config& o) const {
+    // The order of the following tests defines the importance of one
+    // configuration parameter over another.  Those tests first are more
+    // important, trumping any values in those following them.
+    if (imsi || o.imsi) {
+        if (mcc != o.mcc) {
+            if (!mcc) return false;
+            if (!o.mcc) return true;
+        }
+
+        if (mnc != o.mnc) {
+            if (!mnc) return false;
+            if (!o.mnc) return true;
+        }
+    }
+
+    if (locale || o.locale) {
+        if (language[0] != o.language[0]) {
+            if (!language[0]) return false;
+            if (!o.language[0]) return true;
+        }
+
+        if (country[0] != o.country[0]) {
+            if (!country[0]) return false;
+            if (!o.country[0]) return true;
+        }
+    }
+
+    if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
+        if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
+            if (!smallestScreenWidthDp) return false;
+            if (!o.smallestScreenWidthDp) return true;
+        }
+    }
+
+    if (screenSizeDp || o.screenSizeDp) {
+        if (screenWidthDp != o.screenWidthDp) {
+            if (!screenWidthDp) return false;
+            if (!o.screenWidthDp) return true;
+        }
+
+        if (screenHeightDp != o.screenHeightDp) {
+            if (!screenHeightDp) return false;
+            if (!o.screenHeightDp) return true;
+        }
+    }
+
+    if (screenLayout || o.screenLayout) {
+        if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0) {
+            if (!(screenLayout & MASK_SCREENSIZE)) return false;
+            if (!(o.screenLayout & MASK_SCREENSIZE)) return true;
+        }
+        if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0) {
+            if (!(screenLayout & MASK_SCREENLONG)) return false;
+            if (!(o.screenLayout & MASK_SCREENLONG)) return true;
+        }
+    }
+
+    if (orientation != o.orientation) {
+        if (!orientation) return false;
+        if (!o.orientation) return true;
+    }
+
+    if (uiMode || o.uiMode) {
+        if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0) {
+            if (!(uiMode & MASK_UI_MODE_TYPE)) return false;
+            if (!(o.uiMode & MASK_UI_MODE_TYPE)) return true;
+        }
+        if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0) {
+            if (!(uiMode & MASK_UI_MODE_NIGHT)) return false;
+            if (!(o.uiMode & MASK_UI_MODE_NIGHT)) return true;
+        }
+    }
+
+    // density is never 'more specific'
+    // as the default just equals 160
+
+    if (touchscreen != o.touchscreen) {
+        if (!touchscreen) return false;
+        if (!o.touchscreen) return true;
+    }
+
+    if (input || o.input) {
+        if (((inputFlags^o.inputFlags) & MASK_KEYSHIDDEN) != 0) {
+            if (!(inputFlags & MASK_KEYSHIDDEN)) return false;
+            if (!(o.inputFlags & MASK_KEYSHIDDEN)) return true;
+        }
+
+        if (((inputFlags^o.inputFlags) & MASK_NAVHIDDEN) != 0) {
+            if (!(inputFlags & MASK_NAVHIDDEN)) return false;
+            if (!(o.inputFlags & MASK_NAVHIDDEN)) return true;
+        }
+
+        if (keyboard != o.keyboard) {
+            if (!keyboard) return false;
+            if (!o.keyboard) return true;
+        }
+
+        if (navigation != o.navigation) {
+            if (!navigation) return false;
+            if (!o.navigation) return true;
+        }
+    }
+
+    if (screenSize || o.screenSize) {
+        if (screenWidth != o.screenWidth) {
+            if (!screenWidth) return false;
+            if (!o.screenWidth) return true;
+        }
+
+        if (screenHeight != o.screenHeight) {
+            if (!screenHeight) return false;
+            if (!o.screenHeight) return true;
+        }
+    }
+
+    if (version || o.version) {
+        if (sdkVersion != o.sdkVersion) {
+            if (!sdkVersion) return false;
+            if (!o.sdkVersion) return true;
+        }
+
+        if (minorVersion != o.minorVersion) {
+            if (!minorVersion) return false;
+            if (!o.minorVersion) return true;
+        }
+    }
+    return false;
+}
+
+bool ResTable_config::isBetterThan(const ResTable_config& o,
+        const ResTable_config* requested) const {
+    if (requested) {
+        if (imsi || o.imsi) {
+            if ((mcc != o.mcc) && requested->mcc) {
+                return (mcc);
+            }
+
+            if ((mnc != o.mnc) && requested->mnc) {
+                return (mnc);
+            }
+        }
+
+        if (locale || o.locale) {
+            if ((language[0] != o.language[0]) && requested->language[0]) {
+                return (language[0]);
+            }
+
+            if ((country[0] != o.country[0]) && requested->country[0]) {
+                return (country[0]);
+            }
+        }
+
+        if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
+            // The configuration closest to the actual size is best.
+            // We assume that larger configs have already been filtered
+            // out at this point.  That means we just want the largest one.
+            return smallestScreenWidthDp >= o.smallestScreenWidthDp;
+        }
+
+        if (screenSizeDp || o.screenSizeDp) {
+            // "Better" is based on the sum of the difference between both
+            // width and height from the requested dimensions.  We are
+            // assuming the invalid configs (with smaller dimens) have
+            // already been filtered.  Note that if a particular dimension
+            // is unspecified, we will end up with a large value (the
+            // difference between 0 and the requested dimension), which is
+            // good since we will prefer a config that has specified a
+            // dimension value.
+            int myDelta = 0, otherDelta = 0;
+            if (requested->screenWidthDp) {
+                myDelta += requested->screenWidthDp - screenWidthDp;
+                otherDelta += requested->screenWidthDp - o.screenWidthDp;
+            }
+            if (requested->screenHeightDp) {
+                myDelta += requested->screenHeightDp - screenHeightDp;
+                otherDelta += requested->screenHeightDp - o.screenHeightDp;
+            }
+            //ALOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d",
+            //    screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp,
+            //    requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta);
+            return (myDelta <= otherDelta);
+        }
+
+        if (screenLayout || o.screenLayout) {
+            if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0
+                    && (requested->screenLayout & MASK_SCREENSIZE)) {
+                // A little backwards compatibility here: undefined is
+                // considered equivalent to normal.  But only if the
+                // requested size is at least normal; otherwise, small
+                // is better than the default.
+                int mySL = (screenLayout & MASK_SCREENSIZE);
+                int oSL = (o.screenLayout & MASK_SCREENSIZE);
+                int fixedMySL = mySL;
+                int fixedOSL = oSL;
+                if ((requested->screenLayout & MASK_SCREENSIZE) >= SCREENSIZE_NORMAL) {
+                    if (fixedMySL == 0) fixedMySL = SCREENSIZE_NORMAL;
+                    if (fixedOSL == 0) fixedOSL = SCREENSIZE_NORMAL;
+                }
+                // For screen size, the best match is the one that is
+                // closest to the requested screen size, but not over
+                // (the not over part is dealt with in match() below).
+                if (fixedMySL == fixedOSL) {
+                    // If the two are the same, but 'this' is actually
+                    // undefined, then the other is really a better match.
+                    if (mySL == 0) return false;
+                    return true;
+                }
+                return fixedMySL >= fixedOSL;
+            }
+            if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0
+                    && (requested->screenLayout & MASK_SCREENLONG)) {
+                return (screenLayout & MASK_SCREENLONG);
+            }
+        }
+
+        if ((orientation != o.orientation) && requested->orientation) {
+            return (orientation);
+        }
+
+        if (uiMode || o.uiMode) {
+            if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0
+                    && (requested->uiMode & MASK_UI_MODE_TYPE)) {
+                return (uiMode & MASK_UI_MODE_TYPE);
+            }
+            if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0
+                    && (requested->uiMode & MASK_UI_MODE_NIGHT)) {
+                return (uiMode & MASK_UI_MODE_NIGHT);
+            }
+        }
+
+        if (screenType || o.screenType) {
+            if (density != o.density) {
+                // density is tough.  Any density is potentially useful
+                // because the system will scale it.  Scaling down
+                // is generally better than scaling up.
+                // Default density counts as 160dpi (the system default)
+                // TODO - remove 160 constants
+                int h = (density?density:160);
+                int l = (o.density?o.density:160);
+                bool bImBigger = true;
+                if (l > h) {
+                    int t = h;
+                    h = l;
+                    l = t;
+                    bImBigger = false;
+                }
+
+                int reqValue = (requested->density?requested->density:160);
+                if (reqValue >= h) {
+                    // requested value higher than both l and h, give h
+                    return bImBigger;
+                }
+                if (l >= reqValue) {
+                    // requested value lower than both l and h, give l
+                    return !bImBigger;
+                }
+                // saying that scaling down is 2x better than up
+                if (((2 * l) - reqValue) * h > reqValue * reqValue) {
+                    return !bImBigger;
+                } else {
+                    return bImBigger;
+                }
+            }
+
+            if ((touchscreen != o.touchscreen) && requested->touchscreen) {
+                return (touchscreen);
+            }
+        }
+
+        if (input || o.input) {
+            const int keysHidden = inputFlags & MASK_KEYSHIDDEN;
+            const int oKeysHidden = o.inputFlags & MASK_KEYSHIDDEN;
+            if (keysHidden != oKeysHidden) {
+                const int reqKeysHidden =
+                        requested->inputFlags & MASK_KEYSHIDDEN;
+                if (reqKeysHidden) {
+
+                    if (!keysHidden) return false;
+                    if (!oKeysHidden) return true;
+                    // For compatibility, we count KEYSHIDDEN_NO as being
+                    // the same as KEYSHIDDEN_SOFT.  Here we disambiguate
+                    // these by making an exact match more specific.
+                    if (reqKeysHidden == keysHidden) return true;
+                    if (reqKeysHidden == oKeysHidden) return false;
+                }
+            }
+
+            const int navHidden = inputFlags & MASK_NAVHIDDEN;
+            const int oNavHidden = o.inputFlags & MASK_NAVHIDDEN;
+            if (navHidden != oNavHidden) {
+                const int reqNavHidden =
+                        requested->inputFlags & MASK_NAVHIDDEN;
+                if (reqNavHidden) {
+
+                    if (!navHidden) return false;
+                    if (!oNavHidden) return true;
+                }
+            }
+
+            if ((keyboard != o.keyboard) && requested->keyboard) {
+                return (keyboard);
+            }
+
+            if ((navigation != o.navigation) && requested->navigation) {
+                return (navigation);
+            }
+        }
+
+        if (screenSize || o.screenSize) {
+            // "Better" is based on the sum of the difference between both
+            // width and height from the requested dimensions.  We are
+            // assuming the invalid configs (with smaller sizes) have
+            // already been filtered.  Note that if a particular dimension
+            // is unspecified, we will end up with a large value (the
+            // difference between 0 and the requested dimension), which is
+            // good since we will prefer a config that has specified a
+            // size value.
+            int myDelta = 0, otherDelta = 0;
+            if (requested->screenWidth) {
+                myDelta += requested->screenWidth - screenWidth;
+                otherDelta += requested->screenWidth - o.screenWidth;
+            }
+            if (requested->screenHeight) {
+                myDelta += requested->screenHeight - screenHeight;
+                otherDelta += requested->screenHeight - o.screenHeight;
+            }
+            return (myDelta <= otherDelta);
+        }
+
+        if (version || o.version) {
+            if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) {
+                return (sdkVersion > o.sdkVersion);
+            }
+
+            if ((minorVersion != o.minorVersion) &&
+                    requested->minorVersion) {
+                return (minorVersion);
+            }
+        }
+
+        return false;
+    }
+    return isMoreSpecificThan(o);
+}
+
+bool ResTable_config::match(const ResTable_config& settings) const {
+    if (imsi != 0) {
+        if (mcc != 0 && mcc != settings.mcc) {
+            return false;
+        }
+        if (mnc != 0 && mnc != settings.mnc) {
+            return false;
+        }
+    }
+    if (locale != 0) {
+        if (language[0] != 0
+            && (language[0] != settings.language[0]
+                || language[1] != settings.language[1])) {
+            return false;
+        }
+        if (country[0] != 0
+            && (country[0] != settings.country[0]
+                || country[1] != settings.country[1])) {
+            return false;
+        }
+    }
+    if (screenConfig != 0) {
+        const int screenSize = screenLayout&MASK_SCREENSIZE;
+        const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE;
+        // Any screen sizes for larger screens than the setting do not
+        // match.
+        if (screenSize != 0 && screenSize > setScreenSize) {
+            return false;
+        }
+
+        const int screenLong = screenLayout&MASK_SCREENLONG;
+        const int setScreenLong = settings.screenLayout&MASK_SCREENLONG;
+        if (screenLong != 0 && screenLong != setScreenLong) {
+            return false;
+        }
+
+        const int uiModeType = uiMode&MASK_UI_MODE_TYPE;
+        const int setUiModeType = settings.uiMode&MASK_UI_MODE_TYPE;
+        if (uiModeType != 0 && uiModeType != setUiModeType) {
+            return false;
+        }
+
+        const int uiModeNight = uiMode&MASK_UI_MODE_NIGHT;
+        const int setUiModeNight = settings.uiMode&MASK_UI_MODE_NIGHT;
+        if (uiModeNight != 0 && uiModeNight != setUiModeNight) {
+            return false;
+        }
+
+        if (smallestScreenWidthDp != 0
+                && smallestScreenWidthDp > settings.smallestScreenWidthDp) {
+            return false;
+        }
+    }
+    if (screenSizeDp != 0) {
+        if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) {
+            //ALOGI("Filtering out width %d in requested %d", screenWidthDp, settings.screenWidthDp);
+            return false;
+        }
+        if (screenHeightDp != 0 && screenHeightDp > settings.screenHeightDp) {
+            //ALOGI("Filtering out height %d in requested %d", screenHeightDp, settings.screenHeightDp);
+            return false;
+        }
+    }
+    if (screenType != 0) {
+        if (orientation != 0 && orientation != settings.orientation) {
+            return false;
+        }
+        // density always matches - we can scale it.  See isBetterThan
+        if (touchscreen != 0 && touchscreen != settings.touchscreen) {
+            return false;
+        }
+    }
+    if (input != 0) {
+        const int keysHidden = inputFlags&MASK_KEYSHIDDEN;
+        const int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN;
+        if (keysHidden != 0 && keysHidden != setKeysHidden) {
+            // For compatibility, we count a request for KEYSHIDDEN_NO as also
+            // matching the more recent KEYSHIDDEN_SOFT.  Basically
+            // KEYSHIDDEN_NO means there is some kind of keyboard available.
+            //ALOGI("Matching keysHidden: have=%d, config=%d\n", keysHidden, setKeysHidden);
+            if (keysHidden != KEYSHIDDEN_NO || setKeysHidden != KEYSHIDDEN_SOFT) {
+                //ALOGI("No match!");
+                return false;
+            }
+        }
+        const int navHidden = inputFlags&MASK_NAVHIDDEN;
+        const int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN;
+        if (navHidden != 0 && navHidden != setNavHidden) {
+            return false;
+        }
+        if (keyboard != 0 && keyboard != settings.keyboard) {
+            return false;
+        }
+        if (navigation != 0 && navigation != settings.navigation) {
+            return false;
+        }
+    }
+    if (screenSize != 0) {
+        if (screenWidth != 0 && screenWidth > settings.screenWidth) {
+            return false;
+        }
+        if (screenHeight != 0 && screenHeight > settings.screenHeight) {
+            return false;
+        }
+    }
+    if (version != 0) {
+        if (sdkVersion != 0 && sdkVersion > settings.sdkVersion) {
+            return false;
+        }
+        if (minorVersion != 0 && minorVersion != settings.minorVersion) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void ResTable_config::getLocale(char str[6]) const {
+    memset(str, 0, 6);
+    if (language[0]) {
+        str[0] = language[0];
+        str[1] = language[1];
+        if (country[0]) {
+            str[2] = '_';
+            str[3] = country[0];
+            str[4] = country[1];
+        }
+    }
+}
+
+String8 ResTable_config::toString() const {
+    String8 res;
+
+    if (mcc != 0) {
+        if (res.size() > 0) res.append("-");
+        res.appendFormat("%dmcc", dtohs(mcc));
+    }
+    if (mnc != 0) {
+        if (res.size() > 0) res.append("-");
+        res.appendFormat("%dmnc", dtohs(mnc));
+    }
+    if (language[0] != 0) {
+        if (res.size() > 0) res.append("-");
+        res.append(language, 2);
+    }
+    if (country[0] != 0) {
+        if (res.size() > 0) res.append("-");
+        res.append(country, 2);
+    }
+    if (smallestScreenWidthDp != 0) {
+        if (res.size() > 0) res.append("-");
+        res.appendFormat("sw%ddp", dtohs(smallestScreenWidthDp));
+    }
+    if (screenWidthDp != 0) {
+        if (res.size() > 0) res.append("-");
+        res.appendFormat("w%ddp", dtohs(screenWidthDp));
+    }
+    if (screenHeightDp != 0) {
+        if (res.size() > 0) res.append("-");
+        res.appendFormat("h%ddp", dtohs(screenHeightDp));
+    }
+    if ((screenLayout&MASK_SCREENSIZE) != SCREENSIZE_ANY) {
+        if (res.size() > 0) res.append("-");
+        switch (screenLayout&ResTable_config::MASK_SCREENSIZE) {
+            case ResTable_config::SCREENSIZE_SMALL:
+                res.append("small");
+                break;
+            case ResTable_config::SCREENSIZE_NORMAL:
+                res.append("normal");
+                break;
+            case ResTable_config::SCREENSIZE_LARGE:
+                res.append("large");
+                break;
+            case ResTable_config::SCREENSIZE_XLARGE:
+                res.append("xlarge");
+                break;
+            default:
+                res.appendFormat("screenLayoutSize=%d",
+                        dtohs(screenLayout&ResTable_config::MASK_SCREENSIZE));
+                break;
+        }
+    }
+    if ((screenLayout&MASK_SCREENLONG) != 0) {
+        if (res.size() > 0) res.append("-");
+        switch (screenLayout&ResTable_config::MASK_SCREENLONG) {
+            case ResTable_config::SCREENLONG_NO:
+                res.append("notlong");
+                break;
+            case ResTable_config::SCREENLONG_YES:
+                res.append("long");
+                break;
+            default:
+                res.appendFormat("screenLayoutLong=%d",
+                        dtohs(screenLayout&ResTable_config::MASK_SCREENLONG));
+                break;
+        }
+    }
+    if (orientation != ORIENTATION_ANY) {
+        if (res.size() > 0) res.append("-");
+        switch (orientation) {
+            case ResTable_config::ORIENTATION_PORT:
+                res.append("port");
+                break;
+            case ResTable_config::ORIENTATION_LAND:
+                res.append("land");
+                break;
+            case ResTable_config::ORIENTATION_SQUARE:
+                res.append("square");
+                break;
+            default:
+                res.appendFormat("orientation=%d", dtohs(orientation));
+                break;
+        }
+    }
+    if ((uiMode&MASK_UI_MODE_TYPE) != UI_MODE_TYPE_ANY) {
+        if (res.size() > 0) res.append("-");
+        switch (uiMode&ResTable_config::MASK_UI_MODE_TYPE) {
+            case ResTable_config::UI_MODE_TYPE_DESK:
+                res.append("desk");
+                break;
+            case ResTable_config::UI_MODE_TYPE_CAR:
+                res.append("car");
+                break;
+            case ResTable_config::UI_MODE_TYPE_TELEVISION:
+                res.append("television");
+                break;
+            case ResTable_config::UI_MODE_TYPE_APPLIANCE:
+                res.append("appliance");
+                break;
+            default:
+                res.appendFormat("uiModeType=%d",
+                        dtohs(screenLayout&ResTable_config::MASK_UI_MODE_TYPE));
+                break;
+        }
+    }
+    if ((uiMode&MASK_UI_MODE_NIGHT) != 0) {
+        if (res.size() > 0) res.append("-");
+        switch (uiMode&ResTable_config::MASK_UI_MODE_NIGHT) {
+            case ResTable_config::UI_MODE_NIGHT_NO:
+                res.append("notnight");
+                break;
+            case ResTable_config::UI_MODE_NIGHT_YES:
+                res.append("night");
+                break;
+            default:
+                res.appendFormat("uiModeNight=%d",
+                        dtohs(uiMode&MASK_UI_MODE_NIGHT));
+                break;
+        }
+    }
+    if (density != DENSITY_DEFAULT) {
+        if (res.size() > 0) res.append("-");
+        switch (density) {
+            case ResTable_config::DENSITY_LOW:
+                res.append("ldpi");
+                break;
+            case ResTable_config::DENSITY_MEDIUM:
+                res.append("mdpi");
+                break;
+            case ResTable_config::DENSITY_TV:
+                res.append("tvdpi");
+                break;
+            case ResTable_config::DENSITY_HIGH:
+                res.append("hdpi");
+                break;
+            case ResTable_config::DENSITY_XHIGH:
+                res.append("xhdpi");
+                break;
+            case ResTable_config::DENSITY_XXHIGH:
+                res.append("xxhdpi");
+                break;
+            case ResTable_config::DENSITY_NONE:
+                res.append("nodpi");
+                break;
+            default:
+                res.appendFormat("density=%d", dtohs(density));
+                break;
+        }
+    }
+    if (touchscreen != TOUCHSCREEN_ANY) {
+        if (res.size() > 0) res.append("-");
+        switch (touchscreen) {
+            case ResTable_config::TOUCHSCREEN_NOTOUCH:
+                res.append("notouch");
+                break;
+            case ResTable_config::TOUCHSCREEN_FINGER:
+                res.append("finger");
+                break;
+            case ResTable_config::TOUCHSCREEN_STYLUS:
+                res.append("stylus");
+                break;
+            default:
+                res.appendFormat("touchscreen=%d", dtohs(touchscreen));
+                break;
+        }
+    }
+    if (keyboard != KEYBOARD_ANY) {
+        if (res.size() > 0) res.append("-");
+        switch (keyboard) {
+            case ResTable_config::KEYBOARD_NOKEYS:
+                res.append("nokeys");
+                break;
+            case ResTable_config::KEYBOARD_QWERTY:
+                res.append("qwerty");
+                break;
+            case ResTable_config::KEYBOARD_12KEY:
+                res.append("12key");
+                break;
+            default:
+                res.appendFormat("keyboard=%d", dtohs(keyboard));
+                break;
+        }
+    }
+    if ((inputFlags&MASK_KEYSHIDDEN) != 0) {
+        if (res.size() > 0) res.append("-");
+        switch (inputFlags&MASK_KEYSHIDDEN) {
+            case ResTable_config::KEYSHIDDEN_NO:
+                res.append("keysexposed");
+                break;
+            case ResTable_config::KEYSHIDDEN_YES:
+                res.append("keyshidden");
+                break;
+            case ResTable_config::KEYSHIDDEN_SOFT:
+                res.append("keyssoft");
+                break;
+        }
+    }
+    if (navigation != NAVIGATION_ANY) {
+        if (res.size() > 0) res.append("-");
+        switch (navigation) {
+            case ResTable_config::NAVIGATION_NONAV:
+                res.append("nonav");
+                break;
+            case ResTable_config::NAVIGATION_DPAD:
+                res.append("dpad");
+                break;
+            case ResTable_config::NAVIGATION_TRACKBALL:
+                res.append("trackball");
+                break;
+            case ResTable_config::NAVIGATION_WHEEL:
+                res.append("wheel");
+                break;
+            default:
+                res.appendFormat("navigation=%d", dtohs(navigation));
+                break;
+        }
+    }
+    if ((inputFlags&MASK_NAVHIDDEN) != 0) {
+        if (res.size() > 0) res.append("-");
+        switch (inputFlags&MASK_NAVHIDDEN) {
+            case ResTable_config::NAVHIDDEN_NO:
+                res.append("navsexposed");
+                break;
+            case ResTable_config::NAVHIDDEN_YES:
+                res.append("navhidden");
+                break;
+            default:
+                res.appendFormat("inputFlagsNavHidden=%d",
+                        dtohs(inputFlags&MASK_NAVHIDDEN));
+                break;
+        }
+    }
+    if (screenSize != 0) {
+        if (res.size() > 0) res.append("-");
+        res.appendFormat("%dx%d", dtohs(screenWidth), dtohs(screenHeight));
+    }
+    if (version != 0) {
+        if (res.size() > 0) res.append("-");
+        res.appendFormat("v%d", dtohs(sdkVersion));
+        if (minorVersion != 0) {
+            res.appendFormat(".%d", dtohs(minorVersion));
+        }
+    }
+
+    return res;
+}
+
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+
 struct ResTable::Header
 {
     Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL),
@@ -3953,43 +4843,9 @@
         ResTable_config thisConfig;
         thisConfig.copyFromDtoH(thisType->config);
 
-        TABLE_GETENTRY(LOGI("Match entry 0x%x in type 0x%x (sz 0x%x): imsi:%d/%d=%d/%d "
-                            "lang:%c%c=%c%c cnt:%c%c=%c%c orien:%d=%d touch:%d=%d "
-                            "density:%d=%d key:%d=%d inp:%d=%d nav:%d=%d w:%d=%d h:%d=%d "
-                            "swdp:%d=%d wdp:%d=%d hdp:%d=%d\n",
+        TABLE_GETENTRY(LOGI("Match entry 0x%x in type 0x%x (sz 0x%x): %s\n",
                            entryIndex, typeIndex+1, dtohl(thisType->config.size),
-                           thisConfig.mcc, thisConfig.mnc,
-                           config ? config->mcc : 0, config ? config->mnc : 0,
-                           thisConfig.language[0] ? thisConfig.language[0] : '-',
-                           thisConfig.language[1] ? thisConfig.language[1] : '-',
-                           config && config->language[0] ? config->language[0] : '-',
-                           config && config->language[1] ? config->language[1] : '-',
-                           thisConfig.country[0] ? thisConfig.country[0] : '-',
-                           thisConfig.country[1] ? thisConfig.country[1] : '-',
-                           config && config->country[0] ? config->country[0] : '-',
-                           config && config->country[1] ? config->country[1] : '-',
-                           thisConfig.orientation,
-                           config ? config->orientation : 0,
-                           thisConfig.touchscreen,
-                           config ? config->touchscreen : 0,
-                           thisConfig.density,
-                           config ? config->density : 0,
-                           thisConfig.keyboard,
-                           config ? config->keyboard : 0,
-                           thisConfig.inputFlags,
-                           config ? config->inputFlags : 0,
-                           thisConfig.navigation,
-                           config ? config->navigation : 0,
-                           thisConfig.screenWidth,
-                           config ? config->screenWidth : 0,
-                           thisConfig.screenHeight,
-                           config ? config->screenHeight : 0,
-                           thisConfig.smallestScreenWidthDp,
-                           config ? config->smallestScreenWidthDp : 0,
-                           thisConfig.screenWidthDp,
-                           config ? config->screenWidthDp : 0,
-                           thisConfig.screenHeightDp,
-                           config ? config->screenHeightDp : 0));
+                           thisConfig.toString().string()));
         
         // Check to make sure this one is valid for the current parameters.
         if (config && !thisConfig.match(*config)) {
@@ -4273,26 +5129,8 @@
             TABLE_GETENTRY(
                 ResTable_config thisConfig;
                 thisConfig.copyFromDtoH(type->config);
-                ALOGI("Adding config to type %d: imsi:%d/%d lang:%c%c cnt:%c%c "
-                     "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d "
-                     "swdp:%d wdp:%d hdp:%d\n",
-                      type->id,
-                      thisConfig.mcc, thisConfig.mnc,
-                      thisConfig.language[0] ? thisConfig.language[0] : '-',
-                      thisConfig.language[1] ? thisConfig.language[1] : '-',
-                      thisConfig.country[0] ? thisConfig.country[0] : '-',
-                      thisConfig.country[1] ? thisConfig.country[1] : '-',
-                      thisConfig.orientation,
-                      thisConfig.touchscreen,
-                      thisConfig.density,
-                      thisConfig.keyboard,
-                      thisConfig.inputFlags,
-                      thisConfig.navigation,
-                      thisConfig.screenWidth,
-                      thisConfig.screenHeight,
-                      thisConfig.smallestScreenWidthDp,
-                      thisConfig.screenWidthDp,
-                      thisConfig.screenHeightDp));
+                ALOGI("Adding config to type %d: %s\n",
+                      type->id, thisConfig.toString().string()));
             t->configs.add(type);
         } else {
             status_t err = validate_chunk(chunk, sizeof(ResChunk_header),
@@ -4622,186 +5460,9 @@
                         printf("      NON-INTEGER ResTable_type ADDRESS: %p\n", type);
                         continue;
                     }
-                    char density[16];
-                    uint16_t dval = dtohs(type->config.density);
-                    if (dval == ResTable_config::DENSITY_DEFAULT) {
-                        strcpy(density, "def");
-                    } else if (dval == ResTable_config::DENSITY_NONE) {
-                        strcpy(density, "no");
-                    } else {
-                        sprintf(density, "%d", (int)dval);
-                    }
-                    printf("      config %d", (int)configIndex);
-                    if (type->config.mcc != 0) {
-                        printf(" mcc=%d", dtohs(type->config.mcc));
-                    }
-                    if (type->config.mnc != 0) {
-                        printf(" mnc=%d", dtohs(type->config.mnc));
-                    }
-                    if (type->config.locale != 0) {
-                        printf(" lang=%c%c cnt=%c%c",
-                               type->config.language[0] ? type->config.language[0] : '-',
-                               type->config.language[1] ? type->config.language[1] : '-',
-                               type->config.country[0] ? type->config.country[0] : '-',
-                               type->config.country[1] ? type->config.country[1] : '-');
-                    }
-                    if (type->config.screenLayout != 0) {
-                        printf(" sz=%d",
-                                type->config.screenLayout&ResTable_config::MASK_SCREENSIZE);
-                        switch (type->config.screenLayout&ResTable_config::MASK_SCREENSIZE) {
-                            case ResTable_config::SCREENSIZE_SMALL:
-                                printf(" (small)");
-                                break;
-                            case ResTable_config::SCREENSIZE_NORMAL:
-                                printf(" (normal)");
-                                break;
-                            case ResTable_config::SCREENSIZE_LARGE:
-                                printf(" (large)");
-                                break;
-                            case ResTable_config::SCREENSIZE_XLARGE:
-                                printf(" (xlarge)");
-                                break;
-                        }
-                        printf(" lng=%d",
-                                type->config.screenLayout&ResTable_config::MASK_SCREENLONG);
-                        switch (type->config.screenLayout&ResTable_config::MASK_SCREENLONG) {
-                            case ResTable_config::SCREENLONG_NO:
-                                printf(" (notlong)");
-                                break;
-                            case ResTable_config::SCREENLONG_YES:
-                                printf(" (long)");
-                                break;
-                        }
-                    }
-                    if (type->config.orientation != 0) {
-                        printf(" orient=%d", type->config.orientation);
-                        switch (type->config.orientation) {
-                            case ResTable_config::ORIENTATION_PORT:
-                                printf(" (port)");
-                                break;
-                            case ResTable_config::ORIENTATION_LAND:
-                                printf(" (land)");
-                                break;
-                            case ResTable_config::ORIENTATION_SQUARE:
-                                printf(" (square)");
-                                break;
-                        }
-                    }
-                    if (type->config.uiMode != 0) {
-                        printf(" type=%d",
-                                type->config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
-                        switch (type->config.uiMode&ResTable_config::MASK_UI_MODE_TYPE) {
-                            case ResTable_config::UI_MODE_TYPE_NORMAL:
-                                printf(" (normal)");
-                                break;
-                            case ResTable_config::UI_MODE_TYPE_CAR:
-                                printf(" (car)");
-                                break;
-                        }
-                        printf(" night=%d",
-                                type->config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
-                        switch (type->config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT) {
-                            case ResTable_config::UI_MODE_NIGHT_NO:
-                                printf(" (no)");
-                                break;
-                            case ResTable_config::UI_MODE_NIGHT_YES:
-                                printf(" (yes)");
-                                break;
-                        }
-                    }
-                    if (dval != 0) {
-                        printf(" density=%s", density);
-                    }
-                    if (type->config.touchscreen != 0) {
-                        printf(" touch=%d", type->config.touchscreen);
-                        switch (type->config.touchscreen) {
-                            case ResTable_config::TOUCHSCREEN_NOTOUCH:
-                                printf(" (notouch)");
-                                break;
-                            case ResTable_config::TOUCHSCREEN_STYLUS:
-                                printf(" (stylus)");
-                                break;
-                            case ResTable_config::TOUCHSCREEN_FINGER:
-                                printf(" (finger)");
-                                break;
-                        }
-                    }
-                    if (type->config.inputFlags != 0) {
-                        printf(" keyhid=%d", type->config.inputFlags&ResTable_config::MASK_KEYSHIDDEN);
-                        switch (type->config.inputFlags&ResTable_config::MASK_KEYSHIDDEN) {
-                            case ResTable_config::KEYSHIDDEN_NO:
-                                printf(" (no)");
-                                break;
-                            case ResTable_config::KEYSHIDDEN_YES:
-                                printf(" (yes)");
-                                break;
-                            case ResTable_config::KEYSHIDDEN_SOFT:
-                                printf(" (soft)");
-                                break;
-                        }
-                        printf(" navhid=%d", type->config.inputFlags&ResTable_config::MASK_NAVHIDDEN);
-                        switch (type->config.inputFlags&ResTable_config::MASK_NAVHIDDEN) {
-                            case ResTable_config::NAVHIDDEN_NO:
-                                printf(" (no)");
-                                break;
-                            case ResTable_config::NAVHIDDEN_YES:
-                                printf(" (yes)");
-                                break;
-                        }
-                    }
-                    if (type->config.keyboard != 0) {
-                        printf(" kbd=%d", type->config.keyboard);
-                        switch (type->config.keyboard) {
-                            case ResTable_config::KEYBOARD_NOKEYS:
-                                printf(" (nokeys)");
-                                break;
-                            case ResTable_config::KEYBOARD_QWERTY:
-                                printf(" (qwerty)");
-                                break;
-                            case ResTable_config::KEYBOARD_12KEY:
-                                printf(" (12key)");
-                                break;
-                        }
-                    }
-                    if (type->config.navigation != 0) {
-                        printf(" nav=%d", type->config.navigation);
-                        switch (type->config.navigation) {
-                            case ResTable_config::NAVIGATION_NONAV:
-                                printf(" (nonav)");
-                                break;
-                            case ResTable_config::NAVIGATION_DPAD:
-                                printf(" (dpad)");
-                                break;
-                            case ResTable_config::NAVIGATION_TRACKBALL:
-                                printf(" (trackball)");
-                                break;
-                            case ResTable_config::NAVIGATION_WHEEL:
-                                printf(" (wheel)");
-                                break;
-                        }
-                    }
-                    if (type->config.screenWidth != 0) {
-                        printf(" w=%d", dtohs(type->config.screenWidth));
-                    }
-                    if (type->config.screenHeight != 0) {
-                        printf(" h=%d", dtohs(type->config.screenHeight));
-                    }
-                    if (type->config.smallestScreenWidthDp != 0) {
-                        printf(" swdp=%d", dtohs(type->config.smallestScreenWidthDp));
-                    }
-                    if (type->config.screenWidthDp != 0) {
-                        printf(" wdp=%d", dtohs(type->config.screenWidthDp));
-                    }
-                    if (type->config.screenHeightDp != 0) {
-                        printf(" hdp=%d", dtohs(type->config.screenHeightDp));
-                    }
-                    if (type->config.sdkVersion != 0) {
-                        printf(" sdk=%d", dtohs(type->config.sdkVersion));
-                    }
-                    if (type->config.minorVersion != 0) {
-                        printf(" mver=%d", dtohs(type->config.minorVersion));
-                    }
-                    printf("\n");
+                    String8 configStr = type->config.toString();
+                    printf("      config %s:\n", configStr.size() > 0
+                            ? configStr.string() : "(default)");
                     size_t entryCount = dtohl(type->entryCount);
                     uint32_t entriesStart = dtohl(type->entriesStart);
                     if ((entriesStart&0x3) != 0) {
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index e343c62..ab207f5 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -34,6 +34,9 @@
 # include <pthread.h>
 # include <sched.h>
 # include <sys/resource.h>
+#ifdef HAVE_ANDROID_OS
+# include <bionic_pthread.h>
+#endif
 #elif defined(HAVE_WIN32_THREADS)
 # include <windows.h>
 # include <stdint.h>
@@ -86,7 +89,7 @@
     char *          threadName;
 
     // we use this trampoline when we need to set the priority with
-    // nice/setpriority.
+    // nice/setpriority, and name with prctl.
     static int trampoline(const thread_data_t* t) {
         thread_func_t f = t->entryFunction;
         void* u = t->userData;
@@ -141,8 +144,13 @@
 
 #ifdef HAVE_ANDROID_OS  /* valgrind is rejecting RT-priority create reqs */
     if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) {
-        // We could avoid the trampoline if there was a way to get to the
-        // android_thread_id_t (pid) from pthread_t
+        // Now that the pthread_t has a method to find the associated
+        // android_thread_id_t (pid) from pthread_t, it would be possible to avoid
+        // this trampoline in some cases as the parent could set the properties
+        // for the child.  However, there would be a race condition because the
+        // child becomes ready immediately, and it doesn't work for the name.
+        // prctl(PR_SET_NAME) only works for self; prctl(PR_SET_THREAD_NAME) was
+        // proposed but not yet accepted.
         thread_data_t* t = new thread_data_t;
         t->priority = threadPriority;
         t->threadName = threadName ? strdup(threadName) : NULL;
@@ -178,6 +186,13 @@
     return 1;
 }
 
+#ifdef HAVE_ANDROID_OS
+static pthread_t android_thread_id_t_to_pthread(android_thread_id_t thread)
+{
+    return (pthread_t) thread;
+}
+#endif
+
 android_thread_id_t androidGetThreadId()
 {
     return (android_thread_id_t)pthread_self();
@@ -909,6 +924,23 @@
     return mStatus;
 }
 
+#ifdef HAVE_ANDROID_OS
+pid_t Thread::getTid() const
+{
+    // mTid is not defined until the child initializes it, and the caller may need it earlier
+    Mutex::Autolock _l(mLock);
+    pid_t tid;
+    if (mRunning) {
+        pthread_t pthread = android_thread_id_t_to_pthread(mThread);
+        tid = __pthread_gettid(pthread);
+    } else {
+        ALOGW("Thread (this=%p): getTid() is undefined before run()", this);
+        tid = -1;
+    }
+    return tid;
+}
+#endif
+
 bool Thread::exitPending() const
 {
     Mutex::Autolock _l(mLock);
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index a720c0a..85d99c1 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -204,18 +204,24 @@
         /** MPEG4 media file format*/
         public static final int MPEG_4 = 2;
 
-        /** The following formats are audio only .aac or .amr formats **/
-        /** @deprecated  Deprecated in favor of AMR_NB */
-        /** Deprecated in favor of MediaRecorder.OutputFormat.AMR_NB */
-        /** AMR NB file format */
+        /** The following formats are audio only .aac or .amr formats */
+
+        /**
+         * AMR NB file format
+         * @deprecated  Deprecated in favor of MediaRecorder.OutputFormat.AMR_NB
+         */
         public static final int RAW_AMR = 3;
+
         /** AMR NB file format */
         public static final int AMR_NB = 3;
+
         /** AMR WB file format */
         public static final int AMR_WB = 4;
+
         /** @hide AAC ADIF file format */
         public static final int AAC_ADIF = 5;
-        /** @hide AAC ADTS file format */
+
+        /** AAC ADTS file format */
         public static final int AAC_ADTS = 6;
 
         /** @hide Stream over a socket, limited to a single stream */
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index cfd6eea..1c13fff 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -35,6 +35,7 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.provider.MediaStore;
+import android.provider.MediaStore.Files.FileColumns;
 import android.provider.Settings;
 import android.provider.MediaStore.Audio;
 import android.provider.MediaStore.Files;
@@ -58,6 +59,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.Locale;
 
 /**
  * Internal service helper that no-one should use directly.
@@ -312,10 +314,8 @@
 
     private final String mExternalStoragePath;
 
-    // WARNING: Bulk inserts sounded like a great idea and gave us a good performance improvement,
-    // but unfortunately it also introduced a number of bugs. All the known bugs were fixed,
-    // but we need more testing before enabling.
-    private static final boolean ENABLE_BULK_INSERTS = false;
+    /** whether to use bulk inserts or individual inserts for each item */
+    private static final boolean ENABLE_BULK_INSERTS = true;
 
     // used when scanning the image database so we know whether we have to prune
     // old thumbnail files
@@ -946,6 +946,22 @@
                 // path should never change, and we want to avoid replacing mixed cased paths
                 // with squashed lower case paths
                 values.remove(MediaStore.MediaColumns.DATA);
+
+                int mediaType = 0;
+                if (!MediaScanner.isNoMediaPath(entry.mPath)) {
+                    int fileType = MediaFile.getFileTypeForMimeType(mMimeType);
+                    if (MediaFile.isAudioFileType(fileType)) {
+                        mediaType = FileColumns.MEDIA_TYPE_AUDIO;
+                    } else if (MediaFile.isVideoFileType(fileType)) {
+                        mediaType = FileColumns.MEDIA_TYPE_VIDEO;
+                    } else if (MediaFile.isImageFileType(fileType)) {
+                        mediaType = FileColumns.MEDIA_TYPE_IMAGE;
+                    } else if (MediaFile.isPlayListFileType(fileType)) {
+                        mediaType = FileColumns.MEDIA_TYPE_PLAYLIST;
+                    }
+                    values.put(FileColumns.MEDIA_TYPE, mediaType);
+                }
+
                 mMediaProvider.update(result, values, null, null);
             }
 
@@ -1180,6 +1196,10 @@
                     mMediaProvider.delete(ContentUris.withAppendedId(mFilesUri, entry.mRowId),
                             null, null);
                     iterator.remove();
+                    if (entry.mPath.toLowerCase(Locale.US).endsWith("/.nomedia")) {
+                        File f = new File(path);
+                        mMediaProvider.call(MediaStore.UNHIDE_CALL, f.getParent(), null);
+                    }
                 }
             }
         }
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 268c9fc..18aa4b3 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -752,6 +752,29 @@
             return MtpConstants.RESPONSE_GENERAL_ERROR;
         }
 
+        // check if nomedia status changed
+        if (newFile.isDirectory()) {
+            // for directories, check if renamed from something hidden to something non-hidden
+            if (oldFile.getName().startsWith(".") && !newPath.startsWith(".")) {
+                // directory was unhidden
+                try {
+                    mMediaProvider.call(MediaStore.UNHIDE_CALL, newPath, null);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "failed to unhide/rescan for " + newPath);
+                }
+            }
+        } else {
+            // for files, check if renamed from .nomedia to something else
+            if (oldFile.getName().toLowerCase(Locale.US).equals(".nomedia")
+                    && !newPath.toLowerCase(Locale.US).equals(".nomedia")) {
+                try {
+                    mMediaProvider.call(MediaStore.UNHIDE_CALL, oldFile.getParent(), null);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "failed to unhide/rescan for " + newPath);
+                }
+            }
+        }
+
         return MtpConstants.RESPONSE_OK;
     }
 
@@ -915,6 +938,15 @@
 
             Uri uri = Files.getMtpObjectsUri(mVolumeName, handle);
             if (mMediaProvider.delete(uri, null, null) > 0) {
+                if (format != MtpConstants.FORMAT_ASSOCIATION
+                        && path.toLowerCase(Locale.US).endsWith("/.nomedia")) {
+                    try {
+                        String parentPath = path.substring(0, path.lastIndexOf("/"));
+                        mMediaProvider.call(MediaStore.UNHIDE_CALL, parentPath, null);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "failed to unhide/rescan for " + path);
+                    }
+                }
                 return MtpConstants.RESPONSE_OK;
             } else {
                 return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index ee96a95..23cc0e2 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -28,7 +28,11 @@
     libcamera_client \
     libmtp \
     libusbhost \
-    libexif
+    libexif \
+    libstagefright_amrnb_common \
+
+LOCAL_STATIC_LIBRARIES := \
+    libstagefright_amrnbenc
 
 LOCAL_C_INCLUDES += \
     external/jhead \
diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk
index 77d40b6..7f7c7e1 100755
--- a/media/libeffects/preprocessing/Android.mk
+++ b/media/libeffects/preprocessing/Android.mk
@@ -13,7 +13,7 @@
 LOCAL_C_INCLUDES += \
     external/webrtc/src \
     external/webrtc/src/modules/interface \
-    external/webrtc/src/modules/audio_processing/main/interface \
+    external/webrtc/src/modules/audio_processing/interface \
     system/media/audio_effects/include
 
 LOCAL_C_INCLUDES += $(call include-path-for, speex)
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index e988e06..9fd6764 100755
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -24,8 +24,8 @@
 #include <audio_effects/effect_aec.h>
 #include <audio_effects/effect_agc.h>
 #include <audio_effects/effect_ns.h>
-#include "modules/interface/module_common_types.h"
-#include "modules/audio_processing/main/interface/audio_processing.h"
+#include <module_common_types.h>
+#include <audio_processing.h>
 #include "speex/speex_resampler.h"
 
 
@@ -220,8 +220,8 @@
 // Automatic Gain Control (AGC)
 //------------------------------------------------------------------------------
 
-static const int kAgcDefaultTargetLevel = 0;
-static const int kAgcDefaultCompGain = 90;
+static const int kAgcDefaultTargetLevel = 3;
+static const int kAgcDefaultCompGain = 9;
 static const bool kAgcDefaultLimiter = true;
 
 int  AgcInit (preproc_effect_t *effect)
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 124032b..df5017b 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -35,7 +35,8 @@
 sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
 audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
 // Cached values
-DefaultKeyedVector<int, audio_io_handle_t> AudioSystem::gStreamOutputMap(0);
+
+DefaultKeyedVector<audio_stream_type_t, audio_io_handle_t> AudioSystem::gStreamOutputMap(0);
 DefaultKeyedVector<audio_io_handle_t, AudioSystem::OutputDescriptor *> AudioSystem::gOutputs(0);
 
 // Cached values for recording queries, all protected by gLock
@@ -404,7 +405,7 @@
 void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, int ioHandle, void *param2) {
     ALOGV("ioConfigChanged() event %d", event);
     OutputDescriptor *desc;
-    uint32_t stream;
+    audio_stream_type_t stream;
 
     if (ioHandle == 0) return;
 
@@ -413,7 +414,7 @@
     switch (event) {
     case STREAM_CONFIG_CHANGED:
         if (param2 == 0) break;
-        stream = *(uint32_t *)param2;
+        stream = *(audio_stream_type_t *)param2;
         ALOGV("ioConfigChanged() STREAM_CONFIG_CHANGED stream %d, output %d", stream, ioHandle);
         if (gStreamOutputMap.indexOfKey(stream) >= 0) {
             gStreamOutputMap.replaceValueFor(stream, ioHandle);
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 17e3d4b..90a67db 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -501,7 +501,7 @@
     mVolume[LEFT] = left;
     mVolume[RIGHT] = right;
 
-    mCblk->volumeLR = (uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000);
+    mCblk->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000));
 
     return NO_ERROR;
 }
@@ -837,7 +837,7 @@
         mCblk->stepUser(mCblk->frameCount);
     }
 
-    mCblk->volumeLR = (uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) | uint16_t(mVolume[LEFT] * 0x1000);
+    mCblk->setVolumeLR((uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) | uint16_t(mVolume[LEFT] * 0x1000));
     mCblk->setSendLevel(mSendLevel);
     mAudioTrack->attachAuxEffect(mAuxEffectId);
     mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
@@ -1320,7 +1320,7 @@
 audio_track_cblk_t::audio_track_cblk_t()
     : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0),
     userBase(0), serverBase(0), buffers(0), frameCount(0),
-    loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0),
+    loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), mVolumeLR(0x10001000),
     mSendLevel(0), flags(0)
 {
 }
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index d2f5f71..27c7e03 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -59,9 +59,10 @@
         : BpInterface<IOMX>(impl) {
     }
 
-    virtual bool livesLocally(pid_t pid) {
+    virtual bool livesLocally(node_id node, pid_t pid) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        data.writeIntPtr((intptr_t)node);
         data.writeInt32(pid);
         remote()->transact(LIVES_LOCALLY, data, &reply);
 
@@ -417,7 +418,9 @@
         case LIVES_LOCALLY:
         {
             CHECK_INTERFACE(IOMX, data, reply);
-            reply->writeInt32(livesLocally((pid_t)data.readInt32()));
+            node_id node = (void *)data.readIntPtr();
+            pid_t pid = (pid_t)data.readInt32();
+            reply->writeInt32(livesLocally(node, pid));
 
             return OK;
         }
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 4d61067..03e8a06 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -74,11 +74,10 @@
         libcrypto        \
         libssl           \
         libgui           \
+        libstagefright_omx \
 
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_color_conversion \
-        libstagefright_amrnbenc \
-        libstagefright_amrwbenc \
         libstagefright_avcenc \
         libstagefright_m4vh263enc \
         libstagefright_matroska \
@@ -140,7 +139,6 @@
 ################################################################################
 
 LOCAL_SHARED_LIBRARIES += \
-        libstagefright_amrnb_common \
         libstagefright_enc_common \
         libstagefright_avc_common \
         libstagefright_foundation \
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 8480b6d..8073af8 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -30,7 +30,7 @@
 #include "include/MPEG2TSExtractor.h"
 #include "include/WVMExtractor.h"
 
-#include "timedtext/TimedTextPlayer.h"
+#include "timedtext/TimedTextDriver.h"
 
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -192,7 +192,7 @@
       mVideoBuffer(NULL),
       mDecryptHandle(NULL),
       mLastVideoTimeUs(-1),
-      mTextPlayer(NULL) {
+      mTextDriver(NULL) {
     CHECK_EQ(mClient.connect(), (status_t)OK);
 
     DataSource::RegisterDefaultSniffers();
@@ -530,9 +530,9 @@
     delete mAudioPlayer;
     mAudioPlayer = NULL;
 
-    if (mTextPlayer != NULL) {
-        delete mTextPlayer;
-        mTextPlayer = NULL;
+    if (mTextDriver != NULL) {
+        delete mTextDriver;
+        mTextDriver = NULL;
     }
 
     mVideoRenderer.clear();
@@ -1118,7 +1118,7 @@
     }
 
     if (mFlags & TEXTPLAYER_STARTED) {
-        mTextPlayer->pause();
+        mTextDriver->pause();
         modifyFlags(TEXT_RUNNING, CLEAR);
     }
 
@@ -1272,9 +1272,9 @@
 }
 
 status_t AwesomePlayer::setTimedTextTrackIndex(int32_t index) {
-    if (mTextPlayer != NULL) {
+    if (mTextDriver != NULL) {
         if (index >= 0) { // to turn on a text track
-            status_t err = mTextPlayer->setTimedTextTrackIndex(index);
+            status_t err = mTextDriver->setTimedTextTrackIndex(index);
             if (err != OK) {
                 return err;
             }
@@ -1290,7 +1290,7 @@
                 modifyFlags(TEXTPLAYER_STARTED, CLEAR);
             }
 
-            return mTextPlayer->setTimedTextTrackIndex(index);
+            return mTextDriver->setTimedTextTrackIndex(index);
         }
     } else {
         return INVALID_OPERATION;
@@ -1319,7 +1319,7 @@
     seekAudioIfNecessary_l();
 
     if (mFlags & TEXTPLAYER_STARTED) {
-        mTextPlayer->seekTo(mSeekTimeUs);
+        mTextDriver->seekToAsync(mSeekTimeUs);
     }
 
     if (!(mFlags & PLAYING)) {
@@ -1364,11 +1364,11 @@
     Mutex::Autolock autoLock(mTimedTextLock);
     CHECK(source != NULL);
 
-    if (mTextPlayer == NULL) {
-        mTextPlayer = new TimedTextPlayer(this, mListener, &mQueue);
+    if (mTextDriver == NULL) {
+        mTextDriver = new TimedTextDriver(mListener);
     }
 
-    mTextPlayer->addTextSource(source);
+    mTextDriver->addInBandTextSource(source);
 }
 
 status_t AwesomePlayer::initAudioDecoder() {
@@ -1695,7 +1695,7 @@
     }
 
     if ((mFlags & TEXTPLAYER_STARTED) && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) {
-        mTextPlayer->resume();
+        mTextDriver->resume();
         modifyFlags(TEXT_RUNNING, SET);
     }
 
@@ -2241,11 +2241,11 @@
         case KEY_PARAMETER_TIMED_TEXT_ADD_OUT_OF_BAND_SOURCE:
         {
             Mutex::Autolock autoLock(mTimedTextLock);
-            if (mTextPlayer == NULL) {
-                mTextPlayer = new TimedTextPlayer(this, mListener, &mQueue);
+            if (mTextDriver == NULL) {
+                mTextDriver = new TimedTextDriver(mListener);
             }
 
-            return mTextPlayer->setParameter(key, request);
+            return mTextDriver->addOutOfBandTextSource(request);
         }
         case KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS:
         {
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index bc88015..6c95d4e 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -20,7 +20,6 @@
 #include "include/MPEG4Extractor.h"
 #include "include/SampleTable.h"
 #include "include/ESDS.h"
-#include "timedtext/TimedTextPlayer.h"
 
 #include <arpa/inet.h>
 
@@ -2430,4 +2429,3 @@
 }
 
 }  // namespace android
-
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index 9de873e..7a805aa 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -20,11 +20,299 @@
 
 #include <binder/IServiceManager.h>
 #include <media/IMediaPlayerService.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/OMXClient.h>
+#include <utils/KeyedVector.h>
+
+#include "include/OMX.h"
 
 namespace android {
 
+struct MuxOMX : public IOMX {
+    MuxOMX(const sp<IOMX> &remoteOMX);
+    virtual ~MuxOMX();
+
+    virtual IBinder *onAsBinder() { return NULL; }
+
+    virtual bool livesLocally(node_id node, pid_t pid);
+
+    virtual status_t listNodes(List<ComponentInfo> *list);
+
+    virtual status_t allocateNode(
+            const char *name, const sp<IOMXObserver> &observer,
+            node_id *node);
+
+    virtual status_t freeNode(node_id node);
+
+    virtual status_t sendCommand(
+            node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param);
+
+    virtual status_t getParameter(
+            node_id node, OMX_INDEXTYPE index,
+            void *params, size_t size);
+
+    virtual status_t setParameter(
+            node_id node, OMX_INDEXTYPE index,
+            const void *params, size_t size);
+
+    virtual status_t getConfig(
+            node_id node, OMX_INDEXTYPE index,
+            void *params, size_t size);
+
+    virtual status_t setConfig(
+            node_id node, OMX_INDEXTYPE index,
+            const void *params, size_t size);
+
+    virtual status_t getState(
+            node_id node, OMX_STATETYPE* state);
+
+    virtual status_t storeMetaDataInBuffers(
+            node_id node, OMX_U32 port_index, OMX_BOOL enable);
+
+    virtual status_t enableGraphicBuffers(
+            node_id node, OMX_U32 port_index, OMX_BOOL enable);
+
+    virtual status_t getGraphicBufferUsage(
+            node_id node, OMX_U32 port_index, OMX_U32* usage);
+
+    virtual status_t useBuffer(
+            node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+            buffer_id *buffer);
+
+    virtual status_t useGraphicBuffer(
+            node_id node, OMX_U32 port_index,
+            const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer);
+
+    virtual status_t allocateBuffer(
+            node_id node, OMX_U32 port_index, size_t size,
+            buffer_id *buffer, void **buffer_data);
+
+    virtual status_t allocateBufferWithBackup(
+            node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+            buffer_id *buffer);
+
+    virtual status_t freeBuffer(
+            node_id node, OMX_U32 port_index, buffer_id buffer);
+
+    virtual status_t fillBuffer(node_id node, buffer_id buffer);
+
+    virtual status_t emptyBuffer(
+            node_id node,
+            buffer_id buffer,
+            OMX_U32 range_offset, OMX_U32 range_length,
+            OMX_U32 flags, OMX_TICKS timestamp);
+
+    virtual status_t getExtensionIndex(
+            node_id node,
+            const char *parameter_name,
+            OMX_INDEXTYPE *index);
+
+private:
+    mutable Mutex mLock;
+
+    sp<IOMX> mRemoteOMX;
+    sp<IOMX> mLocalOMX;
+
+    KeyedVector<node_id, bool> mIsLocalNode;
+
+    bool isLocalNode(node_id node) const;
+    bool isLocalNode_l(node_id node) const;
+    const sp<IOMX> &getOMX(node_id node) const;
+    const sp<IOMX> &getOMX_l(node_id node) const;
+
+    static bool IsSoftwareComponent(const char *name);
+
+    DISALLOW_EVIL_CONSTRUCTORS(MuxOMX);
+};
+
+MuxOMX::MuxOMX(const sp<IOMX> &remoteOMX)
+    : mRemoteOMX(remoteOMX) {
+}
+
+MuxOMX::~MuxOMX() {
+}
+
+bool MuxOMX::isLocalNode(node_id node) const {
+    Mutex::Autolock autoLock(mLock);
+
+    return isLocalNode_l(node);
+}
+
+bool MuxOMX::isLocalNode_l(node_id node) const {
+    return mIsLocalNode.indexOfKey(node) >= 0;
+}
+
+// static
+bool MuxOMX::IsSoftwareComponent(const char *name) {
+    return !strncasecmp(name, "OMX.google.", 11);
+}
+
+const sp<IOMX> &MuxOMX::getOMX(node_id node) const {
+    return isLocalNode(node) ? mLocalOMX : mRemoteOMX;
+}
+
+const sp<IOMX> &MuxOMX::getOMX_l(node_id node) const {
+    return isLocalNode_l(node) ? mLocalOMX : mRemoteOMX;
+}
+
+bool MuxOMX::livesLocally(node_id node, pid_t pid) {
+    return getOMX(node)->livesLocally(node, pid);
+}
+
+status_t MuxOMX::listNodes(List<ComponentInfo> *list) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mLocalOMX == NULL) {
+        mLocalOMX = new OMX;
+    }
+
+    return mLocalOMX->listNodes(list);
+}
+
+status_t MuxOMX::allocateNode(
+        const char *name, const sp<IOMXObserver> &observer,
+        node_id *node) {
+    Mutex::Autolock autoLock(mLock);
+
+    sp<IOMX> omx;
+
+    if (IsSoftwareComponent(name)) {
+        if (mLocalOMX == NULL) {
+            mLocalOMX = new OMX;
+        }
+        omx = mLocalOMX;
+    } else {
+        omx = mRemoteOMX;
+    }
+
+    status_t err = omx->allocateNode(name, observer, node);
+
+    if (err != OK) {
+        return err;
+    }
+
+    if (omx == mLocalOMX) {
+        mIsLocalNode.add(*node, true);
+    }
+
+    return OK;
+}
+
+status_t MuxOMX::freeNode(node_id node) {
+    Mutex::Autolock autoLock(mLock);
+
+    status_t err = getOMX_l(node)->freeNode(node);
+
+    if (err != OK) {
+        return err;
+    }
+
+    mIsLocalNode.removeItem(node);
+
+    return OK;
+}
+
+status_t MuxOMX::sendCommand(
+        node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
+    return getOMX(node)->sendCommand(node, cmd, param);
+}
+
+status_t MuxOMX::getParameter(
+        node_id node, OMX_INDEXTYPE index,
+        void *params, size_t size) {
+    return getOMX(node)->getParameter(node, index, params, size);
+}
+
+status_t MuxOMX::setParameter(
+        node_id node, OMX_INDEXTYPE index,
+        const void *params, size_t size) {
+    return getOMX(node)->setParameter(node, index, params, size);
+}
+
+status_t MuxOMX::getConfig(
+        node_id node, OMX_INDEXTYPE index,
+        void *params, size_t size) {
+    return getOMX(node)->getConfig(node, index, params, size);
+}
+
+status_t MuxOMX::setConfig(
+        node_id node, OMX_INDEXTYPE index,
+        const void *params, size_t size) {
+    return getOMX(node)->setConfig(node, index, params, size);
+}
+
+status_t MuxOMX::getState(
+        node_id node, OMX_STATETYPE* state) {
+    return getOMX(node)->getState(node, state);
+}
+
+status_t MuxOMX::storeMetaDataInBuffers(
+        node_id node, OMX_U32 port_index, OMX_BOOL enable) {
+    return getOMX(node)->storeMetaDataInBuffers(node, port_index, enable);
+}
+
+status_t MuxOMX::enableGraphicBuffers(
+        node_id node, OMX_U32 port_index, OMX_BOOL enable) {
+    return getOMX(node)->enableGraphicBuffers(node, port_index, enable);
+}
+
+status_t MuxOMX::getGraphicBufferUsage(
+        node_id node, OMX_U32 port_index, OMX_U32* usage) {
+    return getOMX(node)->getGraphicBufferUsage(node, port_index, usage);
+}
+
+status_t MuxOMX::useBuffer(
+        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+        buffer_id *buffer) {
+    return getOMX(node)->useBuffer(node, port_index, params, buffer);
+}
+
+status_t MuxOMX::useGraphicBuffer(
+        node_id node, OMX_U32 port_index,
+        const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
+    return getOMX(node)->useGraphicBuffer(
+            node, port_index, graphicBuffer, buffer);
+}
+
+status_t MuxOMX::allocateBuffer(
+        node_id node, OMX_U32 port_index, size_t size,
+        buffer_id *buffer, void **buffer_data) {
+    return getOMX(node)->allocateBuffer(
+            node, port_index, size, buffer, buffer_data);
+}
+
+status_t MuxOMX::allocateBufferWithBackup(
+        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+        buffer_id *buffer) {
+    return getOMX(node)->allocateBufferWithBackup(
+            node, port_index, params, buffer);
+}
+
+status_t MuxOMX::freeBuffer(
+        node_id node, OMX_U32 port_index, buffer_id buffer) {
+    return getOMX(node)->freeBuffer(node, port_index, buffer);
+}
+
+status_t MuxOMX::fillBuffer(node_id node, buffer_id buffer) {
+    return getOMX(node)->fillBuffer(node, buffer);
+}
+
+status_t MuxOMX::emptyBuffer(
+        node_id node,
+        buffer_id buffer,
+        OMX_U32 range_offset, OMX_U32 range_length,
+        OMX_U32 flags, OMX_TICKS timestamp) {
+    return getOMX(node)->emptyBuffer(
+            node, buffer, range_offset, range_length, flags, timestamp);
+}
+
+status_t MuxOMX::getExtensionIndex(
+        node_id node,
+        const char *parameter_name,
+        OMX_INDEXTYPE *index) {
+    return getOMX(node)->getExtensionIndex(node, parameter_name, index);
+}
+
 OMXClient::OMXClient() {
 }
 
@@ -38,6 +326,11 @@
     mOMX = service->getOMX();
     CHECK(mOMX.get() != NULL);
 
+    if (!mOMX->livesLocally(NULL /* node */, getpid())) {
+        ALOGI("Using client-side OMX mux.");
+        mOMX = new MuxOMX(mOMX);
+    }
+
     return OK;
 }
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 7597f64..af4aa79 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -18,8 +18,6 @@
 #define LOG_TAG "OMXCodec"
 #include <utils/Log.h>
 
-#include "include/AMRNBEncoder.h"
-#include "include/AMRWBEncoder.h"
 #include "include/AVCEncoder.h"
 #include "include/M4vH263Encoder.h"
 
@@ -70,8 +68,6 @@
 
 #define FACTORY_REF(name) { #name, Make##name },
 
-FACTORY_CREATE_ENCODER(AMRNBEncoder)
-FACTORY_CREATE_ENCODER(AMRWBEncoder)
 FACTORY_CREATE_ENCODER(AVCEncoder)
 FACTORY_CREATE_ENCODER(M4vH263Encoder)
 
@@ -84,8 +80,6 @@
     };
 
     static const FactoryInfo kFactoryInfo[] = {
-        FACTORY_REF(AMRNBEncoder)
-        FACTORY_REF(AMRWBEncoder)
         FACTORY_REF(AVCEncoder)
         FACTORY_REF(M4vH263Encoder)
     };
@@ -146,9 +140,9 @@
 
 static const CodecInfo kEncoderInfo[] = {
     { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.encode" },
-    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "AMRNBEncoder" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.google.amrnb.encoder" },
     { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.encode" },
-    { MEDIA_MIMETYPE_AUDIO_AMR_WB, "AMRWBEncoder" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.google.amrwb.encoder" },
     { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.encode" },
     { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.google.aac.encoder" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.DUCATI1.VIDEO.MPEG4E" },
@@ -1479,7 +1473,7 @@
         const sp<MediaSource> &source,
         const sp<ANativeWindow> &nativeWindow)
     : mOMX(omx),
-      mOMXLivesLocally(omx->livesLocally(getpid())),
+      mOMXLivesLocally(omx->livesLocally(node, getpid())),
       mNode(node),
       mQuirks(quirks),
       mFlags(flags),
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC.cpp b/media/libstagefright/codecs/aacdec/SoftAAC.cpp
index da9d280..ea6c360 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC.cpp
@@ -218,6 +218,18 @@
             return OMX_ErrorNone;
         }
 
+        case OMX_IndexParamAudioPcm:
+        {
+            const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (pcmParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
         default:
             return SimpleSoftOMXComponent::internalSetParameter(index, params);
     }
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.mk b/media/libstagefright/codecs/amrnb/enc/Android.mk
index b6aed81..94e8726 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.mk
+++ b/media/libstagefright/codecs/amrnb/enc/Android.mk
@@ -74,3 +74,30 @@
 LOCAL_MODULE := libstagefright_amrnbenc
 
 include $(BUILD_STATIC_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+        SoftAMRNBEncoder.cpp
+
+LOCAL_C_INCLUDES := \
+        frameworks/base/media/libstagefright/include \
+        frameworks/base/include/media/stagefright/openmax \
+        $(LOCAL_PATH)/src \
+        $(LOCAL_PATH)/include \
+        $(LOCAL_PATH)/../common/include \
+        $(LOCAL_PATH)/../common
+
+LOCAL_STATIC_LIBRARIES := \
+        libstagefright_amrnbenc
+
+LOCAL_SHARED_LIBRARIES := \
+        libstagefright_omx libstagefright_foundation libutils \
+        libstagefright_amrnb_common
+
+LOCAL_MODULE := libstagefright_soft_amrnbenc
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
new file mode 100644
index 0000000..07f8b4f
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
@@ -0,0 +1,404 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoftAMRNBEncoder"
+#include <utils/Log.h>
+
+#include "SoftAMRNBEncoder.h"
+
+#include "gsmamr_enc.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
+
+namespace android {
+
+static const int32_t kSampleRate = 8000;
+
+template<class T>
+static void InitOMXParams(T *params) {
+    params->nSize = sizeof(T);
+    params->nVersion.s.nVersionMajor = 1;
+    params->nVersion.s.nVersionMinor = 0;
+    params->nVersion.s.nRevision = 0;
+    params->nVersion.s.nStep = 0;
+}
+
+SoftAMRNBEncoder::SoftAMRNBEncoder(
+        const char *name,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component)
+    : SimpleSoftOMXComponent(name, callbacks, appData, component),
+      mEncState(NULL),
+      mSidState(NULL),
+      mBitRate(0),
+      mMode(MR475),
+      mInputSize(0),
+      mInputTimeUs(-1ll),
+      mSawInputEOS(false),
+      mSignalledError(false) {
+    initPorts();
+    CHECK_EQ(initEncoder(), (status_t)OK);
+}
+
+SoftAMRNBEncoder::~SoftAMRNBEncoder() {
+    if (mEncState != NULL) {
+        AMREncodeExit(&mEncState, &mSidState);
+        mEncState = mSidState = NULL;
+    }
+}
+
+void SoftAMRNBEncoder::initPorts() {
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+
+    def.nPortIndex = 0;
+    def.eDir = OMX_DirInput;
+    def.nBufferCountMin = kNumBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t);
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 1;
+
+    def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
+    def.format.audio.pNativeRender = NULL;
+    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+    addPort(def);
+
+    def.nPortIndex = 1;
+    def.eDir = OMX_DirOutput;
+    def.nBufferCountMin = kNumBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = 8192;
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 2;
+
+    def.format.audio.cMIMEType = const_cast<char *>("audio/3gpp");
+    def.format.audio.pNativeRender = NULL;
+    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+    def.format.audio.eEncoding = OMX_AUDIO_CodingAMR;
+
+    addPort(def);
+}
+
+status_t SoftAMRNBEncoder::initEncoder() {
+    if (AMREncodeInit(&mEncState, &mSidState, false /* dtx_enable */) != 0) {
+        return UNKNOWN_ERROR;
+    }
+
+    return OK;
+}
+
+OMX_ERRORTYPE SoftAMRNBEncoder::internalGetParameter(
+        OMX_INDEXTYPE index, OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexParamAudioPortFormat:
+        {
+            OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+                (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (formatParams->nIndex > 0) {
+                return OMX_ErrorNoMore;
+            }
+
+            formatParams->eEncoding =
+                (formatParams->nPortIndex == 0)
+                    ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAMR;
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioAmr:
+        {
+            OMX_AUDIO_PARAM_AMRTYPE *amrParams =
+                (OMX_AUDIO_PARAM_AMRTYPE *)params;
+
+            if (amrParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            amrParams->nChannels = 1;
+            amrParams->nBitRate = mBitRate;
+            amrParams->eAMRBandMode = (OMX_AUDIO_AMRBANDMODETYPE)(mMode + 1);
+            amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
+            amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (pcmParams->nPortIndex != 0) {
+                return OMX_ErrorUndefined;
+            }
+
+            pcmParams->eNumData = OMX_NumericalDataSigned;
+            pcmParams->eEndian = OMX_EndianBig;
+            pcmParams->bInterleaved = OMX_TRUE;
+            pcmParams->nBitPerSample = 16;
+            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelCF;
+
+            pcmParams->nChannels = 1;
+            pcmParams->nSamplingRate = kSampleRate;
+
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SimpleSoftOMXComponent::internalGetParameter(index, params);
+    }
+}
+
+OMX_ERRORTYPE SoftAMRNBEncoder::internalSetParameter(
+        OMX_INDEXTYPE index, const OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexParamStandardComponentRole:
+        {
+            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+                (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+            if (strncmp((const char *)roleParams->cRole,
+                        "audio_encoder.amrnb",
+                        OMX_MAX_STRINGNAME_SIZE - 1)) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPortFormat:
+        {
+            const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+                (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (formatParams->nIndex > 0) {
+                return OMX_ErrorNoMore;
+            }
+
+            if ((formatParams->nPortIndex == 0
+                        && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
+                || (formatParams->nPortIndex == 1
+                        && formatParams->eEncoding != OMX_AUDIO_CodingAMR)) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioAmr:
+        {
+            OMX_AUDIO_PARAM_AMRTYPE *amrParams =
+                (OMX_AUDIO_PARAM_AMRTYPE *)params;
+
+            if (amrParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (amrParams->nChannels != 1
+                    || amrParams->eAMRDTXMode != OMX_AUDIO_AMRDTXModeOff
+                    || amrParams->eAMRFrameFormat
+                            != OMX_AUDIO_AMRFrameFormatFSF
+                    || amrParams->eAMRBandMode < OMX_AUDIO_AMRBandModeNB0
+                    || amrParams->eAMRBandMode > OMX_AUDIO_AMRBandModeNB7) {
+                return OMX_ErrorUndefined;
+            }
+
+            mBitRate = amrParams->nBitRate;
+            mMode = amrParams->eAMRBandMode - 1;
+
+            amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
+            amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (pcmParams->nPortIndex != 0) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (pcmParams->nChannels != 1
+                    || pcmParams->nSamplingRate != kSampleRate) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+
+        default:
+            return SimpleSoftOMXComponent::internalSetParameter(index, params);
+    }
+}
+
+void SoftAMRNBEncoder::onQueueFilled(OMX_U32 portIndex) {
+    if (mSignalledError) {
+        return;
+    }
+
+    List<BufferInfo *> &inQueue = getPortQueue(0);
+    List<BufferInfo *> &outQueue = getPortQueue(1);
+
+    size_t numBytesPerInputFrame = kNumSamplesPerFrame * sizeof(int16_t);
+
+    for (;;) {
+        // We do the following until we run out of buffers.
+
+        while (mInputSize < numBytesPerInputFrame) {
+            // As long as there's still input data to be read we
+            // will drain "kNumSamplesPerFrame" samples
+            // into the "mInputFrame" buffer and then encode those
+            // as a unit into an output buffer.
+
+            if (mSawInputEOS || inQueue.empty()) {
+                return;
+            }
+
+            BufferInfo *inInfo = *inQueue.begin();
+            OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+            const void *inData = inHeader->pBuffer + inHeader->nOffset;
+
+            size_t copy = numBytesPerInputFrame - mInputSize;
+            if (copy > inHeader->nFilledLen) {
+                copy = inHeader->nFilledLen;
+            }
+
+            if (mInputSize == 0) {
+                mInputTimeUs = inHeader->nTimeStamp;
+            }
+
+            memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy);
+            mInputSize += copy;
+
+            inHeader->nOffset += copy;
+            inHeader->nFilledLen -= copy;
+
+            // "Time" on the input buffer has in effect advanced by the
+            // number of audio frames we just advanced nOffset by.
+            inHeader->nTimeStamp +=
+                (copy * 1000000ll / kSampleRate) / sizeof(int16_t);
+
+            if (inHeader->nFilledLen == 0) {
+                if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+                    ALOGV("saw input EOS");
+                    mSawInputEOS = true;
+
+                    // Pad any remaining data with zeroes.
+                    memset((uint8_t *)mInputFrame + mInputSize,
+                           0,
+                           numBytesPerInputFrame - mInputSize);
+
+                    mInputSize = numBytesPerInputFrame;
+                }
+
+                inQueue.erase(inQueue.begin());
+                inInfo->mOwnedByUs = false;
+                notifyEmptyBufferDone(inHeader);
+
+                inData = NULL;
+                inHeader = NULL;
+                inInfo = NULL;
+            }
+        }
+
+        // At this  point we have all the input data necessary to encode
+        // a single frame, all we need is an output buffer to store the result
+        // in.
+
+        if (outQueue.empty()) {
+            return;
+        }
+
+        BufferInfo *outInfo = *outQueue.begin();
+        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+        uint8_t *outPtr = outHeader->pBuffer + outHeader->nOffset;
+        size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset;
+
+        Frame_Type_3GPP frameType;
+        int res = AMREncode(
+                mEncState, mSidState, (Mode)mMode,
+                mInputFrame, outPtr, &frameType, AMR_TX_WMF);
+
+        CHECK_GE(res, 0);
+        CHECK_LE((size_t)res, outAvailable);
+
+        // Convert header byte from WMF to IETF format.
+        outPtr[0] = ((outPtr[0] << 3) | 4) & 0x7c;
+
+        outHeader->nFilledLen = res;
+        outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
+
+        if (mSawInputEOS) {
+            // We also tag this output buffer with EOS if it corresponds
+            // to the final input buffer.
+            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+        }
+
+        outHeader->nTimeStamp = mInputTimeUs;
+
+#if 0
+        ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)",
+              nOutputBytes, mInputTimeUs, outHeader->nFlags);
+
+        hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
+#endif
+
+        outQueue.erase(outQueue.begin());
+        outInfo->mOwnedByUs = false;
+        notifyFillBufferDone(outHeader);
+
+        outHeader = NULL;
+        outInfo = NULL;
+
+        mInputSize = 0;
+    }
+}
+
+}  // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+        const char *name, const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+    return new android::SoftAMRNBEncoder(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h
new file mode 100644
index 0000000..50178c4
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOFT_AMRNB_ENCODER_H_
+
+#define SOFT_AMRNB_ENCODER_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+namespace android {
+
+struct SoftAMRNBEncoder : public SimpleSoftOMXComponent {
+    SoftAMRNBEncoder(
+            const char *name,
+            const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData,
+            OMX_COMPONENTTYPE **component);
+
+protected:
+    virtual ~SoftAMRNBEncoder();
+
+    virtual OMX_ERRORTYPE internalGetParameter(
+            OMX_INDEXTYPE index, OMX_PTR params);
+
+    virtual OMX_ERRORTYPE internalSetParameter(
+            OMX_INDEXTYPE index, const OMX_PTR params);
+
+    virtual void onQueueFilled(OMX_U32 portIndex);
+
+private:
+    enum {
+        kNumBuffers             = 4,
+        kNumSamplesPerFrame     = 160,
+    };
+
+    void *mEncState;
+    void *mSidState;
+
+    OMX_U32 mBitRate;
+    int mMode;
+
+    size_t mInputSize;
+    int16_t mInputFrame[kNumSamplesPerFrame];
+    int64_t mInputTimeUs;
+
+    bool mSawInputEOS;
+    bool mSignalledError;
+
+    void initPorts();
+    status_t initEncoder();
+
+    status_t setAudioParams();
+
+    DISALLOW_EVIL_CONSTRUCTORS(SoftAMRNBEncoder);
+};
+
+}  // namespace android
+
+#endif  // SOFT_AMRNB_ENCODER_H_
diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk
index ae43870..6ce6171 100644
--- a/media/libstagefright/codecs/amrwbenc/Android.mk
+++ b/media/libstagefright/codecs/amrwbenc/Android.mk
@@ -117,4 +117,26 @@
 
 include $(BUILD_STATIC_LIBRARY)
 
+################################################################################
 
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+        SoftAMRWBEncoder.cpp
+
+LOCAL_C_INCLUDES := \
+        frameworks/base/media/libstagefright/include \
+        frameworks/base/include/media/stagefright/openmax \
+	frameworks/base/media/libstagefright/codecs/common/include \
+
+LOCAL_STATIC_LIBRARIES := \
+        libstagefright_amrwbenc
+
+LOCAL_SHARED_LIBRARIES := \
+        libstagefright_omx libstagefright_foundation libutils \
+        libstagefright_enc_common
+
+LOCAL_MODULE := libstagefright_soft_amrwbenc
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
new file mode 100644
index 0000000..9ccb49c
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
@@ -0,0 +1,459 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoftAMRWBEncoder"
+#include <utils/Log.h>
+
+#include "SoftAMRWBEncoder.h"
+
+#include "cmnMemory.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
+
+namespace android {
+
+static const int32_t kSampleRate = 16000;
+
+template<class T>
+static void InitOMXParams(T *params) {
+    params->nSize = sizeof(T);
+    params->nVersion.s.nVersionMajor = 1;
+    params->nVersion.s.nVersionMinor = 0;
+    params->nVersion.s.nRevision = 0;
+    params->nVersion.s.nStep = 0;
+}
+
+SoftAMRWBEncoder::SoftAMRWBEncoder(
+        const char *name,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component)
+    : SimpleSoftOMXComponent(name, callbacks, appData, component),
+      mEncoderHandle(NULL),
+      mApiHandle(NULL),
+      mMemOperator(NULL),
+      mBitRate(0),
+      mMode(VOAMRWB_MD66),
+      mInputSize(0),
+      mInputTimeUs(-1ll),
+      mSawInputEOS(false),
+      mSignalledError(false) {
+    initPorts();
+    CHECK_EQ(initEncoder(), (status_t)OK);
+}
+
+SoftAMRWBEncoder::~SoftAMRWBEncoder() {
+    if (mEncoderHandle != NULL) {
+        CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
+        mEncoderHandle = NULL;
+    }
+
+    delete mApiHandle;
+    mApiHandle = NULL;
+
+    delete mMemOperator;
+    mMemOperator = NULL;
+}
+
+void SoftAMRWBEncoder::initPorts() {
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+
+    def.nPortIndex = 0;
+    def.eDir = OMX_DirInput;
+    def.nBufferCountMin = kNumBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t);
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 1;
+
+    def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
+    def.format.audio.pNativeRender = NULL;
+    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+    addPort(def);
+
+    def.nPortIndex = 1;
+    def.eDir = OMX_DirOutput;
+    def.nBufferCountMin = kNumBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = 8192;
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 2;
+
+    def.format.audio.cMIMEType = const_cast<char *>("audio/amr-wb");
+    def.format.audio.pNativeRender = NULL;
+    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+    def.format.audio.eEncoding = OMX_AUDIO_CodingAMR;
+
+    addPort(def);
+}
+
+status_t SoftAMRWBEncoder::initEncoder() {
+    mApiHandle = new VO_AUDIO_CODECAPI;
+
+    if (VO_ERR_NONE != voGetAMRWBEncAPI(mApiHandle)) {
+        ALOGE("Failed to get api handle");
+        return UNKNOWN_ERROR;
+    }
+
+    mMemOperator = new VO_MEM_OPERATOR;
+    mMemOperator->Alloc = cmnMemAlloc;
+    mMemOperator->Copy = cmnMemCopy;
+    mMemOperator->Free = cmnMemFree;
+    mMemOperator->Set = cmnMemSet;
+    mMemOperator->Check = cmnMemCheck;
+
+    VO_CODEC_INIT_USERDATA userData;
+    memset(&userData, 0, sizeof(userData));
+    userData.memflag = VO_IMF_USERMEMOPERATOR;
+    userData.memData = (VO_PTR) mMemOperator;
+
+    if (VO_ERR_NONE != mApiHandle->Init(
+                &mEncoderHandle, VO_AUDIO_CodingAMRWB, &userData)) {
+        ALOGE("Failed to init AMRWB encoder");
+        return UNKNOWN_ERROR;
+    }
+
+    VOAMRWBFRAMETYPE type = VOAMRWB_RFC3267;
+    if (VO_ERR_NONE != mApiHandle->SetParam(
+                mEncoderHandle, VO_PID_AMRWB_FRAMETYPE, &type)) {
+        ALOGE("Failed to set AMRWB encoder frame type to %d", type);
+        return UNKNOWN_ERROR;
+    }
+
+    return OK;
+}
+
+OMX_ERRORTYPE SoftAMRWBEncoder::internalGetParameter(
+        OMX_INDEXTYPE index, OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexParamAudioPortFormat:
+        {
+            OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+                (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (formatParams->nIndex > 0) {
+                return OMX_ErrorNoMore;
+            }
+
+            formatParams->eEncoding =
+                (formatParams->nPortIndex == 0)
+                    ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAMR;
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioAmr:
+        {
+            OMX_AUDIO_PARAM_AMRTYPE *amrParams =
+                (OMX_AUDIO_PARAM_AMRTYPE *)params;
+
+            if (amrParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            amrParams->nChannels = 1;
+            amrParams->nBitRate = mBitRate;
+
+            amrParams->eAMRBandMode =
+                (OMX_AUDIO_AMRBANDMODETYPE)(mMode + OMX_AUDIO_AMRBandModeWB0);
+
+            amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
+            amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (pcmParams->nPortIndex != 0) {
+                return OMX_ErrorUndefined;
+            }
+
+            pcmParams->eNumData = OMX_NumericalDataSigned;
+            pcmParams->eEndian = OMX_EndianBig;
+            pcmParams->bInterleaved = OMX_TRUE;
+            pcmParams->nBitPerSample = 16;
+            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelCF;
+
+            pcmParams->nChannels = 1;
+            pcmParams->nSamplingRate = kSampleRate;
+
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SimpleSoftOMXComponent::internalGetParameter(index, params);
+    }
+}
+
+OMX_ERRORTYPE SoftAMRWBEncoder::internalSetParameter(
+        OMX_INDEXTYPE index, const OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexParamStandardComponentRole:
+        {
+            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+                (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+            if (strncmp((const char *)roleParams->cRole,
+                        "audio_encoder.amrwb",
+                        OMX_MAX_STRINGNAME_SIZE - 1)) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPortFormat:
+        {
+            const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+                (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (formatParams->nIndex > 0) {
+                return OMX_ErrorNoMore;
+            }
+
+            if ((formatParams->nPortIndex == 0
+                        && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
+                || (formatParams->nPortIndex == 1
+                        && formatParams->eEncoding != OMX_AUDIO_CodingAMR)) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioAmr:
+        {
+            OMX_AUDIO_PARAM_AMRTYPE *amrParams =
+                (OMX_AUDIO_PARAM_AMRTYPE *)params;
+
+            if (amrParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (amrParams->nChannels != 1
+                    || amrParams->eAMRDTXMode != OMX_AUDIO_AMRDTXModeOff
+                    || amrParams->eAMRFrameFormat
+                            != OMX_AUDIO_AMRFrameFormatFSF
+                    || amrParams->eAMRBandMode < OMX_AUDIO_AMRBandModeWB0
+                    || amrParams->eAMRBandMode > OMX_AUDIO_AMRBandModeWB8) {
+                return OMX_ErrorUndefined;
+            }
+
+            mBitRate = amrParams->nBitRate;
+
+            mMode = (VOAMRWBMODE)(
+                    amrParams->eAMRBandMode - OMX_AUDIO_AMRBandModeWB0);
+
+            amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
+            amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+
+            if (VO_ERR_NONE !=
+                    mApiHandle->SetParam(
+                        mEncoderHandle, VO_PID_AMRWB_MODE,  &mMode)) {
+                ALOGE("Failed to set AMRWB encoder mode to %d", mMode);
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (pcmParams->nPortIndex != 0) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (pcmParams->nChannels != 1
+                    || pcmParams->nSamplingRate != (OMX_U32)kSampleRate) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+
+        default:
+            return SimpleSoftOMXComponent::internalSetParameter(index, params);
+    }
+}
+
+void SoftAMRWBEncoder::onQueueFilled(OMX_U32 portIndex) {
+    if (mSignalledError) {
+        return;
+    }
+
+    List<BufferInfo *> &inQueue = getPortQueue(0);
+    List<BufferInfo *> &outQueue = getPortQueue(1);
+
+    size_t numBytesPerInputFrame = kNumSamplesPerFrame * sizeof(int16_t);
+
+    for (;;) {
+        // We do the following until we run out of buffers.
+
+        while (mInputSize < numBytesPerInputFrame) {
+            // As long as there's still input data to be read we
+            // will drain "kNumSamplesPerFrame" samples
+            // into the "mInputFrame" buffer and then encode those
+            // as a unit into an output buffer.
+
+            if (mSawInputEOS || inQueue.empty()) {
+                return;
+            }
+
+            BufferInfo *inInfo = *inQueue.begin();
+            OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+            const void *inData = inHeader->pBuffer + inHeader->nOffset;
+
+            size_t copy = numBytesPerInputFrame - mInputSize;
+            if (copy > inHeader->nFilledLen) {
+                copy = inHeader->nFilledLen;
+            }
+
+            if (mInputSize == 0) {
+                mInputTimeUs = inHeader->nTimeStamp;
+            }
+
+            memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy);
+            mInputSize += copy;
+
+            inHeader->nOffset += copy;
+            inHeader->nFilledLen -= copy;
+
+            // "Time" on the input buffer has in effect advanced by the
+            // number of audio frames we just advanced nOffset by.
+            inHeader->nTimeStamp +=
+                (copy * 1000000ll / kSampleRate) / sizeof(int16_t);
+
+            if (inHeader->nFilledLen == 0) {
+                if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+                    ALOGV("saw input EOS");
+                    mSawInputEOS = true;
+
+                    // Pad any remaining data with zeroes.
+                    memset((uint8_t *)mInputFrame + mInputSize,
+                           0,
+                           numBytesPerInputFrame - mInputSize);
+
+                    mInputSize = numBytesPerInputFrame;
+                }
+
+                inQueue.erase(inQueue.begin());
+                inInfo->mOwnedByUs = false;
+                notifyEmptyBufferDone(inHeader);
+
+                inData = NULL;
+                inHeader = NULL;
+                inInfo = NULL;
+            }
+        }
+
+        // At this  point we have all the input data necessary to encode
+        // a single frame, all we need is an output buffer to store the result
+        // in.
+
+        if (outQueue.empty()) {
+            return;
+        }
+
+        BufferInfo *outInfo = *outQueue.begin();
+        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+        uint8_t *outPtr = outHeader->pBuffer + outHeader->nOffset;
+        size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset;
+
+        VO_CODECBUFFER inputData;
+        memset(&inputData, 0, sizeof(inputData));
+        inputData.Buffer = (unsigned char *) mInputFrame;
+        inputData.Length = mInputSize;
+
+        CHECK_EQ(VO_ERR_NONE,
+                 mApiHandle->SetInputData(mEncoderHandle, &inputData));
+
+        VO_CODECBUFFER outputData;
+        memset(&outputData, 0, sizeof(outputData));
+        VO_AUDIO_OUTPUTINFO outputInfo;
+        memset(&outputInfo, 0, sizeof(outputInfo));
+
+        outputData.Buffer = outPtr;
+        outputData.Length = outAvailable;
+        VO_U32 ret = mApiHandle->GetOutputData(
+                mEncoderHandle, &outputData, &outputInfo);
+        CHECK(ret == VO_ERR_NONE || ret == VO_ERR_INPUT_BUFFER_SMALL);
+
+        outHeader->nFilledLen = outputData.Length;
+        outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
+
+        if (mSawInputEOS) {
+            // We also tag this output buffer with EOS if it corresponds
+            // to the final input buffer.
+            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+        }
+
+        outHeader->nTimeStamp = mInputTimeUs;
+
+#if 0
+        ALOGI("sending %ld bytes of data (time = %lld us, flags = 0x%08lx)",
+              outHeader->nFilledLen, mInputTimeUs, outHeader->nFlags);
+
+        hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
+#endif
+
+        outQueue.erase(outQueue.begin());
+        outInfo->mOwnedByUs = false;
+        notifyFillBufferDone(outHeader);
+
+        outHeader = NULL;
+        outInfo = NULL;
+
+        mInputSize = 0;
+    }
+}
+
+}  // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+        const char *name, const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+    return new android::SoftAMRWBEncoder(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h
new file mode 100644
index 0000000..d0c1dab
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOFT_AMRWB_ENCODER_H_
+
+#define SOFT_AMRWB_ENCODER_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+#include "voAMRWB.h"
+
+struct VO_AUDIO_CODECAPI;
+struct VO_MEM_OPERATOR;
+
+namespace android {
+
+struct SoftAMRWBEncoder : public SimpleSoftOMXComponent {
+    SoftAMRWBEncoder(
+            const char *name,
+            const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData,
+            OMX_COMPONENTTYPE **component);
+
+protected:
+    virtual ~SoftAMRWBEncoder();
+
+    virtual OMX_ERRORTYPE internalGetParameter(
+            OMX_INDEXTYPE index, OMX_PTR params);
+
+    virtual OMX_ERRORTYPE internalSetParameter(
+            OMX_INDEXTYPE index, const OMX_PTR params);
+
+    virtual void onQueueFilled(OMX_U32 portIndex);
+
+private:
+    enum {
+        kNumBuffers             = 4,
+        kNumSamplesPerFrame     = 320,
+    };
+
+    void *mEncoderHandle;
+    VO_AUDIO_CODECAPI *mApiHandle;
+    VO_MEM_OPERATOR *mMemOperator;
+
+    OMX_U32 mBitRate;
+    VOAMRWBMODE mMode;
+
+    size_t mInputSize;
+    int16_t mInputFrame[kNumSamplesPerFrame];
+    int64_t mInputTimeUs;
+
+    bool mSawInputEOS;
+    bool mSignalledError;
+
+    void initPorts();
+    status_t initEncoder();
+
+    DISALLOW_EVIL_CONSTRUCTORS(SoftAMRWBEncoder);
+};
+
+}  // namespace android
+
+#endif  // SOFT_AMRWB_ENCODER_H_
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index 5cc3f78..f3ef3de 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -144,8 +144,8 @@
         return ERROR_UNSUPPORTED;
     }
 
-    uint32_t *dst_ptr = (uint32_t *)dst.mBits
-        + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
+    uint16_t *dst_ptr = (uint16_t *)dst.mBits
+        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
     const uint8_t *src_ptr = (const uint8_t *)src.mBits
         + (src.mCropTop * dst.mWidth + src.mCropLeft) * 2;
@@ -182,11 +182,15 @@
                 | ((kAdjustedClip[g2] >> 2) << 5)
                 | (kAdjustedClip[b2] >> 3);
 
-            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+            if (x + 1 < src.cropWidth()) {
+                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
+            } else {
+                dst_ptr[x] = rgb1;
+            }
         }
 
         src_ptr += src.mWidth * 2;
-        dst_ptr += dst.mWidth / 2;
+        dst_ptr += dst.mWidth;
     }
 
     return OK;
@@ -290,15 +294,14 @@
         const BitmapParams &src, const BitmapParams &dst) {
     uint8_t *kAdjustedClip = initClip();
 
-    if (!((dst.mWidth & 3) == 0
-            && (src.mCropLeft & 1) == 0
+    if (!((src.mCropLeft & 1) == 0
             && src.cropWidth() == dst.cropWidth()
             && src.cropHeight() == dst.cropHeight())) {
         return ERROR_UNSUPPORTED;
     }
 
-    uint32_t *dst_ptr = (uint32_t *)dst.mBits
-        + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
+    uint16_t *dst_ptr = (uint16_t *)dst.mBits
+        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
     const uint8_t *src_y =
         (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
@@ -340,7 +343,11 @@
                 | ((kAdjustedClip[g2] >> 2) << 5)
                 | (kAdjustedClip[r2] >> 3);
 
-            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+            if (x + 1 < src.cropWidth()) {
+                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
+            } else {
+                dst_ptr[x] = rgb1;
+            }
         }
 
         src_y += src.mWidth;
@@ -349,7 +356,7 @@
             src_u += src.mWidth;
         }
 
-        dst_ptr += dst.mWidth / 2;
+        dst_ptr += dst.mWidth;
     }
 
     return OK;
@@ -361,15 +368,14 @@
 
     uint8_t *kAdjustedClip = initClip();
 
-    if (!((dst.mWidth & 3) == 0
-            && (src.mCropLeft & 1) == 0
+    if (!((src.mCropLeft & 1) == 0
             && src.cropWidth() == dst.cropWidth()
             && src.cropHeight() == dst.cropHeight())) {
         return ERROR_UNSUPPORTED;
     }
 
-    uint32_t *dst_ptr = (uint32_t *)dst.mBits
-        + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
+    uint16_t *dst_ptr = (uint16_t *)dst.mBits
+        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
     const uint8_t *src_y =
         (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
@@ -411,7 +417,11 @@
                 | ((kAdjustedClip[g2] >> 2) << 5)
                 | (kAdjustedClip[r2] >> 3);
 
-            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+            if (x + 1 < src.cropWidth()) {
+                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
+            } else {
+                dst_ptr[x] = rgb1;
+            }
         }
 
         src_y += src.mWidth;
@@ -420,7 +430,7 @@
             src_u += src.mWidth;
         }
 
-        dst_ptr += dst.mWidth / 2;
+        dst_ptr += dst.mWidth;
     }
 
     return OK;
@@ -430,15 +440,14 @@
         const BitmapParams &src, const BitmapParams &dst) {
     uint8_t *kAdjustedClip = initClip();
 
-    if (!((dst.mWidth & 3) == 0
-            && (src.mCropLeft & 1) == 0
+    if (!((src.mCropLeft & 1) == 0
             && src.cropWidth() == dst.cropWidth()
             && src.cropHeight() == dst.cropHeight())) {
         return ERROR_UNSUPPORTED;
     }
 
-    uint32_t *dst_ptr = (uint32_t *)dst.mBits
-        + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
+    uint16_t *dst_ptr = (uint16_t *)dst.mBits
+        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
     const uint8_t *src_y = (const uint8_t *)src.mBits;
 
@@ -478,7 +487,11 @@
                 | ((kAdjustedClip[g2] >> 2) << 5)
                 | (kAdjustedClip[b2] >> 3);
 
-            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+            if (x + 1 < src.cropWidth()) {
+                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
+            } else {
+                dst_ptr[x] = rgb1;
+            }
         }
 
         src_y += src.mWidth;
@@ -487,7 +500,7 @@
             src_u += src.mWidth;
         }
 
-        dst_ptr += dst.mWidth / 2;
+        dst_ptr += dst.mWidth;
     }
 
     return OK;
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 82c6476..a7a3d47 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -41,7 +41,7 @@
 class DrmManagerClinet;
 class DecryptHandle;
 
-class TimedTextPlayer;
+class TimedTextDriver;
 struct WVMExtractor;
 
 struct AwesomeRenderer : public RefBase {
@@ -232,7 +232,7 @@
     sp<DecryptHandle> mDecryptHandle;
 
     int64_t mLastVideoTimeUs;
-    TimedTextPlayer *mTextPlayer;
+    TimedTextDriver *mTextDriver;
     mutable Mutex mTimedTextLock;
 
     sp<WVMExtractor> mWVMExtractor;
@@ -326,4 +326,3 @@
 }  // namespace android
 
 #endif  // AWESOME_PLAYER_H_
-
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index 53e764f..2c87b34 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -31,7 +31,7 @@
 public:
     OMX();
 
-    virtual bool livesLocally(pid_t pid);
+    virtual bool livesLocally(node_id node, pid_t pid);
 
     virtual status_t listNodes(List<ComponentInfo> *list);
 
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 694b12d8..ace883c 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -185,7 +185,7 @@
     instance->onObserverDied(mMaster);
 }
 
-bool OMX::livesLocally(pid_t pid) {
+bool OMX::livesLocally(node_id node, pid_t pid) {
     return pid == getpid();
 }
 
diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
index 0914f32..c79e01f 100644
--- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
@@ -333,8 +333,9 @@
 
 void SimpleSoftOMXComponent::onMessageReceived(const sp<AMessage> &msg) {
     Mutex::Autolock autoLock(mLock);
-
-    switch (msg->what()) {
+    uint32_t msgType = msg->what();
+    ALOGV("msgType = %d", msgType);
+    switch (msgType) {
         case kWhatSendCommand:
         {
             int32_t cmd, param;
@@ -354,27 +355,27 @@
             CHECK(mState == OMX_StateExecuting && mTargetState == mState);
 
             bool found = false;
-            for (size_t i = 0; i < mPorts.size(); ++i) {
-                PortInfo *port = &mPorts.editItemAt(i);
+            size_t portIndex = (kWhatEmptyThisBuffer == msgType)?
+                    header->nInputPortIndex: header->nOutputPortIndex;
+            PortInfo *port = &mPorts.editItemAt(portIndex);
 
-                for (size_t j = 0; j < port->mBuffers.size(); ++j) {
-                    BufferInfo *buffer = &port->mBuffers.editItemAt(j);
+            for (size_t j = 0; j < port->mBuffers.size(); ++j) {
+                BufferInfo *buffer = &port->mBuffers.editItemAt(j);
 
-                    if (buffer->mHeader == header) {
-                        CHECK(!buffer->mOwnedByUs);
+                if (buffer->mHeader == header) {
+                    CHECK(!buffer->mOwnedByUs);
 
-                        buffer->mOwnedByUs = true;
+                    buffer->mOwnedByUs = true;
 
-                        CHECK((msg->what() == kWhatEmptyThisBuffer
-                                    && port->mDef.eDir == OMX_DirInput)
-                                || (port->mDef.eDir == OMX_DirOutput));
+                    CHECK((msgType == kWhatEmptyThisBuffer
+                            && port->mDef.eDir == OMX_DirInput)
+                            || (port->mDef.eDir == OMX_DirOutput));
 
-                        port->mQueue.push_back(buffer);
-                        onQueueFilled(i);
+                    port->mQueue.push_back(buffer);
+                    onQueueFilled(portIndex);
 
-                        found = true;
-                        break;
-                    }
+                    found = true;
+                    break;
                 }
             }
 
diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp
index cf9e8c9..99ffe7d 100644
--- a/media/libstagefright/omx/SoftOMXPlugin.cpp
+++ b/media/libstagefright/omx/SoftOMXPlugin.cpp
@@ -37,7 +37,9 @@
     { "OMX.google.aac.decoder", "aacdec", "audio_decoder.aac" },
     { "OMX.google.aac.encoder", "aacenc", "audio_encoder.aac" },
     { "OMX.google.amrnb.decoder", "amrdec", "audio_decoder.amrnb" },
+    { "OMX.google.amrnb.encoder", "amrnbenc", "audio_encoder.amrnb" },
     { "OMX.google.amrwb.decoder", "amrdec", "audio_decoder.amrwb" },
+    { "OMX.google.amrwb.encoder", "amrwbenc", "audio_encoder.amrwb" },
     { "OMX.google.h264.decoder", "h264dec", "video_decoder.avc" },
     { "OMX.google.g711.alaw.decoder", "g711dec", "audio_decoder.g711alaw" },
     { "OMX.google.g711.mlaw.decoder", "g711dec", "audio_decoder.g711mlaw" },
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index bf69428..41c08be 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -7,11 +7,13 @@
 LOCAL_SHARED_LIBRARIES := \
 	libstagefright libbinder libmedia libutils
 
-LOCAL_C_INCLUDES:= \
+LOCAL_C_INCLUDES := \
 	$(JNI_H_INCLUDE) \
 	frameworks/base/media/libstagefright \
 	$(TOP)/frameworks/base/include/media/stagefright/openmax
 
-LOCAL_MODULE:= omx_tests
+LOCAL_MODULE := omx_tests
+
+LOCAL_MODULE_TAGS := tests
 
 include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk
index 59d0e15..8b23dee 100644
--- a/media/libstagefright/timedtext/Android.mk
+++ b/media/libstagefright/timedtext/Android.mk
@@ -3,7 +3,10 @@
 
 LOCAL_SRC_FILES:=                 \
         TextDescriptions.cpp      \
-        TimedTextParser.cpp       \
+        TimedTextDriver.cpp       \
+        TimedTextInBandSource.cpp \
+        TimedTextSource.cpp       \
+        TimedTextSRTSource.cpp    \
         TimedTextPlayer.cpp
 
 LOCAL_CFLAGS += -Wno-multichar
diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp
new file mode 100644
index 0000000..9ec9415
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextDriver.cpp
@@ -0,0 +1,223 @@
+ /*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "TimedTextDriver"
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/Utils.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+
+#include "TimedTextDriver.h"
+
+#include "TextDescriptions.h"
+#include "TimedTextPlayer.h"
+#include "TimedTextSource.h"
+
+namespace android {
+
+TimedTextDriver::TimedTextDriver(
+        const wp<MediaPlayerBase> &listener)
+    : mLooper(new ALooper),
+      mListener(listener),
+      mState(UNINITIALIZED) {
+    mLooper->setName("TimedTextDriver");
+    mLooper->start();
+    mPlayer = new TimedTextPlayer(listener);
+    mLooper->registerHandler(mPlayer);
+}
+
+TimedTextDriver::~TimedTextDriver() {
+    mTextInBandVector.clear();
+    mTextOutOfBandVector.clear();
+    mLooper->stop();
+}
+
+status_t TimedTextDriver::setTimedTextTrackIndex_l(int32_t index) {
+    if (index >=
+            (int)(mTextInBandVector.size() + mTextOutOfBandVector.size())) {
+        return BAD_VALUE;
+    }
+
+    sp<TimedTextSource> source;
+    if (index < mTextInBandVector.size()) {
+        source = mTextInBandVector.itemAt(index);
+    } else {
+        source = mTextOutOfBandVector.itemAt(index - mTextInBandVector.size());
+    }
+    mPlayer->setDataSource(source);
+    return OK;
+}
+
+status_t TimedTextDriver::start() {
+    Mutex::Autolock autoLock(mLock);
+    switch (mState) {
+        case UNINITIALIZED:
+            return INVALID_OPERATION;
+        case STOPPED:
+            mPlayer->start();
+            break;
+        case PLAYING:
+            return OK;
+        case PAUSED:
+            mPlayer->resume();
+            break;
+        default:
+            TRESPASS();
+    }
+    mState = PLAYING;
+    return OK;
+}
+
+status_t TimedTextDriver::stop() {
+    return pause();
+}
+
+// TODO: Test if pause() works properly.
+// Scenario 1: start - pause - resume
+// Scenario 2: start - seek
+// Scenario 3: start - pause - seek - resume
+status_t TimedTextDriver::pause() {
+    Mutex::Autolock autoLock(mLock);
+    switch (mState) {
+        case UNINITIALIZED:
+            return INVALID_OPERATION;
+        case STOPPED:
+            return OK;
+        case PLAYING:
+            mPlayer->pause();
+            break;
+        case PAUSED:
+            return OK;
+        default:
+            TRESPASS();
+    }
+    mState = PAUSED;
+    return OK;
+}
+
+status_t TimedTextDriver::resume() {
+    return start();
+}
+
+status_t TimedTextDriver::seekToAsync(int64_t timeUs) {
+    mPlayer->seekToAsync(timeUs);
+    return OK;
+}
+
+status_t TimedTextDriver::setTimedTextTrackIndex(int32_t index) {
+    // TODO: This is current implementation for MediaPlayer::disableTimedText().
+    // Find better way for readability.
+    if (index < 0) {
+        mPlayer->pause();
+        return OK;
+    }
+
+    status_t ret = OK;
+    Mutex::Autolock autoLock(mLock);
+    switch (mState) {
+        case UNINITIALIZED:
+            ret = INVALID_OPERATION;
+            break;
+        case PAUSED:
+            ret = setTimedTextTrackIndex_l(index);
+            break;
+        case PLAYING:
+            mPlayer->pause();
+            ret = setTimedTextTrackIndex_l(index);
+            if (ret != OK) {
+                break;
+            }
+            mPlayer->start();
+            break;
+        case STOPPED:
+            // TODO: The only difference between STOPPED and PAUSED is this
+            // part. Revise the flow from "MediaPlayer::enableTimedText()" and
+            // remove one of the status, PAUSED and STOPPED, if possible.
+            ret = setTimedTextTrackIndex_l(index);
+            if (ret != OK) {
+                break;
+            }
+            mPlayer->start();
+            break;
+        defaut:
+            TRESPASS();
+    }
+    return ret;
+}
+
+status_t TimedTextDriver::addInBandTextSource(
+        const sp<MediaSource>& mediaSource) {
+    sp<TimedTextSource> source =
+            TimedTextSource::CreateTimedTextSource(mediaSource);
+    if (source == NULL) {
+        return ERROR_UNSUPPORTED;
+    }
+    Mutex::Autolock autoLock(mLock);
+    mTextInBandVector.add(source);
+    if (mState == UNINITIALIZED) {
+        mState = STOPPED;
+    }
+    return OK;
+}
+
+status_t TimedTextDriver::addOutOfBandTextSource(
+        const Parcel &request) {
+    // TODO: Define "TimedTextSource::CreateFromURI(uri)"
+    // and move below lines there..?
+
+    // String values written in Parcel are UTF-16 values.
+    const String16 uri16 = request.readString16();
+    String8 uri = String8(request.readString16());
+
+    uri.toLower();
+    // To support local subtitle file only for now
+    if (strncasecmp("file://", uri.string(), 7)) {
+        return ERROR_UNSUPPORTED;
+    }
+    sp<DataSource> dataSource =
+            DataSource::CreateFromURI(uri);
+    if (dataSource == NULL) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    sp<TimedTextSource> source;
+    if (uri.getPathExtension() == String8(".srt")) {
+        source = TimedTextSource::CreateTimedTextSource(
+                dataSource, TimedTextSource::OUT_OF_BAND_FILE_SRT);
+    }
+
+    if (source == NULL) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    Mutex::Autolock autoLock(mLock);
+
+    mTextOutOfBandVector.add(source);
+    if (mState == UNINITIALIZED) {
+        mState = STOPPED;
+    }
+    return OK;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextDriver.h b/media/libstagefright/timedtext/TimedTextDriver.h
new file mode 100644
index 0000000..efedb6e
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextDriver.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TIMED_TEXT_DRIVER_H_
+#define TIMED_TEXT_DRIVER_H_
+
+#include <media/stagefright/foundation/ABase.h> // for DISALLOW_* macro
+#include <utils/Errors.h> // for status_t
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class ALooper;
+class MediaPlayerBase;
+class MediaSource;
+class Parcel;
+class TimedTextPlayer;
+class TimedTextSource;
+
+class TimedTextDriver {
+public:
+    TimedTextDriver(const wp<MediaPlayerBase> &listener);
+
+    ~TimedTextDriver();
+
+    // TODO: pause-resume pair seems equivalent to stop-start pair.
+    // Check if it is replaceable with stop-start.
+    status_t start();
+    status_t stop();
+    status_t pause();
+    status_t resume();
+
+    status_t seekToAsync(int64_t timeUs);
+
+    status_t addInBandTextSource(const sp<MediaSource>& source);
+    status_t addOutOfBandTextSource(const Parcel &request);
+
+    status_t setTimedTextTrackIndex(int32_t index);
+
+private:
+    Mutex mLock;
+
+    enum State {
+        UNINITIALIZED,
+        STOPPED,
+        PLAYING,
+        PAUSED,
+    };
+
+    sp<ALooper> mLooper;
+    sp<TimedTextPlayer> mPlayer;
+    wp<MediaPlayerBase> mListener;
+
+    // Variables to be guarded by mLock.
+    State mState;
+    Vector<sp<TimedTextSource> > mTextInBandVector;
+    Vector<sp<TimedTextSource> > mTextOutOfBandVector;
+    // -- End of variables to be guarded by mLock
+
+    status_t setTimedTextTrackIndex_l(int32_t index);
+
+    DISALLOW_EVIL_CONSTRUCTORS(TimedTextDriver);
+};
+
+}  // namespace android
+
+#endif  // TIMED_TEXT_DRIVER_H_
diff --git a/media/libstagefright/timedtext/TimedTextInBandSource.cpp b/media/libstagefright/timedtext/TimedTextInBandSource.cpp
new file mode 100644
index 0000000..f2c4d54
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextInBandSource.cpp
@@ -0,0 +1,118 @@
+ /*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "TimedTextInBandSource"
+#include <utils/Log.h>
+
+#include <binder/Parcel.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDebug.h>  // CHECK_XX macro
+#include <media/stagefright/MediaDefs.h>  // for MEDIA_MIMETYPE_xxx
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+
+#include "TimedTextInBandSource.h"
+#include "TextDescriptions.h"
+
+namespace android {
+
+TimedTextInBandSource::TimedTextInBandSource(const sp<MediaSource>& mediaSource)
+    : mSource(mediaSource) {
+}
+
+TimedTextInBandSource::~TimedTextInBandSource() {
+}
+
+status_t TimedTextInBandSource::read(
+        int64_t *timeUs, Parcel *parcel, const MediaSource::ReadOptions *options) {
+    MediaBuffer *textBuffer = NULL;
+    status_t err = mSource->read(&textBuffer, options);
+    if (err != OK) {
+        return err;
+    }
+    CHECK(textBuffer != NULL);
+    textBuffer->meta_data()->findInt64(kKeyTime, timeUs);
+    // TODO: this is legacy code. when 'timeUs' can be <= 0?
+    if (*timeUs > 0) {
+        extractAndAppendLocalDescriptions(*timeUs, textBuffer, parcel);
+    }
+    textBuffer->release();
+    return OK;
+}
+
+// Each text sample consists of a string of text, optionally with sample
+// modifier description. The modifier description could specify a new
+// text style for the string of text. These descriptions are present only
+// if they are needed. This method is used to extract the modifier
+// description and append it at the end of the text.
+status_t TimedTextInBandSource::extractAndAppendLocalDescriptions(
+        int64_t timeUs, const MediaBuffer *textBuffer, Parcel *parcel) {
+    const void *data;
+    size_t size = 0;
+    int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS;
+
+    const char *mime;
+    CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
+
+    if (strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) == 0) {
+        data = textBuffer->data();
+        size = textBuffer->size();
+
+        if (size > 0) {
+            parcel->freeData();
+            flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
+            return TextDescriptions::getParcelOfDescriptions(
+                    (const uint8_t *)data, size, flag, timeUs / 1000, parcel);
+        }
+        return OK;
+    }
+    return ERROR_UNSUPPORTED;
+}
+
+// To extract and send the global text descriptions for all the text samples
+// in the text track or text file.
+// TODO: send error message to application via notifyListener()...?
+status_t TimedTextInBandSource::extractGlobalDescriptions(Parcel *parcel) {
+    const void *data;
+    size_t size = 0;
+    int32_t flag = TextDescriptions::GLOBAL_DESCRIPTIONS;
+
+    const char *mime;
+    CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
+
+    // support 3GPP only for now
+    if (strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) == 0) {
+        uint32_t type;
+        // get the 'tx3g' box content. This box contains the text descriptions
+        // used to render the text track
+        if (!mSource->getFormat()->findData(
+                kKeyTextFormatData, &type, &data, &size)) {
+            return ERROR_MALFORMED;
+        }
+
+        if (size > 0) {
+            flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
+            return TextDescriptions::getParcelOfDescriptions(
+                    (const uint8_t *)data, size, flag, 0, parcel);
+        }
+        return OK;
+    }
+    return ERROR_UNSUPPORTED;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextInBandSource.h b/media/libstagefright/timedtext/TimedTextInBandSource.h
new file mode 100644
index 0000000..26e5737
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextInBandSource.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TIMED_TEXT_IN_BAND_SOURCE_H_
+#define TIMED_TEXT_IN_BAND_SOURCE_H_
+
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+
+#include "TimedTextSource.h"
+
+namespace android {
+
+class MediaBuffer;
+class Parcel;
+
+class TimedTextInBandSource : public TimedTextSource {
+ public:
+  TimedTextInBandSource(const sp<MediaSource>& mediaSource);
+  virtual status_t start() { return mSource->start(); }
+  virtual status_t stop() { return mSource->stop(); }
+  virtual status_t read(
+          int64_t *timeUs,
+          Parcel *parcel,
+          const MediaSource::ReadOptions *options = NULL);
+  virtual status_t extractGlobalDescriptions(Parcel *parcel);
+
+ protected:
+  virtual ~TimedTextInBandSource();
+
+ private:
+  sp<MediaSource> mSource;
+
+  status_t extractAndAppendLocalDescriptions(
+        int64_t timeUs, const MediaBuffer *textBuffer, Parcel *parcel);
+
+  DISALLOW_EVIL_CONSTRUCTORS(TimedTextInBandSource);
+};
+
+}  // namespace android
+
+#endif  // TIMED_TEXT_IN_BAND_SOURCE_H_
diff --git a/media/libstagefright/timedtext/TimedTextParser.cpp b/media/libstagefright/timedtext/TimedTextParser.cpp
deleted file mode 100644
index caea0a4..0000000
--- a/media/libstagefright/timedtext/TimedTextParser.cpp
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * 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.
- */
-
-#include "TimedTextParser.h"
-#include <media/stagefright/DataSource.h>
-
-namespace android {
-
-TimedTextParser::TimedTextParser()
-    : mDataSource(NULL),
-      mOffset(0),
-      mIndex(0) {
-}
-
-TimedTextParser::~TimedTextParser() {
-    reset();
-}
-
-status_t TimedTextParser::init(
-        const sp<DataSource> &dataSource, FileType fileType) {
-    mDataSource = dataSource;
-    mFileType = fileType;
-
-    status_t err;
-    if ((err = scanFile()) != OK) {
-        reset();
-        return err;
-    }
-
-    return OK;
-}
-
-void TimedTextParser::reset() {
-    mDataSource.clear();
-    mTextVector.clear();
-    mOffset = 0;
-    mIndex = 0;
-}
-
-// scan the text file to get start/stop time and the
-// offset of each piece of text content
-status_t TimedTextParser::scanFile() {
-    if (mFileType != OUT_OF_BAND_FILE_SRT) {
-        return ERROR_UNSUPPORTED;
-    }
-
-    off64_t offset = 0;
-    int64_t startTimeUs;
-    bool endOfFile = false;
-
-    while (!endOfFile) {
-        TextInfo info;
-        status_t err = getNextInSrtFileFormat(&offset, &startTimeUs, &info);
-
-        if (err != OK) {
-            if (err == ERROR_END_OF_STREAM) {
-                endOfFile = true;
-            } else {
-                return err;
-            }
-        } else {
-            mTextVector.add(startTimeUs, info);
-        }
-    }
-
-    if (mTextVector.isEmpty()) {
-        return ERROR_MALFORMED;
-    }
-    return OK;
-}
-
-// read one line started from *offset and store it into data.
-status_t TimedTextParser::readNextLine(off64_t *offset, AString *data) {
-    char character;
-
-    data->clear();
-
-    while (true) {
-        ssize_t err;
-        if ((err = mDataSource->readAt(*offset, &character, 1)) < 1) {
-            if (err == 0) {
-                return ERROR_END_OF_STREAM;
-            }
-            return ERROR_IO;
-        }
-
-        (*offset) ++;
-
-        // a line could end with CR, LF or CR + LF
-        if (character == 10) {
-            break;
-        } else if (character == 13) {
-            if ((err = mDataSource->readAt(*offset, &character, 1)) < 1) {
-                if (err == 0) { // end of the stream
-                    return OK;
-                }
-                return ERROR_IO;
-            }
-
-            (*offset) ++;
-
-            if (character != 10) {
-                (*offset) --;
-            }
-            break;
-        }
-
-        data->append(character);
-    }
-
-    return OK;
-}
-
-/* SRT format:
- *  Subtitle number
- *  Start time --> End time
- *  Text of subtitle (one or more lines)
- *  Blank lines
- *
- * .srt file example:
- *  1
- *  00:00:20,000 --> 00:00:24,400
- *  Altocumulus clouds occur between six thousand
- *
- *  2
- *  00:00:24,600 --> 00:00:27,800
- *  and twenty thousand feet above ground level.
- */
-status_t TimedTextParser::getNextInSrtFileFormat(
-        off64_t *offset, int64_t *startTimeUs, TextInfo *info) {
-    AString data;
-    status_t err;
-
-    // To skip blank lines.
-    do {
-        if ((err = readNextLine(offset, &data)) != OK) {
-            return err;
-        }
-        data.trim();
-    } while(data.empty());
-
-    // Just ignore the first non-blank line which is subtitle sequence number.
-
-    if ((err = readNextLine(offset, &data)) != OK) {
-        return err;
-    }
-    int hour1, hour2, min1, min2, sec1, sec2, msec1, msec2;
-    // the start time format is: hours:minutes:seconds,milliseconds
-    // 00:00:24,600 --> 00:00:27,800
-    if (sscanf(data.c_str(), "%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d",
-                &hour1, &min1, &sec1, &msec1, &hour2, &min2, &sec2, &msec2) != 8) {
-        return ERROR_MALFORMED;
-    }
-
-    *startTimeUs = ((hour1 * 3600 + min1 * 60 + sec1) * 1000 + msec1) * 1000ll;
-    info->endTimeUs = ((hour2 * 3600 + min2 * 60 + sec2) * 1000 + msec2) * 1000ll;
-    if (info->endTimeUs <= *startTimeUs) {
-        return ERROR_MALFORMED;
-    }
-
-    info->offset = *offset;
-
-    bool needMoreData = true;
-    while (needMoreData) {
-        if ((err = readNextLine(offset, &data)) != OK) {
-            if (err == ERROR_END_OF_STREAM) {
-                needMoreData = false;
-            } else {
-                return err;
-            }
-        }
-
-        if (needMoreData) {
-            data.trim();
-            if (data.empty()) {
-                // it's an empty line used to separate two subtitles
-                needMoreData = false;
-            }
-        }
-    }
-
-    info->textLen = *offset - info->offset;
-
-    return OK;
-}
-
-status_t TimedTextParser::getText(
-        AString *text, int64_t *startTimeUs, int64_t *endTimeUs,
-        const MediaSource::ReadOptions *options) {
-    Mutex::Autolock autoLock(mLock);
-
-    text->clear();
-
-    int64_t seekTimeUs;
-    MediaSource::ReadOptions::SeekMode mode;
-    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
-        int64_t lastEndTimeUs = mTextVector.valueAt(mTextVector.size() - 1).endTimeUs;
-        int64_t firstStartTimeUs = mTextVector.keyAt(0);
-
-        if (seekTimeUs < 0 || seekTimeUs > lastEndTimeUs) {
-            return ERROR_OUT_OF_RANGE;
-        } else if (seekTimeUs < firstStartTimeUs) {
-            mIndex = 0;
-        } else {
-            // binary search
-            ssize_t low = 0;
-            ssize_t high = mTextVector.size() - 1;
-            ssize_t mid = 0;
-            int64_t currTimeUs;
-
-            while (low <= high) {
-                mid = low + (high - low)/2;
-                currTimeUs = mTextVector.keyAt(mid);
-                const int diff = currTimeUs - seekTimeUs;
-
-                if (diff == 0) {
-                    break;
-                } else if (diff < 0) {
-                    low = mid + 1;
-                } else {
-                    if ((high == mid + 1)
-                            && (seekTimeUs < mTextVector.keyAt(high))) {
-                        break;
-                    }
-                    high = mid - 1;
-                }
-            }
-
-            mIndex = mid;
-        }
-    }
-
-    TextInfo info = mTextVector.valueAt(mIndex);
-    *startTimeUs = mTextVector.keyAt(mIndex);
-    *endTimeUs = info.endTimeUs;
-    mIndex ++;
-
-    char *str = new char[info.textLen];
-    if (mDataSource->readAt(info.offset, str, info.textLen) < info.textLen) {
-        delete[] str;
-        return ERROR_IO;
-    }
-
-    text->append(str, info.textLen);
-    delete[] str;
-    return OK;
-}
-
-}  // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextParser.h b/media/libstagefright/timedtext/TimedTextParser.h
deleted file mode 100644
index 44774c2..0000000
--- a/media/libstagefright/timedtext/TimedTextParser.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef TIMED_TEXT_PARSER_H_
-
-#define TIMED_TEXT_PARSER_H_
-
-#include <media/MediaPlayerInterface.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/MediaSource.h>
-
-namespace android {
-
-class DataSource;
-
-class TimedTextParser : public RefBase {
-public:
-    TimedTextParser();
-    virtual ~TimedTextParser();
-
-    enum FileType {
-        OUT_OF_BAND_FILE_SRT = 1,
-    };
-
-    status_t getText(AString *text, int64_t *startTimeUs, int64_t *endTimeUs,
-                     const MediaSource::ReadOptions *options = NULL);
-    status_t init(const sp<DataSource> &dataSource, FileType fileType);
-    void reset();
-
-private:
-    Mutex mLock;
-
-    sp<DataSource> mDataSource;
-    off64_t mOffset;
-
-    struct TextInfo {
-        int64_t endTimeUs;
-        // the offset of the text in the original file
-        off64_t offset;
-        int textLen;
-    };
-
-    int mIndex;
-    FileType mFileType;
-
-    // the key indicated the start time of the text
-    KeyedVector<int64_t, TextInfo> mTextVector;
-
-    status_t getNextInSrtFileFormat(
-            off64_t *offset, int64_t *startTimeUs, TextInfo *info);
-    status_t readNextLine(off64_t *offset, AString *data);
-
-    status_t scanFile();
-
-    DISALLOW_EVIL_CONSTRUCTORS(TimedTextParser);
-};
-
-}  // namespace android
-
-#endif  // TIMED_TEXT_PARSER_H_
-
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp
index 3014b0b..8c2df88 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.cpp
+++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp
@@ -1,5 +1,5 @@
  /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2012 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.
@@ -18,399 +18,164 @@
 #define LOG_TAG "TimedTextPlayer"
 #include <utils/Log.h>
 
-#include <binder/IPCThreadState.h>
-
+#include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/Utils.h>
+#include <media/MediaPlayerInterface.h>
 
-#include "include/AwesomePlayer.h"
 #include "TimedTextPlayer.h"
-#include "TimedTextParser.h"
-#include "TextDescriptions.h"
+
+#include "TimedTextDriver.h"
+#include "TimedTextSource.h"
 
 namespace android {
 
-struct TimedTextEvent : public TimedEventQueue::Event {
-    TimedTextEvent(
-            TimedTextPlayer *player,
-            void (TimedTextPlayer::*method)())
-        : mPlayer(player),
-          mMethod(method) {
-    }
+static const int64_t kAdjustmentProcessingTimeUs = 100000ll;
 
-protected:
-    virtual ~TimedTextEvent() {}
-
-    virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
-        (mPlayer->*mMethod)();
-    }
-
-private:
-    TimedTextPlayer *mPlayer;
-    void (TimedTextPlayer::*mMethod)();
-
-    TimedTextEvent(const TimedTextEvent &);
-    TimedTextEvent &operator=(const TimedTextEvent &);
-};
-
-TimedTextPlayer::TimedTextPlayer(
-        AwesomePlayer *observer,
-        const wp<MediaPlayerBase> &listener,
-        TimedEventQueue *queue)
-    : mSource(NULL),
-      mOutOfBandSource(NULL),
-      mSeekTimeUs(0),
-      mStarted(false),
-      mTextEventPending(false),
-      mQueue(queue),
-      mListener(listener),
-      mObserver(observer),
-      mTextBuffer(NULL),
-      mTextParser(NULL),
-      mTextType(kNoText) {
-    mTextEvent = new TimedTextEvent(this, &TimedTextPlayer::onTextEvent);
+TimedTextPlayer::TimedTextPlayer(const wp<MediaPlayerBase> &listener)
+    : mListener(listener),
+      mSource(NULL),
+      mSendSubtitleGeneration(0) {
 }
 
 TimedTextPlayer::~TimedTextPlayer() {
-    if (mStarted) {
-        reset();
+    if (mSource != NULL) {
+        mSource->stop();
+        mSource.clear();
+        mSource = NULL;
     }
-
-    mTextTrackVector.clear();
-    mTextOutOfBandVector.clear();
 }
 
-status_t TimedTextPlayer::start(uint8_t index) {
-    CHECK(!mStarted);
-
-    if (index >=
-            mTextTrackVector.size() + mTextOutOfBandVector.size()) {
-        ALOGE("Incorrect text track index: %d", index);
-        return BAD_VALUE;
-    }
-
-    status_t err;
-    if (index < mTextTrackVector.size()) { // start an in-band text
-        mSource = mTextTrackVector.itemAt(index);
-
-        err = mSource->start();
-
-        if (err != OK) {
-            return err;
-        }
-        mTextType = kInBandText;
-    } else { // start an out-of-band text
-        OutOfBandText text =
-            mTextOutOfBandVector.itemAt(index - mTextTrackVector.size());
-
-        mOutOfBandSource = text.source;
-        TimedTextParser::FileType fileType = text.type;
-
-        if (mTextParser == NULL) {
-            mTextParser = new TimedTextParser();
-        }
-
-        if ((err = mTextParser->init(mOutOfBandSource, fileType)) != OK) {
-            return err;
-        }
-        mTextType = kOutOfBandText;
-    }
-
-    // send sample description format
-    if ((err = extractAndSendGlobalDescriptions()) != OK) {
-        return err;
-    }
-
-    int64_t positionUs;
-    mObserver->getPosition(&positionUs);
-    seekTo(positionUs);
-
-    postTextEvent();
-
-    mStarted = true;
-
-    return OK;
+void TimedTextPlayer::start() {
+    sp<AMessage> msg = new AMessage(kWhatSeek, id());
+    msg->setInt64("seekTimeUs", -1);
+    msg->post();
 }
 
 void TimedTextPlayer::pause() {
-    CHECK(mStarted);
-
-    cancelTextEvent();
+    (new AMessage(kWhatPause, id()))->post();
 }
 
 void TimedTextPlayer::resume() {
-    CHECK(mStarted);
-
-    postTextEvent();
+    start();
 }
 
-void TimedTextPlayer::reset() {
-    CHECK(mStarted);
+void TimedTextPlayer::seekToAsync(int64_t timeUs) {
+    sp<AMessage> msg = new AMessage(kWhatSeek, id());
+    msg->setInt64("seekTimeUs", timeUs);
+    msg->post();
+}
 
-    // send an empty text to clear the screen
-    notifyListener(MEDIA_TIMED_TEXT);
+void TimedTextPlayer::setDataSource(sp<TimedTextSource> source) {
+    sp<AMessage> msg = new AMessage(kWhatSetSource, id());
+    msg->setObject("source", source);
+    msg->post();
+}
 
-    cancelTextEvent();
-
-    mSeeking = false;
-    mStarted = false;
-
-    if (mTextType == kInBandText) {
-        if (mTextBuffer != NULL) {
-            mTextBuffer->release();
-            mTextBuffer = NULL;
+void TimedTextPlayer::onMessageReceived(const sp<AMessage> &msg) {
+    switch (msg->what()) {
+        case kWhatPause: {
+            mSendSubtitleGeneration++;
+            break;
         }
-
-        if (mSource != NULL) {
-            mSource->stop();
-            mSource.clear();
-            mSource = NULL;
+        case kWhatSeek: {
+            int64_t seekTimeUs = 0;
+            msg->findInt64("seekTimeUs", &seekTimeUs);
+            if (seekTimeUs < 0) {
+                sp<MediaPlayerBase> listener = mListener.promote();
+                if (listener != NULL) {
+                    int32_t positionMs = 0;
+                    listener->getCurrentPosition(&positionMs);
+                    seekTimeUs = positionMs * 1000ll;
+                }
+            }
+            doSeekAndRead(seekTimeUs);
+            break;
         }
-    } else {
-        if (mTextParser != NULL) {
-            mTextParser.clear();
-            mTextParser = NULL;
+        case kWhatSendSubtitle: {
+            int32_t generation;
+            CHECK(msg->findInt32("generation", &generation));
+            if (generation != mSendSubtitleGeneration) {
+              // Drop obsolete msg.
+              break;
+            }
+            sp<RefBase> obj;
+            msg->findObject("subtitle", &obj);
+            if (obj != NULL) {
+                sp<ParcelEvent> parcelEvent;
+                parcelEvent = static_cast<ParcelEvent*>(obj.get());
+                notifyListener(MEDIA_TIMED_TEXT, &(parcelEvent->parcel));
+            } else {
+                notifyListener(MEDIA_TIMED_TEXT);
+            }
+            doRead();
+            break;
         }
-        if (mOutOfBandSource != NULL) {
-            mOutOfBandSource.clear();
-            mOutOfBandSource = NULL;
+        case kWhatSetSource: {
+            sp<RefBase> obj;
+            msg->findObject("source", &obj);
+            if (obj == NULL) break;
+            if (mSource != NULL) {
+                mSource->stop();
+            }
+            mSource = static_cast<TimedTextSource*>(obj.get());
+            mSource->start();
+            Parcel parcel;
+            if (mSource->extractGlobalDescriptions(&parcel) == OK &&
+                parcel.dataSize() > 0) {
+                notifyListener(MEDIA_TIMED_TEXT, &parcel);
+            } else {
+                notifyListener(MEDIA_TIMED_TEXT);
+            }
+            break;
         }
     }
 }
 
-status_t TimedTextPlayer::seekTo(int64_t time_us) {
-    Mutex::Autolock autoLock(mLock);
-
-    mSeeking = true;
-    mSeekTimeUs = time_us;
-
-    postTextEvent();
-
-    return OK;
-}
-
-status_t TimedTextPlayer::setTimedTextTrackIndex(int32_t index) {
-    if (index >=
-            (int)(mTextTrackVector.size() + mTextOutOfBandVector.size())) {
-        return BAD_VALUE;
-    }
-
-    if (mStarted) {
-        reset();
-    }
-
-    if (index >= 0) {
-        return start(index);
-    }
-    return OK;
-}
-
-void TimedTextPlayer::onTextEvent() {
-    Mutex::Autolock autoLock(mLock);
-
-    if (!mTextEventPending) {
-        return;
-    }
-    mTextEventPending = false;
-
-    if (mData.dataSize() > 0) {
-        notifyListener(MEDIA_TIMED_TEXT, &mData);
-        mData.freeData();
-    }
-
+void TimedTextPlayer::doSeekAndRead(int64_t seekTimeUs) {
     MediaSource::ReadOptions options;
-    if (mSeeking) {
-        options.setSeekTo(mSeekTimeUs,
-                MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
-        mSeeking = false;
-
-        notifyListener(MEDIA_TIMED_TEXT); //empty text to clear the screen
-    }
-
-    int64_t positionUs, timeUs;
-    mObserver->getPosition(&positionUs);
-
-    if (mTextType == kInBandText) {
-        if (mSource->read(&mTextBuffer, &options) != OK) {
-            return;
-        }
-
-        mTextBuffer->meta_data()->findInt64(kKeyTime, &timeUs);
-    } else {
-        int64_t endTimeUs;
-        if (mTextParser->getText(
-                    &mText, &timeUs, &endTimeUs, &options) != OK) {
-            return;
-        }
-    }
-
-    if (timeUs > 0) {
-        extractAndAppendLocalDescriptions(timeUs);
-    }
-
-    if (mTextType == kInBandText) {
-        if (mTextBuffer != NULL) {
-            mTextBuffer->release();
-            mTextBuffer = NULL;
-        }
-    } else {
-        mText.clear();
-    }
-
-    //send the text now
-    if (timeUs <= positionUs + 100000ll) {
-        postTextEvent();
-    } else {
-        postTextEvent(timeUs - positionUs - 100000ll);
-    }
+    options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+    doRead(&options);
 }
 
-void TimedTextPlayer::postTextEvent(int64_t delayUs) {
-    if (mTextEventPending) {
-        return;
-    }
-
-    mTextEventPending = true;
-    mQueue->postEventWithDelay(mTextEvent, delayUs < 0 ? 10000 : delayUs);
+void TimedTextPlayer::doRead(MediaSource::ReadOptions* options) {
+    int64_t timeUs = 0;
+    sp<ParcelEvent> parcelEvent = new ParcelEvent();
+    mSource->read(&timeUs, &(parcelEvent->parcel), options);
+    postTextEvent(parcelEvent, timeUs);
 }
 
-void TimedTextPlayer::cancelTextEvent() {
-    mQueue->cancelEvent(mTextEvent->eventID());
-    mTextEventPending = false;
-}
+void TimedTextPlayer::postTextEvent(const sp<ParcelEvent>& parcel, int64_t timeUs) {
+    sp<MediaPlayerBase> listener = mListener.promote();
+    if (listener != NULL) {
+        int64_t positionUs, delayUs;
+        int32_t positionMs = 0;
+        listener->getCurrentPosition(&positionMs);
+        positionUs = positionMs * 1000;
 
-void TimedTextPlayer::addTextSource(sp<MediaSource> source) {
-    Mutex::Autolock autoLock(mLock);
-    mTextTrackVector.add(source);
-}
-
-status_t TimedTextPlayer::setParameter(int key, const Parcel &request) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (key == KEY_PARAMETER_TIMED_TEXT_ADD_OUT_OF_BAND_SOURCE) {
-        const String16 uri16 = request.readString16();
-        String8 uri = String8(uri16);
-        KeyedVector<String8, String8> headers;
-
-        // To support local subtitle file only for now
-        if (strncasecmp("file://", uri.string(), 7)) {
-            return INVALID_OPERATION;
-        }
-        sp<DataSource> dataSource =
-            DataSource::CreateFromURI(uri, &headers);
-        status_t err = dataSource->initCheck();
-
-        if (err != OK) {
-            return err;
-        }
-
-        OutOfBandText text;
-        text.source = dataSource;
-        if (uri.getPathExtension() == String8(".srt")) {
-            text.type = TimedTextParser::OUT_OF_BAND_FILE_SRT;
+        if (timeUs <= positionUs + kAdjustmentProcessingTimeUs) {
+            delayUs = 0;
         } else {
-            return ERROR_UNSUPPORTED;
+            delayUs = timeUs - positionUs - kAdjustmentProcessingTimeUs;
         }
-
-        mTextOutOfBandVector.add(text);
-
-        return OK;
+        sp<AMessage> msg = new AMessage(kWhatSendSubtitle, id());
+        msg->setInt32("generation", mSendSubtitleGeneration);
+        if (parcel != NULL) {
+            msg->setObject("subtitle", parcel);
+        }
+        msg->post(delayUs);
     }
-    return INVALID_OPERATION;
 }
 
 void TimedTextPlayer::notifyListener(int msg, const Parcel *parcel) {
-    if (mListener != NULL) {
-        sp<MediaPlayerBase> listener = mListener.promote();
-
-        if (listener != NULL) {
-            if (parcel && (parcel->dataSize() > 0)) {
-                listener->sendEvent(msg, 0, 0, parcel);
-            } else { // send an empty timed text to clear the screen
-                listener->sendEvent(msg);
-            }
+    sp<MediaPlayerBase> listener = mListener.promote();
+    if (listener != NULL) {
+        if (parcel != NULL && (parcel->dataSize() > 0)) {
+            listener->sendEvent(msg, 0, 0, parcel);
+        } else {  // send an empty timed text to clear the screen
+            listener->sendEvent(msg);
         }
     }
 }
 
-// Each text sample consists of a string of text, optionally with sample
-// modifier description. The modifier description could specify a new
-// text style for the string of text. These descriptions are present only
-// if they are needed. This method is used to extract the modifier
-// description and append it at the end of the text.
-status_t TimedTextPlayer::extractAndAppendLocalDescriptions(int64_t timeUs) {
-    const void *data;
-    size_t size = 0;
-    int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS;
-
-    if (mTextType == kInBandText) {
-        const char *mime;
-        CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
-
-        if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
-            flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
-            data = mTextBuffer->data();
-            size = mTextBuffer->size();
-        } else {
-            // support 3GPP only for now
-            return ERROR_UNSUPPORTED;
-        }
-    } else {
-        data = mText.c_str();
-        size = mText.size();
-        flag |= TextDescriptions::OUT_OF_BAND_TEXT_SRT;
-    }
-
-    if ((size > 0) && (flag != TextDescriptions::LOCAL_DESCRIPTIONS)) {
-        mData.freeData();
-        return TextDescriptions::getParcelOfDescriptions(
-                (const uint8_t *)data, size, flag, timeUs / 1000, &mData);
-    }
-
-    return OK;
-}
-
-// To extract and send the global text descriptions for all the text samples
-// in the text track or text file.
-status_t TimedTextPlayer::extractAndSendGlobalDescriptions() {
-    const void *data;
-    size_t size = 0;
-    int32_t flag = TextDescriptions::GLOBAL_DESCRIPTIONS;
-
-    if (mTextType == kInBandText) {
-        const char *mime;
-        CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
-
-        // support 3GPP only for now
-        if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
-            uint32_t type;
-            // get the 'tx3g' box content. This box contains the text descriptions
-            // used to render the text track
-            if (!mSource->getFormat()->findData(
-                        kKeyTextFormatData, &type, &data, &size)) {
-                return ERROR_MALFORMED;
-            }
-
-            flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
-        }
-    }
-
-    if ((size > 0) && (flag != TextDescriptions::GLOBAL_DESCRIPTIONS)) {
-        Parcel parcel;
-        if (TextDescriptions::getParcelOfDescriptions(
-                (const uint8_t *)data, size, flag, 0, &parcel) == OK) {
-            if (parcel.dataSize() > 0) {
-                notifyListener(MEDIA_TIMED_TEXT, &parcel);
-            }
-        }
-    }
-
-    return OK;
-}
-}
+}  // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.h b/media/libstagefright/timedtext/TimedTextPlayer.h
index a744db5..837beeb 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.h
+++ b/media/libstagefright/timedtext/TimedTextPlayer.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2012 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.
@@ -15,99 +15,61 @@
  */
 
 #ifndef TIMEDTEXT_PLAYER_H_
-
 #define TIMEDTEXT_PLAYER_H_
 
-#include <media/MediaPlayerInterface.h>
+#include <binder/Parcel.h>
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/RefBase.h>
 
-#include "include/TimedEventQueue.h"
-#include "TimedTextParser.h"
+#include "TimedTextSource.h"
 
 namespace android {
 
-class MediaSource;
-class AwesomePlayer;
-class MediaBuffer;
+class AMessage;
+class MediaPlayerBase;
+class TimedTextDriver;
+class TimedTextSource;
 
-class TimedTextPlayer {
+class TimedTextPlayer : public AHandler {
 public:
-    TimedTextPlayer(AwesomePlayer *observer,
-                    const wp<MediaPlayerBase> &listener,
-                    TimedEventQueue *queue);
+    TimedTextPlayer(const wp<MediaPlayerBase> &listener);
 
     virtual ~TimedTextPlayer();
 
-    // index: the index of the text track which will
-    // be turned on
-    status_t start(uint8_t index);
-
+    void start();
     void pause();
-
     void resume();
+    void seekToAsync(int64_t timeUs);
+    void setDataSource(sp<TimedTextSource> source);
 
-    status_t seekTo(int64_t time_us);
-
-    void addTextSource(sp<MediaSource> source);
-
-    status_t setTimedTextTrackIndex(int32_t index);
-    status_t setParameter(int key, const Parcel &request);
+protected:
+    virtual void onMessageReceived(const sp<AMessage> &msg);
 
 private:
-    enum TextType {
-        kNoText        = 0,
-        kInBandText    = 1,
-        kOutOfBandText = 2,
+    enum {
+        kWhatPause = 'paus',
+        kWhatSeek = 'seek',
+        kWhatSendSubtitle = 'send',
+        kWhatSetSource = 'ssrc',
     };
 
-    Mutex mLock;
-
-    sp<MediaSource> mSource;
-    sp<DataSource> mOutOfBandSource;
-
-    bool mSeeking;
-    int64_t mSeekTimeUs;
-
-    bool mStarted;
-
-    sp<TimedEventQueue::Event> mTextEvent;
-    bool mTextEventPending;
-
-    TimedEventQueue *mQueue;
+    // To add Parcel into an AMessage as an object, it should be 'RefBase'.
+    struct ParcelEvent : public RefBase {
+        Parcel parcel;
+    };
 
     wp<MediaPlayerBase> mListener;
-    AwesomePlayer *mObserver;
+    sp<TimedTextSource> mSource;
+    int32_t mSendSubtitleGeneration;
 
-    MediaBuffer *mTextBuffer;
-    Parcel mData;
-
-    // for in-band timed text
-    Vector<sp<MediaSource> > mTextTrackVector;
-
-    // for out-of-band timed text
-    struct OutOfBandText {
-        TimedTextParser::FileType type;
-        sp<DataSource> source;
-    };
-    Vector<OutOfBandText > mTextOutOfBandVector;
-
-    sp<TimedTextParser> mTextParser;
-    AString mText;
-
-    TextType mTextType;
-
-    void reset();
-
+    void doSeekAndRead(int64_t seekTimeUs);
+    void doRead(MediaSource::ReadOptions* options = NULL);
     void onTextEvent();
-    void postTextEvent(int64_t delayUs = -1);
-    void cancelTextEvent();
-
+    void postTextEvent(const sp<ParcelEvent>& parcel = NULL, int64_t timeUs = -1);
     void notifyListener(int msg, const Parcel *parcel = NULL);
 
-    status_t extractAndAppendLocalDescriptions(int64_t timeUs);
-    status_t extractAndSendGlobalDescriptions();
-
     DISALLOW_EVIL_CONSTRUCTORS(TimedTextPlayer);
 };
 
diff --git a/media/libstagefright/timedtext/TimedTextSRTSource.cpp b/media/libstagefright/timedtext/TimedTextSRTSource.cpp
new file mode 100644
index 0000000..3752d34
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextSRTSource.cpp
@@ -0,0 +1,275 @@
+ /*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "TimedTextSRTSource"
+#include <utils/Log.h>
+
+#include <binder/Parcel.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+
+#include "TimedTextSRTSource.h"
+#include "TextDescriptions.h"
+
+namespace android {
+
+TimedTextSRTSource::TimedTextSRTSource(const sp<DataSource>& dataSource)
+        : mSource(dataSource),
+          mIndex(0) {
+}
+
+TimedTextSRTSource::~TimedTextSRTSource() {
+}
+
+status_t TimedTextSRTSource::start() {
+    status_t err = scanFile();
+    if (err != OK) {
+        reset();
+    }
+    return err;
+}
+
+void TimedTextSRTSource::reset() {
+    mTextVector.clear();
+    mIndex = 0;
+}
+
+status_t TimedTextSRTSource::stop() {
+    reset();
+    return OK;
+}
+
+status_t TimedTextSRTSource::read(
+        int64_t *timeUs,
+        Parcel *parcel,
+        const MediaSource::ReadOptions *options) {
+    int64_t endTimeUs;
+    AString text;
+    status_t err = getText(options, &text, timeUs, &endTimeUs);
+    if (err != OK) {
+        return err;
+    }
+
+    if (*timeUs > 0) {
+        extractAndAppendLocalDescriptions(*timeUs, text, parcel);
+    }
+    return OK;
+}
+
+status_t TimedTextSRTSource::scanFile() {
+    off64_t offset = 0;
+    int64_t startTimeUs;
+    bool endOfFile = false;
+
+    while (!endOfFile) {
+        TextInfo info;
+        status_t err = getNextSubtitleInfo(&offset, &startTimeUs, &info);
+        switch (err) {
+            case OK:
+                mTextVector.add(startTimeUs, info);
+                break;
+            case ERROR_END_OF_STREAM:
+                endOfFile = true;
+                break;
+            default:
+                return err;
+        }
+    }
+    if (mTextVector.isEmpty()) {
+        return ERROR_MALFORMED;
+    }
+    return OK;
+}
+
+/* SRT format:
+ *   Subtitle number
+ *   Start time --> End time
+ *   Text of subtitle (one or more lines)
+ *   Blank lines
+ *
+ * .srt file example:
+ * 1
+ * 00:00:20,000 --> 00:00:24,400
+ * Altocumulus clouds occr between six thousand
+ *
+ * 2
+ * 00:00:24,600 --> 00:00:27,800
+ * and twenty thousand feet above ground level.
+ */
+status_t TimedTextSRTSource::getNextSubtitleInfo(
+          off64_t *offset, int64_t *startTimeUs, TextInfo *info) {
+    AString data;
+    status_t err;
+
+    // To skip blank lines.
+    do {
+        if ((err = readNextLine(offset, &data)) != OK) {
+            return err;
+        }
+        data.trim();
+    } while (data.empty());
+
+    // Just ignore the first non-blank line which is subtitle sequence number.
+    if ((err = readNextLine(offset, &data)) != OK) {
+        return err;
+    }
+    int hour1, hour2, min1, min2, sec1, sec2, msec1, msec2;
+    // the start time format is: hours:minutes:seconds,milliseconds
+    // 00:00:24,600 --> 00:00:27,800
+    if (sscanf(data.c_str(), "%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d",
+               &hour1, &min1, &sec1, &msec1, &hour2, &min2, &sec2, &msec2) != 8) {
+        return ERROR_MALFORMED;
+    }
+
+    *startTimeUs = ((hour1 * 3600 + min1 * 60 + sec1) * 1000 + msec1) * 1000ll;
+    info->endTimeUs = ((hour2 * 3600 + min2 * 60 + sec2) * 1000 + msec2) * 1000ll;
+    if (info->endTimeUs <= *startTimeUs) {
+        return ERROR_MALFORMED;
+    }
+
+    info->offset = *offset;
+    bool needMoreData = true;
+    while (needMoreData) {
+        if ((err = readNextLine(offset, &data)) != OK) {
+            if (err == ERROR_END_OF_STREAM) {
+                needMoreData = false;
+            } else {
+                return err;
+            }
+        }
+
+        if (needMoreData) {
+            data.trim();
+            if (data.empty()) {
+                // it's an empty line used to separate two subtitles
+                needMoreData = false;
+            }
+        }
+    }
+    info->textLen = *offset - info->offset;
+    return OK;
+}
+
+status_t TimedTextSRTSource::readNextLine(off64_t *offset, AString *data) {
+    data->clear();
+    while (true) {
+        ssize_t readSize;
+        char character;
+        if ((readSize = mSource->readAt(*offset, &character, 1)) < 1) {
+            if (readSize == 0) {
+                return ERROR_END_OF_STREAM;
+            }
+            return ERROR_IO;
+        }
+
+        (*offset)++;
+
+        // a line could end with CR, LF or CR + LF
+        if (character == 10) {
+            break;
+        } else if (character == 13) {
+            if ((readSize = mSource->readAt(*offset, &character, 1)) < 1) {
+                if (readSize == 0) {  // end of the stream
+                    return OK;
+                }
+                return ERROR_IO;
+            }
+
+            (*offset)++;
+            if (character != 10) {
+                (*offset)--;
+            }
+            break;
+        }
+        data->append(character);
+    }
+    return OK;
+}
+
+status_t TimedTextSRTSource::getText(
+        const MediaSource::ReadOptions *options,
+        AString *text, int64_t *startTimeUs, int64_t *endTimeUs) {
+    text->clear();
+    int64_t seekTimeUs;
+    MediaSource::ReadOptions::SeekMode mode;
+    if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) {
+        int64_t lastEndTimeUs =
+                mTextVector.valueAt(mTextVector.size() - 1).endTimeUs;
+        int64_t firstStartTimeUs = mTextVector.keyAt(0);
+        if (seekTimeUs < 0 || seekTimeUs > lastEndTimeUs) {
+            return ERROR_OUT_OF_RANGE;
+        } else if (seekTimeUs < firstStartTimeUs) {
+            mIndex = 0;
+        } else {
+            // binary search
+            ssize_t low = 0;
+            ssize_t high = mTextVector.size() - 1;
+            ssize_t mid = 0;
+            int64_t currTimeUs;
+
+            while (low <= high) {
+                mid = low + (high - low)/2;
+                currTimeUs = mTextVector.keyAt(mid);
+                const int diff = currTimeUs - seekTimeUs;
+
+                if (diff == 0) {
+                    break;
+                } else if (diff < 0) {
+                    low = mid + 1;
+                } else {
+                    if ((high == mid + 1)
+                        && (seekTimeUs < mTextVector.keyAt(high))) {
+                        break;
+                    }
+                    high = mid - 1;
+                }
+            }
+            mIndex = mid;
+        }
+    }
+    const TextInfo &info = mTextVector.valueAt(mIndex);
+    *startTimeUs = mTextVector.keyAt(mIndex);
+    *endTimeUs = info.endTimeUs;
+    mIndex++;
+
+    char *str = new char[info.textLen];
+    if (mSource->readAt(info.offset, str, info.textLen) < info.textLen) {
+        delete[] str;
+        return ERROR_IO;
+    }
+    text->append(str, info.textLen);
+    delete[] str;
+    return OK;
+}
+
+status_t TimedTextSRTSource::extractAndAppendLocalDescriptions(
+        int64_t timeUs, const AString &text, Parcel *parcel) {
+    const void *data = text.c_str();
+    size_t size = text.size();
+    int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS |
+                   TextDescriptions::OUT_OF_BAND_TEXT_SRT;
+
+    if (size > 0) {
+        return TextDescriptions::getParcelOfDescriptions(
+                (const uint8_t *)data, size, flag, timeUs / 1000, parcel);
+    }
+    return OK;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextSRTSource.h b/media/libstagefright/timedtext/TimedTextSRTSource.h
new file mode 100644
index 0000000..a0734d9
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextSRTSource.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TIMED_TEXT_SRT_SOURCE_H_
+#define TIMED_TEXT_SRT_SOURCE_H_
+
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/Compat.h>  // off64_t
+
+#include "TimedTextSource.h"
+
+namespace android {
+
+class AString;
+class DataSource;
+class MediaBuffer;
+class Parcel;
+
+class TimedTextSRTSource : public TimedTextSource {
+ public:
+  TimedTextSRTSource(const sp<DataSource>& dataSource);
+  virtual status_t start();
+  virtual status_t stop();
+  virtual status_t read(
+          int64_t *timeUs,
+          Parcel *parcel,
+          const MediaSource::ReadOptions *options = NULL);
+
+ protected:
+  virtual ~TimedTextSRTSource();
+
+ private:
+  sp<DataSource> mSource;
+
+  struct TextInfo {
+      int64_t endTimeUs;
+      // The offset of the text in the original file.
+      off64_t offset;
+      int textLen;
+  };
+
+  int mIndex;
+  KeyedVector<int64_t, TextInfo> mTextVector;
+
+  void reset();
+  status_t scanFile();
+  status_t getNextSubtitleInfo(
+          off64_t *offset, int64_t *startTimeUs, TextInfo *info);
+  status_t readNextLine(off64_t *offset, AString *data);
+  status_t getText(
+          const MediaSource::ReadOptions *options,
+          AString *text, int64_t *startTimeUs, int64_t *endTimeUs);
+  status_t extractAndAppendLocalDescriptions(
+          int64_t timeUs, const AString &text, Parcel *parcel);
+
+  DISALLOW_EVIL_CONSTRUCTORS(TimedTextSRTSource);
+};
+
+}  // namespace android
+
+#endif  // TIMED_TEXT_SRT_SOURCE_H_
diff --git a/media/libstagefright/timedtext/TimedTextSource.cpp b/media/libstagefright/timedtext/TimedTextSource.cpp
new file mode 100644
index 0000000..9efe67c
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextSource.cpp
@@ -0,0 +1,53 @@
+ /*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "TimedTextSource"
+#include <utils/Log.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaSource.h>
+
+#include "TimedTextSource.h"
+
+#include "TimedTextInBandSource.h"
+#include "TimedTextSRTSource.h"
+
+namespace android {
+
+// static
+sp<TimedTextSource> TimedTextSource::CreateTimedTextSource(
+        const sp<MediaSource>& mediaSource) {
+    return new TimedTextInBandSource(mediaSource);
+}
+
+// static
+sp<TimedTextSource> TimedTextSource::CreateTimedTextSource(
+        const sp<DataSource>& dataSource, FileType filetype) {
+    switch(filetype) {
+        case OUT_OF_BAND_FILE_SRT:
+            return new TimedTextSRTSource(dataSource);
+        case OUT_OF_BAND_FILE_SMI:
+            // TODO: Implement for SMI.
+            ALOGE("Supporting SMI is not implemented yet");
+            break;
+        default:
+            ALOGE("Undefined subtitle format. : %d", filetype);
+    }
+    return NULL;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextSource.h b/media/libstagefright/timedtext/TimedTextSource.h
new file mode 100644
index 0000000..06bae71
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextSource.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TIMED_TEXT_SOURCE_H_
+#define TIMED_TEXT_SOURCE_H_
+
+#include <media/stagefright/foundation/ABase.h>  // for DISALLOW_XXX macro.
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>  // for MediaSource::ReadOptions
+#include <utils/RefBase.h>
+
+namespace android {
+
+class DataSource;
+class Parcel;
+
+class TimedTextSource : public RefBase {
+ public:
+  enum FileType {
+      OUT_OF_BAND_FILE_SRT = 1,
+      OUT_OF_BAND_FILE_SMI = 2,
+  };
+  static sp<TimedTextSource> CreateTimedTextSource(
+      const sp<MediaSource>& source);
+  static sp<TimedTextSource> CreateTimedTextSource(
+      const sp<DataSource>& source, FileType filetype);
+  TimedTextSource() {}
+  virtual status_t start() = 0;
+  virtual status_t stop() = 0;
+  // Returns subtitle parcel and its start time.
+  virtual status_t read(
+          int64_t *timeUs,
+          Parcel *parcel,
+          const MediaSource::ReadOptions *options = NULL) = 0;
+  virtual status_t extractGlobalDescriptions(Parcel *parcel) {
+      return INVALID_OPERATION;
+  }
+
+ protected:
+  virtual ~TimedTextSource() { }
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(TimedTextSource);
+};
+
+}  // namespace android
+
+#endif  // TIMED_TEXT_SOURCE_H_
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 2fc6125..06be2ef 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -253,6 +253,19 @@
         if (f == NULL) {
             //ALOGD("%s", name);
             f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
+
+            /*
+             * GL_EXT_debug_label is special, we always report it as
+             * supported, it's handled by GLES_trace. If GLES_trace is not
+             * enabled, then these are no-ops.
+             */
+            if (!strcmp(name, "glInsertEventMarkerEXT")) {
+                f = (__eglMustCastToProperFunctionPointerType)gl_noop;
+            } else if (!strcmp(name, "glPushGroupMarkerEXT")) {
+                f = (__eglMustCastToProperFunctionPointerType)gl_noop;
+            } else if (!strcmp(name, "glPopGroupMarkerEXT")) {
+                f = (__eglMustCastToProperFunctionPointerType)gl_noop;
+            }
         }
         *curr++ = f;
         api++;
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index e053589..83933e5 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -233,6 +233,26 @@
 
 // ----------------------------------------------------------------------------
 
+const GLubyte * egl_get_string_for_current_context(GLenum name) {
+    // NOTE: returning NULL here will fall-back to the default
+    // implementation.
+
+    EGLContext context = egl_tls_t::getContext();
+    if (context == EGL_NO_CONTEXT)
+        return NULL;
+
+    egl_context_t const * const c = get_context(context);
+    if (c == NULL) // this should never happen, by construction
+        return NULL;
+
+    if (name != GL_EXTENSIONS)
+        return NULL;
+
+    return (const GLubyte *)c->gl_extensions.string();
+}
+
+// ----------------------------------------------------------------------------
+
 // this mutex protects:
 //    d->disp[]
 //    egl_init_drivers_locked()
@@ -290,6 +310,9 @@
     ALOGE("called unimplemented OpenGL ES API");
 }
 
+void gl_noop() {
+}
+
 // ----------------------------------------------------------------------------
 
 #if USE_FAST_TLS_KEY
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 8b37da5..73aab26 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -566,27 +566,6 @@
     return result;
 }
 
-static void loseCurrent(egl_context_t * cur_c)
-{
-    if (cur_c) {
-        egl_surface_t * cur_r = get_surface(cur_c->read);
-        egl_surface_t * cur_d = get_surface(cur_c->draw);
-
-        // by construction, these are either 0 or valid (possibly terminated)
-        // it should be impossible for these to be invalid
-        ContextRef _cur_c(cur_c);
-        SurfaceRef _cur_r(cur_r);
-        SurfaceRef _cur_d(cur_d);
-
-        cur_c->read = NULL;
-        cur_c->draw = NULL;
-
-        _cur_c.release();
-        _cur_r.release();
-        _cur_d.release();
-    }
-}
-
 EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
                             EGLSurface read, EGLContext ctx)
 {
@@ -663,21 +642,13 @@
         impl_read = r->surface;
     }
 
-    EGLBoolean result;
 
-    if (c) {
-        result = c->cnx->egl.eglMakeCurrent(
-                dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
-    } else {
-        result = cur_c->cnx->egl.eglMakeCurrent(
-                dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
-    }
+    EGLBoolean result = const_cast<egl_display_t*>(dp)->makeCurrent(c, cur_c,
+            draw, read, ctx,
+            impl_draw, impl_read, impl_ctx);
 
     if (result == EGL_TRUE) {
-
-        loseCurrent(cur_c);
-
-        if (ctx != EGL_NO_CONTEXT) {
+        if (c) {
             setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
             egl_tls_t::setContext(ctx);
 #if EGL_TRACE
@@ -687,8 +658,6 @@
             _c.acquire();
             _r.acquire();
             _d.acquire();
-            c->read = read;
-            c->draw = draw;
         } else {
             setGLHooksThreadSpecific(&gHooksNoContext);
             egl_tls_t::setContext(EGL_NO_CONTEXT);
@@ -924,7 +893,8 @@
                     cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] =
                     cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] =
 #if EGL_TRACE
-                    debugHooks->ext.extensions[slot] = gHooksTrace.ext.extensions[slot] =
+                    debugHooks->ext.extensions[slot] =
+                    gHooksTrace.ext.extensions[slot] =
 #endif
                             cnx->egl.eglGetProcAddress(procname);
                 }
@@ -1180,7 +1150,7 @@
     clearError();
 
     // If there is context bound to the thread, release it
-    loseCurrent(get_context(getContext()));
+    egl_display_t::loseCurrent(get_context(getContext()));
 
     for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 53eaf9a..5cf5236 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -342,6 +342,47 @@
     return res;
 }
 
+void egl_display_t::loseCurrent(egl_context_t * cur_c)
+{
+    if (cur_c) {
+        egl_surface_t * cur_r = get_surface(cur_c->read);
+        egl_surface_t * cur_d = get_surface(cur_c->draw);
+
+        // by construction, these are either 0 or valid (possibly terminated)
+        // it should be impossible for these to be invalid
+        ContextRef _cur_c(cur_c);
+        SurfaceRef _cur_r(cur_r);
+        SurfaceRef _cur_d(cur_d);
+
+        cur_c->onLooseCurrent();
+
+        _cur_c.release();
+        _cur_r.release();
+        _cur_d.release();
+    }
+}
+
+EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c,
+        EGLSurface draw, EGLSurface read, EGLContext ctx,
+        EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx)
+{
+    Mutex::Autolock _l(lock);
+    EGLBoolean result;
+    if (c) {
+        result = c->cnx->egl.eglMakeCurrent(
+                disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
+    } else {
+        result = cur_c->cnx->egl.eglMakeCurrent(
+                disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
+    }
+    if (result == EGL_TRUE) {
+        loseCurrent(cur_c);
+        if (c) {
+            c->onMakeCurrent(draw, read);
+        }
+    }
+    return result;
+}
 
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 042ae07..4479e00 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -39,6 +39,7 @@
 // ----------------------------------------------------------------------------
 
 class egl_object_t;
+class egl_context_t;
 class egl_connection_t;
 
 // ----------------------------------------------------------------------------
@@ -84,10 +85,14 @@
     // add reference to this object. returns true if this is a valid object.
     bool getObject(egl_object_t* object) const;
 
-
     static egl_display_t* get(EGLDisplay dpy);
     static EGLDisplay getFromNativeDisplay(EGLNativeDisplayType disp);
 
+    EGLBoolean makeCurrent(egl_context_t* c, egl_context_t* cur_c,
+            EGLSurface draw, EGLSurface read, EGLContext ctx,
+            EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx);
+    static void loseCurrent(egl_context_t * cur_c);
+
     inline bool isReady() const { return (refs > 0); }
     inline bool isValid() const { return magic == '_dpy'; }
     inline bool isAlive() const { return isValid(); }
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index 26e8c3e..b660c53 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -62,5 +62,41 @@
 }
 
 // ----------------------------------------------------------------------------
+
+egl_context_t::egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
+        int impl, egl_connection_t const* cnx, int version) :
+    egl_object_t(get_display(dpy)), dpy(dpy), context(context),
+            config(config), read(0), draw(0), impl(impl), cnx(cnx),
+            version(version)
+{
+}
+
+void egl_context_t::onLooseCurrent() {
+    read = NULL;
+    draw = NULL;
+}
+
+void egl_context_t::onMakeCurrent(EGLSurface draw, EGLSurface read) {
+    this->read = read;
+    this->draw = draw;
+
+    /*
+     * Here we cache the GL_EXTENSIONS string for this context and we
+     * add the extensions always handled by the wrapper
+     */
+
+    if (gl_extensions.isEmpty()) {
+        // call the implementation's glGetString(GL_EXTENSIONS)
+        const char* exts = (const char *)gEGLImpl[impl].hooks[version]->gl.glGetString(GL_EXTENSIONS);
+        gl_extensions.setTo(exts);
+        if (gl_extensions.find("GL_EXT_debug_marker") < 0) {
+            String8 temp("GL_EXT_debug_marker ");
+            temp.append(gl_extensions);
+            gl_extensions.setTo(temp);
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
 }; // namespace android
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index 7106fa5..abd4cbb 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -28,6 +28,7 @@
 #include <GLES/glext.h>
 
 #include <utils/threads.h>
+#include <utils/String8.h>
 
 #include <system/window.h>
 
@@ -158,11 +159,11 @@
     typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;
 
     egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
-            int impl, egl_connection_t const* cnx, int version) :
-        egl_object_t(get_display(dpy)), dpy(dpy), context(context),
-                config(config), read(0), draw(0), impl(impl), cnx(cnx),
-                version(version) {
-    }
+            int impl, egl_connection_t const* cnx, int version);
+
+    void onLooseCurrent();
+    void onMakeCurrent(EGLSurface draw, EGLSurface read);
+
     EGLDisplay dpy;
     EGLContext context;
     EGLConfig config;
@@ -171,6 +172,7 @@
     int impl;
     egl_connection_t const* cnx;
     int version;
+    String8 gl_extensions;
 };
 
 class egl_image_t: public egl_object_t {
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 107acd9..ff20957 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -58,6 +58,7 @@
 extern gl_hooks_t gHooksNoContext;
 extern pthread_key_t gGLWrapperKey;
 extern "C" void gl_unimplemented();
+extern "C" void gl_noop();
 
 extern char const * const gl_names[];
 extern char const * const egl_names[];
diff --git a/opengl/libs/EGL/getProcAddress.cpp b/opengl/libs/EGL/getProcAddress.cpp
index f89c865..8dcf38d 100644
--- a/opengl/libs/EGL/getProcAddress.cpp
+++ b/opengl/libs/EGL/getProcAddress.cpp
@@ -82,23 +82,41 @@
 
 #endif
 
+
 #define GL_EXTENSION_LIST(name) \
-        name(0)   name(1)   name(2)   name(3)   \
-        name(4)   name(5)   name(6)   name(7)   \
-        name(8)   name(9)   name(10)  name(11)  \
-        name(12)  name(13)  name(14)  name(15)  \
-        name(16)  name(17)  name(18)  name(19)  \
-        name(20)  name(21)  name(22)  name(23)  \
-        name(24)  name(25)  name(26)  name(27)  \
-        name(28)  name(29)  name(30)  name(31)  \
-        name(32)  name(33)  name(34)  name(35)  \
-        name(36)  name(37)  name(38)  name(39)  \
-        name(40)  name(41)  name(42)  name(43)  \
-        name(44)  name(45)  name(46)  name(47)  \
-        name(48)  name(49)  name(50)  name(51)  \
-        name(52)  name(53)  name(54)  name(55)  \
-        name(56)  name(57)  name(58)  name(59)  \
-        name(60)  name(61)  name(62)  name(63)
+    name(0)   name(1)   name(2)   name(3)   name(4)   name(5)   name(6)   name(7)  \
+    name(8)   name(9)   name(10)  name(11)  name(12)  name(13)  name(14)  name(15) \
+    name(16)  name(17)  name(18)  name(19)  name(20)  name(21)  name(22)  name(23) \
+    name(24)  name(25)  name(26)  name(27)  name(28)  name(29)  name(30)  name(31) \
+    name(32)  name(33)  name(34)  name(35)  name(36)  name(37)  name(38)  name(39) \
+    name(40)  name(41)  name(42)  name(43)  name(44)  name(45)  name(46)  name(47) \
+    name(48)  name(49)  name(50)  name(51)  name(52)  name(53)  name(54)  name(55) \
+    name(56)  name(57)  name(58)  name(59)  name(60)  name(61)  name(62)  name(63) \
+    name(64)  name(65)  name(66)  name(67)  name(68)  name(69)  name(70)  name(71) \
+    name(72)  name(73)  name(74)  name(75)  name(76)  name(77)  name(78)  name(79) \
+    name(80)  name(81)  name(82)  name(83)  name(84)  name(85)  name(86)  name(87) \
+    name(88)  name(89)  name(90)  name(91)  name(92)  name(93)  name(94)  name(95) \
+    name(96)  name(97)  name(98)  name(99)  \
+    name(100) name(101) name(102) name(103) name(104) name(105) name(106) name(107) \
+    name(108) name(109) name(110) name(111) name(112) name(113) name(114) name(115) \
+    name(116) name(117) name(118) name(119) name(120) name(121) name(122) name(123) \
+    name(124) name(125) name(126) name(127) name(128) name(129) name(130) name(131) \
+    name(132) name(133) name(134) name(135) name(136) name(137) name(138) name(139) \
+    name(140) name(141) name(142) name(143) name(144) name(145) name(146) name(147) \
+    name(148) name(149) name(150) name(151) name(152) name(153) name(154) name(155) \
+    name(156) name(157) name(158) name(159) name(160) name(161) name(162) name(163) \
+    name(164) name(165) name(166) name(167) name(168) name(169) name(170) name(171) \
+    name(172) name(173) name(174) name(175) name(176) name(177) name(178) name(179) \
+    name(180) name(181) name(182) name(183) name(184) name(185) name(186) name(187) \
+    name(188) name(189) name(190) name(191) name(192) name(193) name(194) name(195) \
+    name(196) name(197) name(198) name(199) \
+    name(200) name(201) name(202) name(203) name(204) name(205) name(206) name(207) \
+    name(208) name(209) name(210) name(211) name(212) name(213) name(214) name(215) \
+    name(216) name(217) name(218) name(219) name(220) name(221) name(222) name(223) \
+    name(224) name(225) name(226) name(227) name(228) name(229) name(230) name(231) \
+    name(232) name(233) name(234) name(235) name(236) name(237) name(238) name(239) \
+    name(240) name(241) name(242) name(243) name(244) name(245) name(246) name(247) \
+    name(248) name(249) name(250) name(251) name(252) name(253) name(254) name(255)
 
 
 GL_EXTENSION_LIST( GL_EXTENSION )
diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
index df22b96..79aa3cd 100644
--- a/opengl/libs/GLES2/gl2.cpp
+++ b/opengl/libs/GLES2/gl2.cpp
@@ -110,6 +110,20 @@
 #undef CALL_GL_API
 #undef CALL_GL_API_RETURN
 
+/*
+ * glGetString() is special because we expose some extensions in the wrapper
+ */
+
+extern "C" const GLubyte * __glGetString(GLenum name);
+
+const GLubyte * glGetString(GLenum name)
+{
+    const GLubyte * ret = egl_get_string_for_current_context(name);
+    if (ret == NULL) {
+        ret = __glGetString(name);
+    }
+    return ret;
+}
 
 /*
  * These GL calls are special because they need to EGL to retrieve some
diff --git a/opengl/libs/GLES2/gl2_api.in b/opengl/libs/GLES2/gl2_api.in
index 5164450..9a89a52 100644
--- a/opengl/libs/GLES2/gl2_api.in
+++ b/opengl/libs/GLES2/gl2_api.in
@@ -211,7 +211,7 @@
 void API_ENTRY(glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) {
     CALL_GL_API(glGetShaderSource, shader, bufsize, length, source);
 }
-const GLubyte* API_ENTRY(glGetString)(GLenum name) {
+const GLubyte* API_ENTRY(__glGetString)(GLenum name) {
     CALL_GL_API_RETURN(glGetString, name);
 }
 void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params) {
diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
index 2d31a35..adeaa5b 100644
--- a/opengl/libs/GLES_CM/gl.cpp
+++ b/opengl/libs/GLES_CM/gl.cpp
@@ -165,6 +165,20 @@
 #undef CALL_GL_API
 #undef CALL_GL_API_RETURN
 
+/*
+ * glGetString() is special because we expose some extensions in the wrapper
+ */
+
+extern "C" const GLubyte * __glGetString(GLenum name);
+
+const GLubyte * glGetString(GLenum name)
+{
+    const GLubyte * ret = egl_get_string_for_current_context(name);
+    if (ret == NULL) {
+        ret = __glGetString(name);
+    }
+    return ret;
+}
 
 /*
  * These GL calls are special because they need to EGL to retrieve some
diff --git a/opengl/libs/GLES_CM/gl_api.in b/opengl/libs/GLES_CM/gl_api.in
index 7f20c4f..c8f6b0c 100644
--- a/opengl/libs/GLES_CM/gl_api.in
+++ b/opengl/libs/GLES_CM/gl_api.in
@@ -262,7 +262,7 @@
 void API_ENTRY(glGetPointerv)(GLenum pname, GLvoid **params) {
     CALL_GL_API(glGetPointerv, pname, params);
 }
-const GLubyte * API_ENTRY(glGetString)(GLenum name) {
+const GLubyte * API_ENTRY(__glGetString)(GLenum name) {
     CALL_GL_API_RETURN(glGetString, name);
 }
 void API_ENTRY(glGetTexEnviv)(GLenum env, GLenum pname, GLint *params) {
diff --git a/opengl/libs/GLES_trace/src/gltrace_eglapi.cpp b/opengl/libs/GLES_trace/src/gltrace_eglapi.cpp
index c237d75..c442153 100644
--- a/opengl/libs/GLES_trace/src/gltrace_eglapi.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_eglapi.cpp
@@ -77,12 +77,10 @@
 }
 
 void GLTrace_start() {
-    char value[PROPERTY_VALUE_MAX];
+    char udsName[PROPERTY_VALUE_MAX];
 
-    property_get("debug.egl.debug_port", value, "5039");
-    const unsigned short port = (unsigned short)atoi(value);
-
-    int clientSocket = gltrace::acceptClientConnection(port);
+    property_get("debug.egl.debug_portname", udsName, "gltrace");
+    int clientSocket = gltrace::acceptClientConnection(udsName);
     if (clientSocket < 0) {
         ALOGE("Error creating GLTrace server socket. Quitting application.");
         exit(-1);
diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
index daba3ff..871b5dc 100644
--- a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
@@ -358,6 +358,14 @@
             fixup_addFBContents(context, glmsg, CURRENTLY_BOUND_FB);
         }
         break;
+    case GLMessage::glPushGroupMarkerEXT:
+        /* void PushGroupMarkerEXT(sizei length, const char *marker); */
+        fixup_CStringPtr(1, glmsg);
+        break;
+    case GLMessage::glInsertEventMarkerEXT:
+        /* void InsertEventMarkerEXT(sizei length, const char *marker); */
+        fixup_CStringPtr(1, glmsg);
+        break;
     default:
         break;
     }
diff --git a/opengl/libs/GLES_trace/src/gltrace_transport.cpp b/opengl/libs/GLES_trace/src/gltrace_transport.cpp
index ce3fae5..5251b12 100644
--- a/opengl/libs/GLES_trace/src/gltrace_transport.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_transport.cpp
@@ -17,9 +17,10 @@
 #include <stdlib.h>
 #include <unistd.h>
 
+#include <unistd.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <netinet/in.h>
-#include <arpa/inet.h>
 
 #include <cutils/log.h>
 
@@ -28,22 +29,24 @@
 namespace android {
 namespace gltrace {
 
-int acceptClientConnection(int serverPort) {
-    int serverSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+int acceptClientConnection(char *sockname) {
+    int serverSocket = socket(AF_LOCAL, SOCK_STREAM, 0);
     if (serverSocket < 0) {
         ALOGE("Error (%d) while creating socket. Check if app has network permissions.",
                                                                             serverSocket);
         return -1;
     }
 
-    struct sockaddr_in server, client;
+    struct sockaddr_un server, client;
 
-    server.sin_family = AF_INET;
-    server.sin_addr.s_addr = htonl(INADDR_ANY);
-    server.sin_port = htons(serverPort);
+    memset(&server, 0, sizeof server);
+    server.sun_family = AF_UNIX;
+    // the first byte of sun_path should be '\0' for abstract namespace
+    strcpy(server.sun_path + 1, sockname);
 
-    socklen_t sockaddr_len = sizeof(sockaddr_in);
-    if (bind(serverSocket, (struct sockaddr *) &server, sizeof(server)) < 0) {
+    // note that sockaddr_len should be set to the exact size of the buffer that is used.
+    socklen_t sockaddr_len = sizeof(server.sun_family) + strlen(sockname) + 1;
+    if (bind(serverSocket, (struct sockaddr *) &server, sockaddr_len) < 0) {
         close(serverSocket);
         ALOGE("Failed to bind the server socket");
         return -1;
@@ -55,7 +58,7 @@
         return -1;
     }
 
-    ALOGD("gltrace::waitForClientConnection: server listening @ port %d", serverPort);
+    ALOGD("gltrace::waitForClientConnection: server listening @ path %s", sockname);
 
     int clientSocket = accept(serverSocket, (struct sockaddr *)&client, &sockaddr_len);
     if (clientSocket < 0) {
@@ -64,7 +67,7 @@
         return -1;
     }
 
-    ALOGD("gltrace::waitForClientConnection: client connected: %s", inet_ntoa(client.sin_addr));
+    ALOGD("gltrace::waitForClientConnection: client connected.");
 
     // do not accept any more incoming connections
     close(serverSocket);
diff --git a/opengl/libs/GLES_trace/src/gltrace_transport.h b/opengl/libs/GLES_trace/src/gltrace_transport.h
index d31df7b..3665035 100644
--- a/opengl/libs/GLES_trace/src/gltrace_transport.h
+++ b/opengl/libs/GLES_trace/src/gltrace_transport.h
@@ -76,10 +76,11 @@
 };
 
 /**
- * Utility method: start a server at @serverPort, and wait for a client
- * connection. Returns the connected client socket on success, or -1 on failure.
+ * Utility method: start a server listening at @sockName (unix domain socket,
+ * abstract namespace path), and wait for a client connection.
+ * Returns the connected client socket on success, or -1 on failure.
  */
-int acceptClientConnection(int serverPort);
+int acceptClientConnection(char *sockName);
 
 };
 };
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
index a809316..8ff51ec 100644
--- a/opengl/libs/egl_impl.h
+++ b/opengl/libs/egl_impl.h
@@ -29,6 +29,7 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name);
 EGLAPI EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image);
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/tools/glapigen b/opengl/libs/tools/glapigen
index bd8dda3..9be40cf 100755
--- a/opengl/libs/tools/glapigen
+++ b/opengl/libs/tools/glapigen
@@ -43,6 +43,9 @@
   if ($name eq "glEGLImageTargetRenderbufferStorageOES") {
     $prefix = "__";
   }
+  if ($name eq "glGetString") {
+    $prefix = "__";
+  }
   
   printf("%s API_ENTRY(%s%s)(%s)", $type, $prefix, $name, $args);
   
diff --git a/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java b/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
index 723e338..888b76e 100644
--- a/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
@@ -77,7 +77,7 @@
         final INetworkPolicyManager policyService = INetworkPolicyManager.Stub.asInterface(
                 ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
         try {
-            policyService.snoozePolicy(template);
+            policyService.snoozeLimit(template);
         } catch (RemoteException e) {
             Slog.w(TAG, "problem snoozing network policy", e);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index d46ab6c..d787e10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -588,8 +588,12 @@
             }
         }
 
-        if ((isCdma() && isCdmaEri()) || mPhone.isNetworkRoaming()) {
-            mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
+        if (isCdma()) {
+            if (isCdmaEri()) {
+                mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
+            }
+        } else if (mPhone.isNetworkRoaming()) {
+                mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
         }
     }
 
@@ -850,8 +854,10 @@
             Slog.d(TAG, "updateConnectivity: intent=" + intent);
         }
 
-        NetworkInfo info = (NetworkInfo)(intent.getParcelableExtra(
-                ConnectivityManager.EXTRA_NETWORK_INFO));
+        final ConnectivityManager connManager = (ConnectivityManager) mContext
+                .getSystemService(Context.CONNECTIVITY_SERVICE);
+        final NetworkInfo info = connManager.getActiveNetworkInfo();
+
         int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
 
         if (CHATTY) {
@@ -1017,10 +1023,13 @@
             mContentDescriptionCombinedSignal = mHasMobileDataFeature
                 ? mContentDescriptionDataType : mContentDescriptionWifi;
 
-            if ((isCdma() && isCdmaEri()) || mPhone.isNetworkRoaming()) {
+            mDataTypeIconId = 0;
+            if (isCdma()) {
+                if (isCdmaEri()) {
+                    mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
+                }
+            } else if (mPhone.isNetworkRoaming()) {
                 mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
-            } else {
-                mDataTypeIconId = 0;
             }
         }
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 09d7954..1a2fa66 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -160,7 +160,10 @@
 
 AudioFlinger::AudioFlinger()
     : BnAudioFlinger(),
-        mPrimaryHardwareDev(NULL), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1),
+        mPrimaryHardwareDev(NULL),
+        mHardwareStatus(AUDIO_HW_IDLE), // see also onFirstRef()
+        mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1),
+        mMode(AUDIO_MODE_INVALID),
         mBtNrecIsOff(false)
 {
 }
@@ -172,7 +175,6 @@
     Mutex::Autolock _l(mLock);
 
     /* TODO: move all this work into an Init() function */
-    mHardwareStatus = AUDIO_HW_IDLE;
 
     for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
         const hw_module_t *mod;
@@ -265,13 +267,10 @@
 
     result.append("Clients:\n");
     for (size_t i = 0; i < mClients.size(); ++i) {
-        wp<Client> wClient = mClients.valueAt(i);
-        if (wClient != 0) {
-            sp<Client> client = wClient.promote();
-            if (client != 0) {
-                snprintf(buffer, SIZE, "  pid: %d\n", client->pid());
-                result.append(buffer);
-            }
+        sp<Client> client = mClients.valueAt(i).promote();
+        if (client != 0) {
+            snprintf(buffer, SIZE, "  pid: %d\n", client->pid());
+            result.append(buffer);
         }
     }
 
@@ -971,7 +970,8 @@
 {
     size_t size = mNotificationClients.size();
     for (size_t i = 0; i < size; i++) {
-        mNotificationClients.valueAt(i)->client()->ioConfigChanged(event, ioHandle, param2);
+        mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event, ioHandle,
+                                                                               param2);
     }
 }
 
@@ -985,13 +985,19 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id, uint32_t device)
+AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id, uint32_t device,
+        type_t type)
     :   Thread(false),
-        mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0),
-        mFrameSize(1), mFormat(AUDIO_FORMAT_INVALID), mStandby(false), mId(id), mExiting(false),
-        mDevice(device)
+        mType(type),
+        mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0),
+        // mChannelMask
+        mChannelCount(0),
+        mFrameSize(1), mFormat(AUDIO_FORMAT_INVALID),
+        mParamStatus(NO_ERROR),
+        mStandby(false), mId(id), mExiting(false),
+        mDevice(device),
+        mDeathRecipient(new PMDeathRecipient(this))
 {
-    mDeathRecipient = new PMDeathRecipient(this);
 }
 
 AudioFlinger::ThreadBase::~ThreadBase()
@@ -1372,20 +1378,24 @@
 AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger,
                                              AudioStreamOut* output,
                                              int id,
-                                             uint32_t device)
-    :   ThreadBase(audioFlinger, id, device),
-        mMixBuffer(NULL), mSuspended(0), mBytesWritten(0), mOutput(output),
+                                             uint32_t device,
+                                             type_t type)
+    :   ThreadBase(audioFlinger, id, device, type),
+        mMixBuffer(NULL), mSuspended(0), mBytesWritten(0),
+        // Assumes constructor is called by AudioFlinger with it's mLock held,
+        // but it would be safer to explicitly pass initial masterMute as parameter
+        mMasterMute(audioFlinger->masterMute_l()),
+        // mStreamTypes[] initialized in constructor body
+        mOutput(output),
+        // Assumes constructor is called by AudioFlinger with it's mLock held,
+        // but it would be safer to explicitly pass initial masterVolume as parameter
+        mMasterVolume(audioFlinger->masterVolume_l()),
         mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false)
 {
     snprintf(mName, kNameLength, "AudioOut_%d", id);
 
     readOutputParameters();
 
-    // Assumes constructor is called by AudioFlinger with it's mLock held,
-    // but it would be safer to explicitly pass these as parameters
-    mMasterVolume = mAudioFlinger->masterVolume_l();
-    mMasterMute = mAudioFlinger->masterMute_l();
-
     // mStreamTypes[AUDIO_STREAM_CNT] is initialized by stream_type_t default constructor
     // There is no AUDIO_STREAM_MIN, and ++ operator does not compile
     for (audio_stream_type_t stream = (audio_stream_type_t) 0; stream < AUDIO_STREAM_CNT;
@@ -1431,13 +1441,10 @@
     result.append(buffer);
     result.append("   Name  Clien Typ Fmt Chn mask   Session Buf  S M F SRate LeftV RighV  Serv       User       Main buf   Aux Buf\n");
     for (size_t i = 0; i < mActiveTracks.size(); ++i) {
-        wp<Track> wTrack = mActiveTracks[i];
-        if (wTrack != 0) {
-            sp<Track> track = wTrack.promote();
-            if (track != 0) {
-                track->dump(buffer, SIZE);
-                result.append(buffer);
-            }
+        sp<Track> track = mActiveTracks[i].promote();
+        if (track != 0) {
+            track->dump(buffer, SIZE);
+            result.append(buffer);
         }
     }
     write(fd, result.string(), result.size());
@@ -1740,7 +1747,7 @@
 
     // FIXME - Current mixer implementation only supports stereo output: Always
     // Allocate a stereo buffer even if HW output is mono.
-    if (mMixBuffer != NULL) delete[] mMixBuffer;
+    delete[] mMixBuffer;
     mMixBuffer = new int16_t[mFrameCount * 2];
     memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
 
@@ -1845,13 +1852,12 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
-    :   PlaybackThread(audioFlinger, output, id, device),
-        mAudioMixer(NULL), mPrevMixerStatus(MIXER_IDLE)
+AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
+        int id, uint32_t device, type_t type)
+    :   PlaybackThread(audioFlinger, output, id, device, type),
+        mAudioMixer(new AudioMixer(mFrameCount, mSampleRate)),
+        mPrevMixerStatus(MIXER_IDLE)
 {
-    mType = ThreadBase::MIXER;
-    mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
-
     // FIXME - Current mixer implementation only supports stereo output
     if (mChannelCount == 1) {
         ALOGE("Invalid audio hardware channel count");
@@ -2193,7 +2199,7 @@
                 // read original volumes with volume control
                 float typeVolume = mStreamTypes[track->type()].volume;
                 float v = masterVolume * typeVolume;
-                uint32_t vlr = cblk->volumeLR;
+                uint32_t vlr = cblk->getVolumeLR();
                 vl = vlr & 0xFFFF;
                 vr = vlr >> 16;
                 // track volumes come from shared memory, so can't be trusted and must be clamped
@@ -2461,6 +2467,8 @@
             }
             if (status == NO_ERROR && reconfig) {
                 delete mAudioMixer;
+                // for safety in case readOutputParameters() accesses mAudioMixer (it doesn't)
+                mAudioMixer = NULL;
                 readOutputParameters();
                 mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
                 for (size_t i = 0; i < mTracks.size() ; i++) {
@@ -2513,9 +2521,10 @@
 
 // ----------------------------------------------------------------------------
 AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
-    :   PlaybackThread(audioFlinger, output, id, device)
+    :   PlaybackThread(audioFlinger, output, id, device, DIRECT)
+        // mLeftVolFloat, mRightVolFloat
+        // mLeftVolShort, mRightVolShort
 {
-    mType = ThreadBase::DIRECT;
 }
 
 AudioFlinger::DirectOutputThread::~DirectOutputThread()
@@ -2729,7 +2738,7 @@
                     } else {
                         float typeVolume = mStreamTypes[track->type()].volume;
                         float v = mMasterVolume * typeVolume;
-                        uint32_t vlr = cblk->volumeLR;
+                        uint32_t vlr = cblk->getVolumeLR();
                         float v_clamped = v * (vlr & 0xFFFF);
                         if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
                         left = v_clamped/MAX_GAIN;
@@ -2992,10 +3001,11 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread, int id)
-    :   MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->device()), mWaitTimeMs(UINT_MAX)
+AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger,
+        AudioFlinger::MixerThread* mainThread, int id)
+    :   MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->device(), DUPLICATING),
+        mWaitTimeMs(UINT_MAX)
 {
-    mType = ThreadBase::DUPLICATING;
     addOutputTrack(mainThread);
 }
 
@@ -3244,13 +3254,17 @@
     :   RefBase(),
         mThread(thread),
         mClient(client),
-        mCblk(0),
+        mCblk(NULL),
+        // mBuffer
+        // mBufferEnd
         mFrameCount(0),
         mState(IDLE),
         mClientTid(-1),
         mFormat(format),
         mFlags(flags & ~SYSTEM_FLAGS_MASK),
         mSessionId(sessionId)
+        // mChannelCount
+        // mChannelMask
 {
     ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
 
@@ -3317,6 +3331,7 @@
     }
     mCblkMemory.clear();            // and free the shared memory
     if (mClient != NULL) {
+        // Client destructor must run with AudioFlinger mutex locked
         Mutex::Autolock _l(mClient->audioFlinger()->mLock);
         mClient.clear();
     }
@@ -3468,7 +3483,7 @@
 
 void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size)
 {
-    uint32_t vlr = mCblk->volumeLR;
+    uint32_t vlr = mCblk->getVolumeLR();
     snprintf(buffer, size, "   %05d %05d %03u %03u 0x%08x %05u   %04u %1d %1d %1d %05u %05u %05u  0x%08x 0x%08x 0x%08x 0x%08x\n",
             mName - AudioMixer::TRACK0,
             (mClient == NULL) ? getpid() : mClient->pid(),
@@ -3827,7 +3842,6 @@
     if (mCblk != NULL) {
         mCblk->flags |= CBLK_DIRECTION_OUT;
         mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
-        mCblk->volumeLR = (MAX_GAIN_INT << 16) | MAX_GAIN_INT;
         mOutBuffer.frameCount = 0;
         playbackThread->mTracks.add(this);
         ALOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, " \
@@ -4065,7 +4079,7 @@
     mAudioFlinger->removeClient_l(mPid);
 }
 
-const sp<MemoryDealer>& AudioFlinger::Client::heap() const
+sp<MemoryDealer> AudioFlinger::Client::heap() const
 {
     return mMemoryDealer;
 }
@@ -4075,13 +4089,12 @@
 AudioFlinger::NotificationClient::NotificationClient(const sp<AudioFlinger>& audioFlinger,
                                                      const sp<IAudioFlingerClient>& client,
                                                      pid_t pid)
-    : mAudioFlinger(audioFlinger), mPid(pid), mClient(client)
+    : mAudioFlinger(audioFlinger), mPid(pid), mAudioFlingerClient(client)
 {
 }
 
 AudioFlinger::NotificationClient::~NotificationClient()
 {
-    mClient.clear();
 }
 
 void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who)
@@ -4266,15 +4279,16 @@
                                          uint32_t channels,
                                          int id,
                                          uint32_t device) :
-    ThreadBase(audioFlinger, id, device),
-    mInput(input), mTrack(NULL), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL)
+    ThreadBase(audioFlinger, id, device, RECORD),
+    mInput(input), mTrack(NULL), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL),
+    // mRsmpInIndex and mInputBytes set by readInputParameters()
+    mReqChannelCount(popcount(channels)),
+    mReqSampleRate(sampleRate)
+    // mBytesRead is only meaningful while active, and so is cleared in start()
+    // (but might be better to also clear here for dump?)
 {
-    mType = ThreadBase::RECORD;
-
     snprintf(mName, kNameLength, "AudioIn_%d", id);
 
-    mReqChannelCount = popcount(channels);
-    mReqSampleRate = sampleRate;
     readInputParameters();
 }
 
@@ -4282,10 +4296,8 @@
 AudioFlinger::RecordThread::~RecordThread()
 {
     delete[] mRsmpInBuffer;
-    if (mResampler != NULL) {
-        delete mResampler;
-        delete[] mRsmpOutBuffer;
-    }
+    delete mResampler;
+    delete[] mRsmpOutBuffer;
 }
 
 void AudioFlinger::RecordThread::onFirstRef()
@@ -4829,9 +4841,11 @@
 
 void AudioFlinger::RecordThread::readInputParameters()
 {
-    if (mRsmpInBuffer) delete mRsmpInBuffer;
-    if (mRsmpOutBuffer) delete mRsmpOutBuffer;
-    if (mResampler) delete mResampler;
+    delete mRsmpInBuffer;
+    // mRsmpInBuffer is always assigned a new[] below
+    delete mRsmpOutBuffer;
+    mRsmpOutBuffer = NULL;
+    delete mResampler;
     mResampler = NULL;
 
     mSampleRate = mInput->stream->common.get_sample_rate(&mInput->stream->common);
@@ -5243,12 +5257,8 @@
             return;
         }
     }
-    AudioSessionRef *ref = new AudioSessionRef();
-    ref->sessionid = audioSession;
-    ref->pid = caller;
-    ref->cnt = 1;
-    mAudioSessionRefs.push(ref);
-    ALOGV(" added new entry for %d", ref->sessionid);
+    mAudioSessionRefs.push(new AudioSessionRef(audioSession, caller));
+    ALOGV(" added new entry for %d", audioSession);
 }
 
 void AudioFlinger::releaseAudioSessionId(int audioSession)
@@ -6179,7 +6189,7 @@
     }
 }
 
-status_t AudioFlinger::EffectModule::addHandle(sp<EffectHandle>& handle)
+status_t AudioFlinger::EffectModule::addHandle(const sp<EffectHandle>& handle)
 {
     status_t status;
 
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 16048c8..4156da8 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -226,16 +226,16 @@
     public:
                             Client(const sp<AudioFlinger>& audioFlinger, pid_t pid);
         virtual             ~Client();
-        const sp<MemoryDealer>&     heap() const;
+        sp<MemoryDealer>    heap() const;
         pid_t               pid() const { return mPid; }
         sp<AudioFlinger>    audioFlinger() { return mAudioFlinger; }
 
     private:
                             Client(const Client&);
                             Client& operator = (const Client&);
-        sp<AudioFlinger>    mAudioFlinger;
-        sp<MemoryDealer>    mMemoryDealer;
-        pid_t               mPid;
+        const sp<AudioFlinger> mAudioFlinger;
+        const sp<MemoryDealer> mMemoryDealer;
+        const pid_t         mPid;
     };
 
     // --- Notification Client ---
@@ -246,7 +246,7 @@
                                                 pid_t pid);
         virtual             ~NotificationClient();
 
-                sp<IAudioFlingerClient>    client() { return mClient; }
+                sp<IAudioFlingerClient> audioFlingerClient() const { return mAudioFlingerClient; }
 
                 // IBinder::DeathRecipient
                 virtual     void        binderDied(const wp<IBinder>& who);
@@ -255,9 +255,9 @@
                             NotificationClient(const NotificationClient&);
                             NotificationClient& operator = (const NotificationClient&);
 
-        sp<AudioFlinger>        mAudioFlinger;
-        pid_t                   mPid;
-        sp<IAudioFlingerClient> mClient;
+        const sp<AudioFlinger>  mAudioFlinger;
+        const pid_t             mPid;
+        const sp<IAudioFlingerClient> mAudioFlingerClient;
     };
 
     class TrackHandle;
@@ -277,17 +277,17 @@
 
     class ThreadBase : public Thread {
     public:
-        ThreadBase (const sp<AudioFlinger>& audioFlinger, int id, uint32_t device);
-        virtual             ~ThreadBase();
 
-
-        enum type {
+        enum type_t {
             MIXER,              // Thread class is MixerThread
             DIRECT,             // Thread class is DirectOutputThread
             DUPLICATING,        // Thread class is DuplicatingThread
             RECORD              // Thread class is RecordThread
         };
 
+        ThreadBase (const sp<AudioFlinger>& audioFlinger, int id, uint32_t device, type_t type);
+        virtual             ~ThreadBase();
+
         status_t dumpBase(int fd, const Vector<String16>& args);
         status_t dumpEffectChains(int fd, const Vector<String16>& args);
 
@@ -367,8 +367,8 @@
             bool step();
             void reset();
 
-            wp<ThreadBase>      mThread;
-            sp<Client>          mClient;
+            const wp<ThreadBase> mThread;
+            /*const*/ sp<Client> mClient;   // see explanation at ~TrackBase() why not const
             sp<IMemory>         mCblkMemory;
             audio_track_cblk_t* mCblk;
             void*               mBuffer;
@@ -377,9 +377,9 @@
             // we don't really need a lock for these
             track_state         mState;
             int                 mClientTid;
-            audio_format_t      mFormat;
+            const audio_format_t mFormat;
             uint32_t            mFlags;
-            int                 mSessionId;
+            const int           mSessionId;
             uint8_t             mChannelCount;
             uint32_t            mChannelMask;
         };
@@ -408,7 +408,7 @@
         };
 
         virtual     status_t    initCheck() const = 0;
-                    int         type() const { return mType; }
+                    type_t      type() const { return mType; }
                     uint32_t    sampleRate() const;
                     int         channelCount() const;
                     audio_format_t format() const;
@@ -530,9 +530,9 @@
         friend class RecordThread;
         friend class RecordTrack;
 
-                    int                     mType;
+                    const type_t            mType;
                     Condition               mWaitWorkCV;
-                    sp<AudioFlinger>        mAudioFlinger;
+                    const sp<AudioFlinger>  mAudioFlinger;
                     uint32_t                mSampleRate;
                     size_t                  mFrameCount;
                     uint32_t                mChannelMask;
@@ -553,7 +553,7 @@
                     char                    mName[kNameLength];
                     sp<IPowerManager>       mPowerManager;
                     sp<IBinder>             mWakeLockToken;
-                    sp<PMDeathRecipient>    mDeathRecipient;
+                    const sp<PMDeathRecipient> mDeathRecipient;
                     // list of suspended effects per session and per type. The first vector is
                     // keyed by session ID, the second by type UUID timeLow field
                     KeyedVector< int, KeyedVector< int, sp<SuspendedSessionDesc> > >  mSuspendedSessions;
@@ -671,7 +671,7 @@
                     bool        write(int16_t* data, uint32_t frames);
                     bool        bufferQueueEmpty() { return (mBufferQueue.size() == 0) ? true : false; }
                     bool        isActive() { return mActive; }
-            wp<ThreadBase>&     thread()  { return mThread; }
+            const wp<ThreadBase>& thread() { return mThread; }
 
         private:
 
@@ -688,10 +688,11 @@
             Vector < Buffer* >          mBufferQueue;
             AudioBufferProvider::Buffer mOutBuffer;
             bool                        mActive;
-            DuplicatingThread*          mSourceThread;
+            DuplicatingThread* const mSourceThread; // for waitTimeMs() in write()
         };  // end of OutputTrack
 
-        PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
+        PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id,
+                        uint32_t device, type_t type);
         virtual             ~PlaybackThread();
 
         virtual     status_t    dump(int fd, const Vector<String16>& args);
@@ -817,7 +818,8 @@
         MixerThread (const sp<AudioFlinger>& audioFlinger,
                      AudioStreamOut* output,
                      int id,
-                     uint32_t device);
+                     uint32_t device,
+                     type_t type = MIXER);
         virtual             ~MixerThread();
 
         // Thread virtuals
@@ -917,7 +919,7 @@
         virtual status_t onTransact(
             uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
     private:
-        sp<PlaybackThread::Track> mTrack;
+        const sp<PlaybackThread::Track> mTrack;
     };
 
     friend class Client;
@@ -1021,8 +1023,8 @@
                 int16_t                             *mRsmpInBuffer;
                 size_t                              mRsmpInIndex;
                 size_t                              mInputBytes;
-                int                                 mReqChannelCount;
-                uint32_t                            mReqSampleRate;
+                const int                           mReqChannelCount;
+                const uint32_t                      mReqSampleRate;
                 ssize_t                             mBytesRead;
     };
 
@@ -1036,7 +1038,7 @@
         virtual status_t onTransact(
             uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
     private:
-        sp<RecordThread::RecordTrack> mRecordTrack;
+        const sp<RecordThread::RecordTrack> mRecordTrack;
     };
 
     //--- Audio Effect Management
@@ -1105,9 +1107,9 @@
         int16_t     *outBuffer() { return mConfig.outputCfg.buffer.s16; }
         void        setChain(const wp<EffectChain>& chain) { mChain = chain; }
         void        setThread(const wp<ThreadBase>& thread) { mThread = thread; }
-        wp<ThreadBase>& thread() { return mThread; }
+        const wp<ThreadBase>& thread() { return mThread; }
 
-        status_t addHandle(sp<EffectHandle>& handle);
+        status_t addHandle(const sp<EffectHandle>& handle);
         void disconnect(const wp<EffectHandle>& handle, bool unpiniflast);
         size_t removeHandle (const wp<EffectHandle>& handle);
 
@@ -1378,8 +1380,11 @@
     };
 
     struct AudioSessionRef {
-        int sessionid;
-        pid_t pid;
+        // FIXME rename parameter names when fields get "m" prefix
+        AudioSessionRef(int sessionid_, pid_t pid_) :
+            sessionid(sessionid_), pid(pid_), cnt(1) {}
+        const int sessionid;
+        const pid_t pid;
         int cnt;
     };
 
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index a8102e5..1f7d883 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -48,9 +48,10 @@
     mState.enabledTracks= 0;
     mState.needsChanged = 0;
     mState.frameCount   = frameCount;
+    mState.hook         = process__nop;
     mState.outputTemp   = NULL;
     mState.resampleTemp = NULL;
-    mState.hook         = process__nop;
+    // mState.reserved
     track_t* t = mState.tracks;
     for (unsigned i=0 ; i < MAX_NUM_TRACKS ; i++) {
         t->needs = 0;
@@ -70,12 +71,13 @@
         t->enabled = 0;
         t->format = 16;
         t->channelMask = AUDIO_CHANNEL_OUT_STEREO;
-        t->buffer.raw = 0;
         t->bufferProvider = NULL;
+        t->buffer.raw = NULL;
+        // t->buffer.frameCount
         t->hook = NULL;
+        t->in = NULL;
         t->resampler = NULL;
         t->sampleRate = mSampleRate;
-        t->in = NULL;
         t->mainBuffer = NULL;
         t->auxBuffer = NULL;
         t++;
@@ -1127,9 +1129,7 @@
         }
     }
 
-    if (buff != NULL) {
-        delete [] buff;
-    }
+    delete [] buff;
 }
 #endif
 
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 2df1385..7695d2b 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -649,7 +649,7 @@
         release_wake_lock(mName.string());
     }
     mAudioCommands.clear();
-    if (mpToneGenerator != NULL) delete mpToneGenerator;
+    delete mpToneGenerator;
 }
 
 void AudioPolicyService::AudioCommandThread::onFirstRef()
@@ -682,8 +682,7 @@
                     ToneData *data = (ToneData *)command->mParam;
                     ALOGV("AudioCommandThread() processing start tone %d on stream %d",
                             data->mType, data->mStream);
-                    if (mpToneGenerator != NULL)
-                        delete mpToneGenerator;
+                    delete mpToneGenerator;
                     mpToneGenerator = new ToneGenerator(data->mStream, 1.0);
                     mpToneGenerator->startTone(data->mType);
                     delete data;
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 1f8cf63..296c95e 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -831,7 +831,7 @@
 
     ALOGV("Opening device: %s", devicePath);
 
-    int fd = open(devicePath, O_RDWR);
+    int fd = open(devicePath, O_RDWR | O_CLOEXEC);
     if(fd < 0) {
         ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
         return -1;
@@ -1063,14 +1063,20 @@
         return -1;
     }
 
+    // Enable wake-lock behavior on kernels that support it.
+    // TODO: Only need this for devices that can really wake the system.
+    bool usingSuspendBlock = ioctl(fd, EVIOCSSUSPENDBLOCK, 1) == 0;
+
     ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
-            "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s",
+            "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, "
+            "usingSuspendBlock=%s",
          deviceId, fd, devicePath, device->identifier.name.string(),
          device->classes,
          device->configurationFile.string(),
          device->keyMap.keyLayoutFile.string(),
          device->keyMap.keyCharacterMapFile.string(),
-         toString(mBuiltInKeyboardId == deviceId));
+         toString(mBuiltInKeyboardId == deviceId),
+         toString(usingSuspendBlock));
 
     mDevices.add(deviceId, device);
 
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 56afe7f..8cb9d99b 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -1962,8 +1962,10 @@
                 } else {
                     mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
                 }
-                NetworkInfo info =
-                    (NetworkInfo)intent.getExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
+
+                final ConnectivityManager connManager = (ConnectivityManager) context
+                        .getSystemService(Context.CONNECTIVITY_SERVICE);
+                final NetworkInfo info = connManager.getActiveNetworkInfo();
 
                 // Notify location providers of current network state
                 synchronized (mLock) {
diff --git a/services/java/com/android/server/NetworkTimeUpdateService.java b/services/java/com/android/server/NetworkTimeUpdateService.java
index f7fe39e..a7d1992 100644
--- a/services/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/java/com/android/server/NetworkTimeUpdateService.java
@@ -234,8 +234,9 @@
             String action = intent.getAction();
             if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
                 // There is connectivity
-                NetworkInfo netInfo = (NetworkInfo)intent.getParcelableExtra(
-                        ConnectivityManager.EXTRA_NETWORK_INFO);
+                final ConnectivityManager connManager = (ConnectivityManager) context
+                        .getSystemService(Context.CONNECTIVITY_SERVICE);
+                final NetworkInfo netInfo = connManager.getActiveNetworkInfo();
                 if (netInfo != null) {
                     // Verify that it's a WIFI connection
                     if (netInfo.getState() == NetworkInfo.State.CONNECTED &&
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 23fa94a..8bda755 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -46,7 +46,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.IWindow;
-import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -96,6 +95,10 @@
 
     private static final int DO_SET_SERVICE_INFO = 10;
 
+    public static final int ACTIVE_WINDOW_ID = -1;
+
+    public static final long ROOT_NODE_ID = -1;
+
     private static int sNextWindowId;
 
     final HandlerCaller mCaller;
@@ -467,7 +470,8 @@
         }
     }
 
-    public void registerEventListener(IEventListener listener) {
+    public void registerUiTestAutomationService(IEventListener listener,
+            AccessibilityServiceInfo accessibilityServiceInfo) {
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
                 FUNCTION_REGISTER_EVENT_LISTENER);
         ComponentName componentName = new ComponentName("foo.bar",
@@ -490,13 +494,23 @@
             }
         }
         // Hook the automation service up.
-        AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo();
-        accessibilityServiceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
-        accessibilityServiceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
         Service service = new Service(componentName, accessibilityServiceInfo, true);
         service.onServiceConnected(componentName, listener.asBinder());
     }
 
+    public void unregisterUiTestAutomationService(IEventListener listener) {
+        synchronized (mLock) {
+            final int serviceCount = mServices.size();
+            for (int i = 0; i < serviceCount; i++) {
+                Service service = mServices.get(i);
+                if (service.mServiceInterface == listener && service.mIsAutomation) {
+                    // Automation service is not bound, so pretend it died to perform clean up.
+                    service.binderDied();
+                }
+            }
+        }
+    }
+
     /**
      * Removes an AccessibilityInteractionConnection.
      *
@@ -1070,10 +1084,11 @@
             }
         }
 
-        public float findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId,
-                int interactionId, IAccessibilityInteractionConnectionCallback callback,
-                long interrogatingTid)
+        public float findAccessibilityNodeInfoByViewId(int accessibilityWindowId,
+                long accessibilityNodeId, int viewId, int interactionId,
+                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
                 throws RemoteException {
+            final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
                 mSecurityPolicy.enforceCanRetrieveWindowContent(this);
@@ -1081,12 +1096,8 @@
                 if (!permissionGranted) {
                     return 0;
                 } else {
-                    connection = getConnectionToRetrievalAllowingWindowLocked();
+                    connection = getConnectionLocked(resolvedWindowId);
                     if (connection == null) {
-                        if (DEBUG) {
-                            Slog.e(LOG_TAG, "No interaction connection to a retrieve "
-                                    + "allowing window.");
-                        }
                         return 0;
                     }
                 }
@@ -1094,44 +1105,33 @@
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
             try {
-                connection.findAccessibilityNodeInfoByViewId(viewId, interactionId, callback,
-                        interrogatingPid, interrogatingTid);
+                connection.findAccessibilityNodeInfoByViewId(accessibilityNodeId, viewId,
+                        interactionId, callback, interrogatingPid, interrogatingTid);
             } catch (RemoteException re) {
                 if (DEBUG) {
-                    Slog.e(LOG_TAG, "Error finding node.");
+                    Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId().");
                 }
             } finally {
                 Binder.restoreCallingIdentity(identityToken);
             }
-            return getCompatibilityScale(mSecurityPolicy.getRetrievalAllowingWindowLocked());
+            return getCompatibilityScale(resolvedWindowId);
         }
 
-        public float findAccessibilityNodeInfosByTextInActiveWindow(
-                String text, int interactionId,
-                IAccessibilityInteractionConnectionCallback callback, long threadId)
-                throws RemoteException {
-            return findAccessibilityNodeInfosByText(text,
-                    mSecurityPolicy.mRetrievalAlowingWindowId, View.NO_ID, interactionId, callback,
-                    threadId);
-        }
-
-        public float findAccessibilityNodeInfosByText(String text,
-                int accessibilityWindowId, long accessibilityNodeId, int interactionId,
+        public float findAccessibilityNodeInfosByText(int accessibilityWindowId,
+                long accessibilityNodeId, String text, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
                 throws RemoteException {
+            final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
                 mSecurityPolicy.enforceCanRetrieveWindowContent(this);
                 final boolean permissionGranted =
-                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId);
+                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
                 if (!permissionGranted) {
                     return 0;
                 } else {
-                    connection = getConnectionToRetrievalAllowingWindowLocked();
+                    connection = getConnectionLocked(resolvedWindowId);
                     if (connection == null) {
-                        if (DEBUG) {
-                            Slog.e(LOG_TAG, "No interaction connection to focused window.");
-                        }
                         return 0;
                     }
                 }
@@ -1139,40 +1139,35 @@
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
             try {
-                connection.findAccessibilityNodeInfosByText(text, accessibilityNodeId,
+                connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
                         interactionId, callback, interrogatingPid, interrogatingTid);
             } catch (RemoteException re) {
                 if (DEBUG) {
-                    Slog.e(LOG_TAG, "Error finding node.");
+                    Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()");
                 }
             } finally {
                 Binder.restoreCallingIdentity(identityToken);
             }
-            return getCompatibilityScale(accessibilityWindowId);
+            return getCompatibilityScale(resolvedWindowId);
         }
 
         public float findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
                 long accessibilityNodeId, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
                 throws RemoteException {
+            final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
                 mSecurityPolicy.enforceCanRetrieveWindowContent(this);
                 final boolean permissionGranted =
-                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId);
+                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
                 if (!permissionGranted) {
                     return 0;
                 } else {
-                    AccessibilityConnectionWrapper wrapper =
-                        mWindowIdToInteractionConnectionWrapperMap.get(accessibilityWindowId);
-                    if (wrapper == null) {
-                        if (DEBUG) {
-                            Slog.e(LOG_TAG, "No interaction connection to window: "
-                                    + accessibilityWindowId);
-                        }
+                    connection = getConnectionLocked(resolvedWindowId);
+                    if (connection == null) {
                         return 0;
                     }
-                    connection = wrapper.mConnection;
                 }
             }
             final int interrogatingPid = Binder.getCallingPid();
@@ -1182,35 +1177,29 @@
                         interactionId, callback, interrogatingPid, interrogatingTid);
             } catch (RemoteException re) {
                 if (DEBUG) {
-                    Slog.e(LOG_TAG, "Error requesting node with accessibilityNodeId: "
-                            + accessibilityNodeId);
+                    Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
                 }
             } finally {
                 Binder.restoreCallingIdentity(identityToken);
             }
-            return getCompatibilityScale(accessibilityWindowId);
+            return getCompatibilityScale(resolvedWindowId);
         }
 
         public boolean performAccessibilityAction(int accessibilityWindowId,
                 long accessibilityNodeId, int action, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) {
+            final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
                 final boolean permissionGranted = mSecurityPolicy.canPerformActionLocked(this,
-                        accessibilityWindowId, action);
+                        resolvedWindowId, action);
                 if (!permissionGranted) {
                     return false;
                 } else {
-                    AccessibilityConnectionWrapper wrapper =
-                        mWindowIdToInteractionConnectionWrapperMap.get(accessibilityWindowId);
-                    if (wrapper == null) {
-                        if (DEBUG) {
-                            Slog.e(LOG_TAG, "No interaction connection to window: "
-                                    + accessibilityWindowId);
-                        }
+                    connection = getConnectionLocked(resolvedWindowId);
+                    if (connection == null) {
                         return false;
                     }
-                    connection = wrapper.mConnection;
                 }
             }
             final int interrogatingPid = Binder.getCallingPid();
@@ -1220,8 +1209,7 @@
                         callback, interrogatingPid, interrogatingTid);
             } catch (RemoteException re) {
                 if (DEBUG) {
-                    Slog.e(LOG_TAG, "Error requesting node with accessibilityNodeId: "
-                            + accessibilityNodeId);
+                    Slog.e(LOG_TAG, "Error calling performAccessibilityAction()");
                 }
             } finally {
                 Binder.restoreCallingIdentity(identityToken);
@@ -1265,14 +1253,26 @@
             }
         }
 
-        private IAccessibilityInteractionConnection getConnectionToRetrievalAllowingWindowLocked() {
-            final int windowId = mSecurityPolicy.getRetrievalAllowingWindowLocked();
+        private IAccessibilityInteractionConnection getConnectionLocked(int windowId) {
             if (DEBUG) {
                 Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
             }
-            AccessibilityConnectionWrapper wrapper =
-                mWindowIdToInteractionConnectionWrapperMap.get(windowId);
-            return (wrapper != null) ? wrapper.mConnection : null;
+            AccessibilityConnectionWrapper wrapper = mWindowIdToInteractionConnectionWrapperMap.get(
+                    windowId);
+            if (wrapper != null && wrapper.mConnection != null) {
+                return wrapper.mConnection;
+            }
+            if (DEBUG) {
+                Slog.e(LOG_TAG, "No interaction connection to window: " + windowId);
+            }
+            return null;
+        }
+
+        private int resolveAccessibilityWindowId(int accessibilityWindowId) {
+            if (accessibilityWindowId == ACTIVE_WINDOW_ID) {
+                return mSecurityPolicy.mRetrievalAlowingWindowId;
+            }
+            return accessibilityWindowId;
         }
 
         private float getCompatibilityScale(int windowId) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index db0a736..3a6a3de 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -158,6 +158,7 @@
     static final boolean DEBUG_OOM_ADJ = localLOGV || false;
     static final boolean DEBUG_TRANSITION = localLOGV || false;
     static final boolean DEBUG_BROADCAST = localLOGV || false;
+    static final boolean DEBUG_BACKGROUND_BROADCAST = DEBUG_BROADCAST || false;
     static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
     static final boolean DEBUG_SERVICE = localLOGV || false;
     static final boolean DEBUG_SERVICE_EXECUTING = localLOGV || false;
@@ -221,7 +222,8 @@
     static final int CPU_MIN_CHECK_DURATION = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000;
 
     // How long we allow a receiver to run before giving up on it.
-    static final int BROADCAST_TIMEOUT = 10*1000;
+    static final int BROADCAST_FG_TIMEOUT = 10*1000;
+    static final int BROADCAST_BG_TIMEOUT = 60*1000;
 
     // How long we wait for a service to finish executing.
     static final int SERVICE_TIMEOUT = 20*1000;
@@ -276,33 +278,823 @@
             = new ArrayList<PendingActivityLaunch>();
     
     /**
-     * List of all active broadcasts that are to be executed immediately
-     * (without waiting for another broadcast to finish).  Currently this only
-     * contains broadcasts to registered receivers, to avoid spinning up
-     * a bunch of processes to execute IntentReceiver components.
+     * BROADCASTS
+     *
+     * We keep two broadcast queues and associated bookkeeping, one for those at
+     * foreground priority, and one for normal (background-priority) broadcasts.
      */
-    final ArrayList<BroadcastRecord> mParallelBroadcasts
-            = new ArrayList<BroadcastRecord>();
+    public class BroadcastQueue {
+        static final String TAG = "BroadcastQueue";
 
-    /**
-     * List of all active broadcasts that are to be executed one at a time.
-     * The object at the top of the list is the currently activity broadcasts;
-     * those after it are waiting for the top to finish..
-     */
-    final ArrayList<BroadcastRecord> mOrderedBroadcasts
-            = new ArrayList<BroadcastRecord>();
+        static final int MAX_BROADCAST_HISTORY = 25;
 
-    /**
-     * Historical data of past broadcasts, for debugging.
-     */
-    static final int MAX_BROADCAST_HISTORY = 25;
-    final BroadcastRecord[] mBroadcastHistory
-            = new BroadcastRecord[MAX_BROADCAST_HISTORY];
+        /**
+         * Recognizable moniker for this queue
+         */
+        String mQueueName;
 
-    /**
-     * Set when we current have a BROADCAST_INTENT_MSG in flight.
-     */
-    boolean mBroadcastsScheduled = false;
+        /**
+         * Timeout period for this queue's broadcasts
+         */
+        long mTimeoutPeriod;
+
+        /**
+         * Lists of all active broadcasts that are to be executed immediately
+         * (without waiting for another broadcast to finish).  Currently this only
+         * contains broadcasts to registered receivers, to avoid spinning up
+         * a bunch of processes to execute IntentReceiver components.  Background-
+         * and foreground-priority broadcasts are queued separately.
+         */
+        final ArrayList<BroadcastRecord> mParallelBroadcasts
+                = new ArrayList<BroadcastRecord>();
+        /**
+         * List of all active broadcasts that are to be executed one at a time.
+         * The object at the top of the list is the currently activity broadcasts;
+         * those after it are waiting for the top to finish.  As with parallel
+         * broadcasts, separate background- and foreground-priority queues are
+         * maintained.
+         */
+        final ArrayList<BroadcastRecord> mOrderedBroadcasts
+                = new ArrayList<BroadcastRecord>();
+
+        /**
+         * Historical data of past broadcasts, for debugging.
+         */
+        final BroadcastRecord[] mBroadcastHistory
+                = new BroadcastRecord[MAX_BROADCAST_HISTORY];
+
+        /**
+         * Set when we current have a BROADCAST_INTENT_MSG in flight.
+         */
+        boolean mBroadcastsScheduled = false;
+
+        /**
+         * True if we have a pending unexpired BROADCAST_TIMEOUT_MSG posted to our handler.
+         */
+        boolean mPendingBroadcastTimeoutMessage;
+
+        /**
+         * Intent broadcasts that we have tried to start, but are
+         * waiting for the application's process to be created.  We only
+         * need one per scheduling class (instead of a list) because we always
+         * process broadcasts one at a time, so no others can be started while
+         * waiting for this one.
+         */
+        BroadcastRecord mPendingBroadcast = null;
+
+        /**
+         * The receiver index that is pending, to restart the broadcast if needed.
+         */
+        int mPendingBroadcastRecvIndex;
+
+        BroadcastQueue(String name, long timeoutPeriod) {
+            mQueueName = name;
+            mTimeoutPeriod = timeoutPeriod;
+        }
+
+        public boolean isPendingBroadcastProcessLocked(int pid) {
+            return mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid;
+        }
+
+        public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
+            mParallelBroadcasts.add(r);
+        }
+
+        public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
+            mOrderedBroadcasts.add(r);
+        }
+
+        public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) {
+            for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
+                if (r.intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
+                    if (DEBUG_BROADCAST) Slog.v(TAG,
+                            "***** DROPPING PARALLEL ["
+                    + mQueueName + "]: " + r.intent);
+                    mParallelBroadcasts.set(i, r);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public final boolean replaceOrderedBroadcastLocked(BroadcastRecord r) {
+            for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {
+                if (r.intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
+                    if (DEBUG_BROADCAST) Slog.v(TAG,
+                            "***** DROPPING ORDERED ["
+                            + mQueueName + "]: " + r.intent);
+                    mOrderedBroadcasts.set(i, r);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
+            boolean didSomething = false;
+            final BroadcastRecord br = mPendingBroadcast;
+            if (br != null && br.curApp.pid == app.pid) {
+                try {
+                    mPendingBroadcast = null;
+                    processCurBroadcastLocked(br, app);
+                    didSomething = true;
+                } catch (Exception e) {
+                    Slog.w(TAG, "Exception in new application when starting receiver "
+                            + br.curComponent.flattenToShortString(), e);
+                    logBroadcastReceiverDiscardLocked(br);
+                    finishReceiverLocked(br, br.resultCode, br.resultData,
+                            br.resultExtras, br.resultAbort, true);
+                    scheduleBroadcastsLocked();
+                    // We need to reset the state if we fails to start the receiver.
+                    br.state = BroadcastRecord.IDLE;
+                    throw new RuntimeException(e.getMessage());
+                }
+            }
+            return didSomething;
+        }
+
+        public void skipPendingBroadcastLocked(int pid) {
+            final BroadcastRecord br = mPendingBroadcast;
+            if (br != null && br.curApp.pid == pid) {
+                br.state = BroadcastRecord.IDLE;
+                br.nextReceiver = mPendingBroadcastRecvIndex;
+                mPendingBroadcast = null;
+                scheduleBroadcastsLocked();
+            }
+        }
+
+        public void skipCurrentReceiverLocked(ProcessRecord app) {
+            boolean reschedule = false;
+            BroadcastRecord r = app.curReceiver;
+            if (r != null) {
+                // The current broadcast is waiting for this app's receiver
+                // to be finished.  Looks like that's not going to happen, so
+                // let the broadcast continue.
+                logBroadcastReceiverDiscardLocked(r);
+                finishReceiverLocked(r, r.resultCode, r.resultData,
+                        r.resultExtras, r.resultAbort, true);
+                reschedule = true;
+            }
+
+            r = mPendingBroadcast;
+            if (r != null && r.curApp == app) {
+                if (DEBUG_BROADCAST) Slog.v(TAG,
+                        "[" + mQueueName + "] skip & discard pending app " + r);
+                logBroadcastReceiverDiscardLocked(r);
+                finishReceiverLocked(r, r.resultCode, r.resultData,
+                        r.resultExtras, r.resultAbort, true);
+                reschedule = true;
+            }
+            if (reschedule) {
+                scheduleBroadcastsLocked();
+            }
+        }
+
+        public void scheduleBroadcastsLocked() {
+            if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts ["
+                    + mQueueName + "]: current="
+                    + mBroadcastsScheduled);
+
+            if (mBroadcastsScheduled) {
+                return;
+            }
+            mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
+            mBroadcastsScheduled = true;
+        }
+
+        public BroadcastRecord getMatchingOrderedReceiver(IBinder receiver) {
+            if (mOrderedBroadcasts.size() > 0) {
+                final BroadcastRecord r = mOrderedBroadcasts.get(0);
+                if (r != null && r.receiver == receiver) {
+                    return r;
+                }
+            }
+            return null;
+        }
+
+        public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
+                String resultData, Bundle resultExtras, boolean resultAbort,
+                boolean explicit) {
+            int state = r.state;
+            r.state = BroadcastRecord.IDLE;
+            if (state == BroadcastRecord.IDLE) {
+                if (explicit) {
+                    Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
+                }
+            }
+            r.receiver = null;
+            r.intent.setComponent(null);
+            if (r.curApp != null) {
+                r.curApp.curReceiver = null;
+            }
+            if (r.curFilter != null) {
+                r.curFilter.receiverList.curBroadcast = null;
+            }
+            r.curFilter = null;
+            r.curApp = null;
+            r.curComponent = null;
+            r.curReceiver = null;
+            mPendingBroadcast = null;
+
+            r.resultCode = resultCode;
+            r.resultData = resultData;
+            r.resultExtras = resultExtras;
+            r.resultAbort = resultAbort;
+
+            // We will process the next receiver right now if this is finishing
+            // an app receiver (which is always asynchronous) or after we have
+            // come back from calling a receiver.
+            return state == BroadcastRecord.APP_RECEIVE
+                    || state == BroadcastRecord.CALL_DONE_RECEIVE;
+        }
+
+        private final void processNextBroadcast(boolean fromMsg) {
+            synchronized(ActivityManagerService.this) {
+                BroadcastRecord r;
+
+                if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast ["
+                        + mQueueName + "]: "
+                        + mParallelBroadcasts.size() + " broadcasts, "
+                        + mOrderedBroadcasts.size() + " ordered broadcasts");
+
+                updateCpuStats();
+
+                if (fromMsg) {
+                    mBroadcastsScheduled = false;
+                }
+
+                // First, deliver any non-serialized broadcasts right away.
+                while (mParallelBroadcasts.size() > 0) {
+                    r = mParallelBroadcasts.remove(0);
+                    r.dispatchTime = SystemClock.uptimeMillis();
+                    r.dispatchClockTime = System.currentTimeMillis();
+                    final int N = r.receivers.size();
+                    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast ["
+                            + mQueueName + "] " + r);
+                    for (int i=0; i<N; i++) {
+                        Object target = r.receivers.get(i);
+                        if (DEBUG_BROADCAST)  Slog.v(TAG,
+                                "Delivering non-ordered on [" + mQueueName + "] to registered "
+                                + target + ": " + r);
+                        deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
+                    }
+                    addBroadcastToHistoryLocked(r);
+                    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast ["
+                            + mQueueName + "] " + r);
+                }
+
+                // Now take care of the next serialized one...
+
+                // If we are waiting for a process to come up to handle the next
+                // broadcast, then do nothing at this point.  Just in case, we
+                // check that the process we're waiting for still exists.
+                if (mPendingBroadcast != null) {
+                    if (DEBUG_BROADCAST_LIGHT) {
+                        Slog.v(TAG, "processNextBroadcast ["
+                                + mQueueName + "]: waiting for "
+                                + mPendingBroadcast.curApp);
+                    }
+
+                    boolean isDead;
+                    synchronized (mPidsSelfLocked) {
+                        isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
+                    }
+                    if (!isDead) {
+                        // It's still alive, so keep waiting
+                        return;
+                    } else {
+                        Slog.w(TAG, "pending app  ["
+                                + mQueueName + "]" + mPendingBroadcast.curApp
+                                + " died before responding to broadcast");
+                        mPendingBroadcast.state = BroadcastRecord.IDLE;
+                        mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
+                        mPendingBroadcast = null;
+                    }
+                }
+
+                boolean looped = false;
+                
+                do {
+                    if (mOrderedBroadcasts.size() == 0) {
+                        // No more broadcasts pending, so all done!
+                        scheduleAppGcsLocked();
+                        if (looped) {
+                            // If we had finished the last ordered broadcast, then
+                            // make sure all processes have correct oom and sched
+                            // adjustments.
+                            updateOomAdjLocked();
+                        }
+                        return;
+                    }
+                    r = mOrderedBroadcasts.get(0);
+                    boolean forceReceive = false;
+
+                    // Ensure that even if something goes awry with the timeout
+                    // detection, we catch "hung" broadcasts here, discard them,
+                    // and continue to make progress.
+                    //
+                    // This is only done if the system is ready so that PRE_BOOT_COMPLETED
+                    // receivers don't get executed with timeouts. They're intended for
+                    // one time heavy lifting after system upgrades and can take
+                    // significant amounts of time.
+                    int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
+                    if (mProcessesReady && r.dispatchTime > 0) {
+                        long now = SystemClock.uptimeMillis();
+                        if ((numReceivers > 0) &&
+                                (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
+                            Slog.w(TAG, "Hung broadcast ["
+                                    + mQueueName + "] discarded after timeout failure:"
+                                    + " now=" + now
+                                    + " dispatchTime=" + r.dispatchTime
+                                    + " startTime=" + r.receiverTime
+                                    + " intent=" + r.intent
+                                    + " numReceivers=" + numReceivers
+                                    + " nextReceiver=" + r.nextReceiver
+                                    + " state=" + r.state);
+                            broadcastTimeoutLocked(false); // forcibly finish this broadcast
+                            forceReceive = true;
+                            r.state = BroadcastRecord.IDLE;
+                        }
+                    }
+
+                    if (r.state != BroadcastRecord.IDLE) {
+                        if (DEBUG_BROADCAST) Slog.d(TAG,
+                                "processNextBroadcast("
+                                + mQueueName + ") called when not idle (state="
+                                + r.state + ")");
+                        return;
+                    }
+
+                    if (r.receivers == null || r.nextReceiver >= numReceivers
+                            || r.resultAbort || forceReceive) {
+                        // No more receivers for this broadcast!  Send the final
+                        // result if requested...
+                        if (r.resultTo != null) {
+                            try {
+                                if (DEBUG_BROADCAST) {
+                                    int seq = r.intent.getIntExtra("seq", -1);
+                                    Slog.i(TAG, "Finishing broadcast ["
+                                            + mQueueName + "] " + r.intent.getAction()
+                                            + " seq=" + seq + " app=" + r.callerApp);
+                                }
+                                performReceiveLocked(r.callerApp, r.resultTo,
+                                    new Intent(r.intent), r.resultCode,
+                                    r.resultData, r.resultExtras, false, false);
+                                // Set this to null so that the reference
+                                // (local and remote) isnt kept in the mBroadcastHistory.
+                                r.resultTo = null;
+                            } catch (RemoteException e) {
+                                Slog.w(TAG, "Failure ["
+                                        + mQueueName + "] sending broadcast result of "
+                                        + r.intent, e);
+                            }
+                        }
+
+                        if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
+                        cancelBroadcastTimeoutLocked();
+
+                        if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast "
+                                + r);
+
+                        // ... and on to the next...
+                        addBroadcastToHistoryLocked(r);
+                        mOrderedBroadcasts.remove(0);
+                        r = null;
+                        looped = true;
+                        continue;
+                    }
+                } while (r == null);
+
+                // Get the next receiver...
+                int recIdx = r.nextReceiver++;
+
+                // Keep track of when this receiver started, and make sure there
+                // is a timeout message pending to kill it if need be.
+                r.receiverTime = SystemClock.uptimeMillis();
+                if (recIdx == 0) {
+                    r.dispatchTime = r.receiverTime;
+                    r.dispatchClockTime = System.currentTimeMillis();
+                    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast ["
+                            + mQueueName + "] " + r);
+                }
+                if (! mPendingBroadcastTimeoutMessage) {
+                    long timeoutTime = r.receiverTime + mTimeoutPeriod;
+                    if (DEBUG_BROADCAST) Slog.v(TAG,
+                            "Submitting BROADCAST_TIMEOUT_MSG ["
+                            + mQueueName + "] for " + r + " at " + timeoutTime);
+                    setBroadcastTimeoutLocked(timeoutTime);
+                }
+
+                Object nextReceiver = r.receivers.get(recIdx);
+                if (nextReceiver instanceof BroadcastFilter) {
+                    // Simple case: this is a registered receiver who gets
+                    // a direct call.
+                    BroadcastFilter filter = (BroadcastFilter)nextReceiver;
+                    if (DEBUG_BROADCAST)  Slog.v(TAG,
+                            "Delivering ordered ["
+                            + mQueueName + "] to registered "
+                            + filter + ": " + r);
+                    deliverToRegisteredReceiverLocked(r, filter, r.ordered);
+                    if (r.receiver == null || !r.ordered) {
+                        // The receiver has already finished, so schedule to
+                        // process the next one.
+                        if (DEBUG_BROADCAST) Slog.v(TAG, "Quick finishing ["
+                                + mQueueName + "]: ordered="
+                                + r.ordered + " receiver=" + r.receiver);
+                        r.state = BroadcastRecord.IDLE;
+                        scheduleBroadcastsLocked();
+                    }
+                    return;
+                }
+
+                // Hard case: need to instantiate the receiver, possibly
+                // starting its application process to host it.
+
+                ResolveInfo info =
+                    (ResolveInfo)nextReceiver;
+
+                boolean skip = false;
+                int perm = checkComponentPermission(info.activityInfo.permission,
+                        r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
+                        info.activityInfo.exported);
+                if (perm != PackageManager.PERMISSION_GRANTED) {
+                    if (!info.activityInfo.exported) {
+                        Slog.w(TAG, "Permission Denial: broadcasting "
+                                + r.intent.toString()
+                                + " from " + r.callerPackage + " (pid=" + r.callingPid
+                                + ", uid=" + r.callingUid + ")"
+                                + " is not exported from uid " + info.activityInfo.applicationInfo.uid
+                                + " due to receiver " + info.activityInfo.packageName
+                                + "/" + info.activityInfo.name);
+                    } else {
+                        Slog.w(TAG, "Permission Denial: broadcasting "
+                                + r.intent.toString()
+                                + " from " + r.callerPackage + " (pid=" + r.callingPid
+                                + ", uid=" + r.callingUid + ")"
+                                + " requires " + info.activityInfo.permission
+                                + " due to receiver " + info.activityInfo.packageName
+                                + "/" + info.activityInfo.name);
+                    }
+                    skip = true;
+                }
+                if (info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
+                    r.requiredPermission != null) {
+                    try {
+                        perm = AppGlobals.getPackageManager().
+                                checkPermission(r.requiredPermission,
+                                        info.activityInfo.applicationInfo.packageName);
+                    } catch (RemoteException e) {
+                        perm = PackageManager.PERMISSION_DENIED;
+                    }
+                    if (perm != PackageManager.PERMISSION_GRANTED) {
+                        Slog.w(TAG, "Permission Denial: receiving "
+                                + r.intent + " to "
+                                + info.activityInfo.applicationInfo.packageName
+                                + " requires " + r.requiredPermission
+                                + " due to sender " + r.callerPackage
+                                + " (uid " + r.callingUid + ")");
+                        skip = true;
+                    }
+                }
+                if (r.curApp != null && r.curApp.crashing) {
+                    // If the target process is crashing, just skip it.
+                    if (DEBUG_BROADCAST)  Slog.v(TAG,
+                            "Skipping deliver ordered ["
+                            + mQueueName + "] " + r + " to " + r.curApp
+                            + ": process crashing");
+                    skip = true;
+                }
+
+                if (skip) {
+                    if (DEBUG_BROADCAST)  Slog.v(TAG,
+                            "Skipping delivery of ordered ["
+                            + mQueueName + "] " + r + " for whatever reason");
+                    r.receiver = null;
+                    r.curFilter = null;
+                    r.state = BroadcastRecord.IDLE;
+                    scheduleBroadcastsLocked();
+                    return;
+                }
+
+                r.state = BroadcastRecord.APP_RECEIVE;
+                String targetProcess = info.activityInfo.processName;
+                r.curComponent = new ComponentName(
+                        info.activityInfo.applicationInfo.packageName,
+                        info.activityInfo.name);
+                r.curReceiver = info.activityInfo;
+
+                // Broadcast is being executed, its package can't be stopped.
+                try {
+                    AppGlobals.getPackageManager().setPackageStoppedState(
+                            r.curComponent.getPackageName(), false);
+                } catch (RemoteException e) {
+                } catch (IllegalArgumentException e) {
+                    Slog.w(TAG, "Failed trying to unstop package "
+                            + r.curComponent.getPackageName() + ": " + e);
+                }
+
+                // Is this receiver's application already running?
+                ProcessRecord app = getProcessRecordLocked(targetProcess,
+                        info.activityInfo.applicationInfo.uid);
+                if (app != null && app.thread != null) {
+                    try {
+                        app.addPackage(info.activityInfo.packageName);
+                        processCurBroadcastLocked(r, app);
+                        return;
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, "Exception when sending broadcast to "
+                              + r.curComponent, e);
+                    }
+
+                    // If a dead object exception was thrown -- fall through to
+                    // restart the application.
+                }
+
+                // Not running -- get it started, to be executed when the app comes up.
+                if (DEBUG_BROADCAST)  Slog.v(TAG,
+                        "Need to start app ["
+                        + mQueueName + "] " + targetProcess + " for broadcast " + r);
+                if ((r.curApp=startProcessLocked(targetProcess,
+                        info.activityInfo.applicationInfo, true,
+                        r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
+                        "broadcast", r.curComponent,
+                        (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
+                                == null) {
+                    // Ah, this recipient is unavailable.  Finish it if necessary,
+                    // and mark the broadcast record as ready for the next.
+                    Slog.w(TAG, "Unable to launch app "
+                            + info.activityInfo.applicationInfo.packageName + "/"
+                            + info.activityInfo.applicationInfo.uid + " for broadcast "
+                            + r.intent + ": process is bad");
+                    logBroadcastReceiverDiscardLocked(r);
+                    finishReceiverLocked(r, r.resultCode, r.resultData,
+                            r.resultExtras, r.resultAbort, true);
+                    scheduleBroadcastsLocked();
+                    r.state = BroadcastRecord.IDLE;
+                    return;
+                }
+
+                mPendingBroadcast = r;
+                mPendingBroadcastRecvIndex = recIdx;
+            }
+        }
+
+        final void setBroadcastTimeoutLocked(long timeoutTime) {
+            if (! mPendingBroadcastTimeoutMessage) {
+                Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
+                mHandler.sendMessageAtTime(msg, timeoutTime);
+                mPendingBroadcastTimeoutMessage = true;
+            }
+        }
+
+        final void cancelBroadcastTimeoutLocked() {
+            if (mPendingBroadcastTimeoutMessage) {
+                mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
+                mPendingBroadcastTimeoutMessage = false;
+            }
+        }
+
+        final void broadcastTimeoutLocked(boolean fromMsg) {
+            if (fromMsg) {
+                mPendingBroadcastTimeoutMessage = false;
+            }
+
+            if (mOrderedBroadcasts.size() == 0) {
+                return;
+            }
+
+            long now = SystemClock.uptimeMillis();
+            BroadcastRecord r = mOrderedBroadcasts.get(0);
+            if (fromMsg) {
+                if (mDidDexOpt) {
+                    // Delay timeouts until dexopt finishes.
+                    mDidDexOpt = false;
+                    long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod;
+                    setBroadcastTimeoutLocked(timeoutTime);
+                    return;
+                }
+                if (! mProcessesReady) {
+                    // Only process broadcast timeouts if the system is ready. That way
+                    // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended
+                    // to do heavy lifting for system up.
+                    return;
+                }
+
+                long timeoutTime = r.receiverTime + mTimeoutPeriod;
+                if (timeoutTime > now) {
+                    // We can observe premature timeouts because we do not cancel and reset the
+                    // broadcast timeout message after each receiver finishes.  Instead, we set up
+                    // an initial timeout then kick it down the road a little further as needed
+                    // when it expires.
+                    if (DEBUG_BROADCAST) Slog.v(TAG,
+                            "Premature timeout ["
+                            + mQueueName + "] @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
+                            + timeoutTime);
+                    setBroadcastTimeoutLocked(timeoutTime);
+                    return;
+                }
+            }
+
+            Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
+                    + ", started " + (now - r.receiverTime) + "ms ago");
+            r.receiverTime = now;
+            r.anrCount++;
+
+            // Current receiver has passed its expiration date.
+            if (r.nextReceiver <= 0) {
+                Slog.w(TAG, "Timeout on receiver with nextReceiver <= 0");
+                return;
+            }
+
+            ProcessRecord app = null;
+            String anrMessage = null;
+
+            Object curReceiver = r.receivers.get(r.nextReceiver-1);
+            Slog.w(TAG, "Receiver during timeout: " + curReceiver);
+            logBroadcastReceiverDiscardLocked(r);
+            if (curReceiver instanceof BroadcastFilter) {
+                BroadcastFilter bf = (BroadcastFilter)curReceiver;
+                if (bf.receiverList.pid != 0
+                        && bf.receiverList.pid != MY_PID) {
+                    synchronized (ActivityManagerService.this.mPidsSelfLocked) {
+                        app = ActivityManagerService.this.mPidsSelfLocked.get(
+                                bf.receiverList.pid);
+                    }
+                }
+            } else {
+                app = r.curApp;
+            }
+
+            if (app != null) {
+                anrMessage = "Broadcast of " + r.intent.toString();
+            }
+
+            if (mPendingBroadcast == r) {
+                mPendingBroadcast = null;
+            }
+
+            // Move on to the next receiver.
+            finishReceiverLocked(r, r.resultCode, r.resultData,
+                    r.resultExtras, r.resultAbort, true);
+            scheduleBroadcastsLocked();
+
+            if (anrMessage != null) {
+                // Post the ANR to the handler since we do not want to process ANRs while
+                // potentially holding our lock.
+                mHandler.post(new AppNotResponding(app, anrMessage));
+            }
+        }
+
+        private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
+            if (r.callingUid < 0) {
+                // This was from a registerReceiver() call; ignore it.
+                return;
+            }
+            System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
+                    MAX_BROADCAST_HISTORY-1);
+            r.finishTime = SystemClock.uptimeMillis();
+            mBroadcastHistory[0] = r;
+        }
+
+        final void logBroadcastReceiverDiscardLocked(BroadcastRecord r) {
+            if (r.nextReceiver > 0) {
+                Object curReceiver = r.receivers.get(r.nextReceiver-1);
+                if (curReceiver instanceof BroadcastFilter) {
+                    BroadcastFilter bf = (BroadcastFilter) curReceiver;
+                    EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
+                            System.identityHashCode(r),
+                            r.intent.getAction(),
+                            r.nextReceiver - 1,
+                            System.identityHashCode(bf));
+                } else {
+                    EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
+                            System.identityHashCode(r),
+                            r.intent.getAction(),
+                            r.nextReceiver - 1,
+                            ((ResolveInfo)curReceiver).toString());
+                }
+            } else {
+                Slog.w(TAG, "Discarding broadcast before first receiver is invoked: "
+                        + r);
+                EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
+                        System.identityHashCode(r),
+                        r.intent.getAction(),
+                        r.nextReceiver,
+                        "NONE");
+            }
+        }
+
+        final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+                int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
+            if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
+                    || mPendingBroadcast != null) {
+                boolean printed = false;
+                for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
+                    BroadcastRecord br = mParallelBroadcasts.get(i);
+                    if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
+                        continue;
+                    }
+                    if (!printed) {
+                        if (needSep) {
+                            pw.println();
+                            needSep = false;
+                        }
+                        printed = true;
+                        pw.println("  Active broadcasts [" + mQueueName + "]:");
+                    }
+                    pw.println("  Broadcast #" + i + ":");
+                    br.dump(pw, "    ");
+                }
+                printed = false;
+                needSep = true;
+                for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
+                    BroadcastRecord br = mOrderedBroadcasts.get(i);
+                    if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
+                        continue;
+                    }
+                    if (!printed) {
+                        if (needSep) {
+                            pw.println();
+                        }
+                        needSep = true;
+                        pw.println("  Active ordered broadcasts [" + mQueueName + "]:");
+                    }
+                    pw.println("  Ordered Broadcast #" + i + ":");
+                    mOrderedBroadcasts.get(i).dump(pw, "    ");
+                }
+                if (dumpPackage == null || (mPendingBroadcast != null
+                        && dumpPackage.equals(mPendingBroadcast.callerPackage))) {
+                    if (needSep) {
+                        pw.println();
+                    }
+                    pw.println("  Pending broadcast [" + mQueueName + "]:");
+                    if (mPendingBroadcast != null) {
+                        mPendingBroadcast.dump(pw, "    ");
+                    } else {
+                        pw.println("    (null)");
+                    }
+                    needSep = true;
+                }
+            }
+
+            boolean printed = false;
+            for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
+                BroadcastRecord r = mBroadcastHistory[i];
+                if (r == null) {
+                    break;
+                }
+                if (dumpPackage != null && !dumpPackage.equals(r.callerPackage)) {
+                    continue;
+                }
+                if (!printed) {
+                    if (needSep) {
+                        pw.println();
+                    }
+                    needSep = true;
+                    pw.println("  Historical broadcasts [" + mQueueName + "]:");
+                    printed = true;
+                }
+                if (dumpAll) {
+                    pw.print("  Historical Broadcast #"); pw.print(i); pw.println(":");
+                    r.dump(pw, "    ");
+                } else {
+                    if (i >= 50) {
+                        pw.println("  ...");
+                        break;
+                    }
+                    pw.print("  #"); pw.print(i); pw.print(": "); pw.println(r);
+                }
+            }
+
+            return needSep;
+        }
+    }
+
+    final BroadcastQueue mFgBroadcastQueue = new BroadcastQueue("foreground", BROADCAST_FG_TIMEOUT);
+    final BroadcastQueue mBgBroadcastQueue = new BroadcastQueue("background", BROADCAST_BG_TIMEOUT);
+    // Convenient for easy iteration over the queues. Foreground is first
+    // so that dispatch of foreground broadcasts gets precedence.
+    final BroadcastQueue[] mBroadcastQueues = { mFgBroadcastQueue, mBgBroadcastQueue };
+
+    BroadcastQueue broadcastQueueForIntent(Intent intent) {
+        final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
+        if (DEBUG_BACKGROUND_BROADCAST) {
+            Slog.i(TAG, "Broadcast intent " + intent + " on "
+                    + (isFg ? "foreground" : "background")
+                    + " queue");
+        }
+        return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;
+    }
+
+    BroadcastRecord broadcastRecordForReceiverLocked(IBinder receiver) {
+        for (BroadcastQueue queue : mBroadcastQueues) {
+            BroadcastRecord r = queue.getMatchingOrderedReceiver(receiver);
+            if (r != null) {
+                return r;
+            }
+        }
+        return null;
+    }
 
     /**
      * Activity we have told the window manager to have key focus.
@@ -456,25 +1248,6 @@
     private final StringBuilder mStrictModeBuffer = new StringBuilder();
 
     /**
-     * True if we have a pending unexpired BROADCAST_TIMEOUT_MSG posted to our handler.
-     */
-    private boolean mPendingBroadcastTimeoutMessage;
-
-    /**
-     * Intent broadcast that we have tried to start, but are
-     * waiting for its application's process to be created.  We only
-     * need one (instead of a list) because we always process broadcasts
-     * one at a time, so no others can be started while waiting for this
-     * one.
-     */
-    BroadcastRecord mPendingBroadcast = null;
-
-    /**
-     * The receiver index that is pending, to restart the broadcast if needed.
-     */
-    int mPendingBroadcastRecvIndex;
-
-    /**
      * Keeps track of all IIntentReceivers that have been registered for
      * broadcasts.  Hash keys are the receiver IBinder, hash value is
      * a ReceiverList.
@@ -910,7 +1683,8 @@
                     
                     Intent intent = new Intent("android.intent.action.ANR");
                     if (!mProcessesReady) {
-                        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                                | Intent.FLAG_RECEIVER_FOREGROUND);
                     }
                     broadcastIntentLocked(null, null, intent,
                             null, null, 0, null, null, null,
@@ -987,11 +1761,13 @@
             case BROADCAST_INTENT_MSG: {
                 if (DEBUG_BROADCAST) Slog.v(
                         TAG, "Received BROADCAST_INTENT_MSG");
-                processNextBroadcast(true);
+                BroadcastQueue queue = (BroadcastQueue) msg.obj;
+                queue.processNextBroadcast(true);
             } break;
             case BROADCAST_TIMEOUT_MSG: {
+                final BroadcastQueue queue = (BroadcastQueue) msg.obj;
                 synchronized (ActivityManagerService.this) {
-                    broadcastTimeoutLocked(true);
+                    queue.broadcastTimeoutLocked(true);
                 }
             } break;
             case SERVICE_TIMEOUT_MSG: {
@@ -3708,12 +4484,9 @@
                     // Can't happen; the backup manager is local
                 }
             }
-            if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
+            if (isPendingBroadcastProcessLocked(pid)) {
                 Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
-                mPendingBroadcast.state = BroadcastRecord.IDLE;
-                mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
-                mPendingBroadcast = null;
-                scheduleBroadcastsLocked();
+                skipPendingBroadcastLocked(pid);
             }
         } else {
             Slog.w(TAG, "Spurious process start timeout - pid not known for " + app);
@@ -3912,23 +4685,13 @@
             }
         }
 
-        // Check if the next broadcast receiver is in this process...
-        BroadcastRecord br = mPendingBroadcast;
-        if (!badApp && br != null && br.curApp == app) {
+        // Check if a next-broadcast receiver is in this process...
+        if (!badApp && isPendingBroadcastProcessLocked(pid)) {
             try {
-                mPendingBroadcast = null;
-                processCurBroadcastLocked(br, app);
-                didSomething = true;
+                didSomething = sendPendingBroadcastsLocked(app);
             } catch (Exception e) {
-                Slog.w(TAG, "Exception in new application when starting receiver "
-                      + br.curComponent.flattenToShortString(), e);
+                // If the app died trying to launch the receiver we declare it 'bad'
                 badApp = true;
-                logBroadcastReceiverDiscardLocked(br);
-                finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
-                        br.resultExtras, br.resultAbort, true);
-                scheduleBroadcastsLocked();
-                // We need to reset the state if we fails to start the receiver.
-                br.state = BroadcastRecord.IDLE;
             }
         }
 
@@ -7227,28 +7990,8 @@
     }
 
     void skipCurrentReceiverLocked(ProcessRecord app) {
-        boolean reschedule = false;
-        BroadcastRecord r = app.curReceiver;
-        if (r != null) {
-            // The current broadcast is waiting for this app's receiver
-            // to be finished.  Looks like that's not going to happen, so
-            // let the broadcast continue.
-            logBroadcastReceiverDiscardLocked(r);
-            finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
-                    r.resultExtras, r.resultAbort, true);
-            reschedule = true;
-        }
-        r = mPendingBroadcast;
-        if (r != null && r.curApp == app) {
-            if (DEBUG_BROADCAST) Slog.v(TAG,
-                    "skip & discard pending app " + r);
-            logBroadcastReceiverDiscardLocked(r);
-            finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
-                    r.resultExtras, r.resultAbort, true);
-            reschedule = true;
-        }
-        if (reschedule) {
-            scheduleBroadcastsLocked();
+        for (BroadcastQueue queue : mBroadcastQueues) {
+            queue.skipCurrentReceiverLocked(app);
         }
     }
 
@@ -8971,84 +9714,11 @@
                 needSep = true;
             }
         }
-        
-        if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
-                || mPendingBroadcast != null) {
-            boolean printed = false;
-            for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
-                BroadcastRecord br = mParallelBroadcasts.get(i);
-                if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
-                    continue;
-                }
-                if (!printed) {
-                    if (needSep) {
-                        pw.println();
-                    }
-                    needSep = true;
-                    pw.println("  Active broadcasts:");
-                }
-                pw.println("  Broadcast #" + i + ":");
-                br.dump(pw, "    ");
-            }
-            printed = false;
-            for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
-                BroadcastRecord br = mOrderedBroadcasts.get(i);
-                if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
-                    continue;
-                }
-                if (!printed) {
-                    if (needSep) {
-                        pw.println();
-                    }
-                    needSep = true;
-                    pw.println("  Active ordered broadcasts:");
-                }
-                pw.println("  Ordered Broadcast #" + i + ":");
-                mOrderedBroadcasts.get(i).dump(pw, "    ");
-            }
-            if (dumpPackage == null || (mPendingBroadcast != null
-                    && dumpPackage.equals(mPendingBroadcast.callerPackage))) {
-                if (needSep) {
-                    pw.println();
-                }
-                pw.println("  Pending broadcast:");
-                if (mPendingBroadcast != null) {
-                    mPendingBroadcast.dump(pw, "    ");
-                } else {
-                    pw.println("    (null)");
-                }
-                needSep = true;
-            }
+
+        for (BroadcastQueue q : mBroadcastQueues) {
+            needSep = q.dumpLocked(fd, pw, args, opti, dumpAll, dumpPackage, needSep);
         }
 
-        boolean printed = false;
-        for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
-            BroadcastRecord r = mBroadcastHistory[i];
-            if (r == null) {
-                break;
-            }
-            if (dumpPackage != null && !dumpPackage.equals(r.callerPackage)) {
-                continue;
-            }
-            if (!printed) {
-                if (needSep) {
-                    pw.println();
-                }
-                needSep = true;
-                pw.println("  Historical broadcasts:");
-                printed = true;
-            }
-            if (dumpAll) {
-                pw.print("  Historical Broadcast #"); pw.print(i); pw.println(":");
-                r.dump(pw, "    ");
-            } else {
-                if (i >= 50) {
-                    pw.println("  ...");
-                    break;
-                }
-                pw.print("  #"); pw.print(i); pw.print(": "); pw.println(r);
-            }
-        }
         needSep = true;
         
         if (mStickyBroadcasts != null && dumpPackage == null) {
@@ -9085,7 +9755,10 @@
         
         if (dumpAll) {
             pw.println();
-            pw.println("  mBroadcastsScheduled=" + mBroadcastsScheduled);
+            for (BroadcastQueue queue : mBroadcastQueues) {
+                pw.println("  mBroadcastsScheduled [" + queue.mQueueName + "]="
+                        + queue.mBroadcastsScheduled);
+            }
             pw.println("  mHandler:");
             mHandler.dump(new PrintWriterPrinter(pw), "    ");
             needSep = true;
@@ -12072,15 +12745,25 @@
         return cur;
     }
 
-    private final void scheduleBroadcastsLocked() {
-        if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts: current="
-                + mBroadcastsScheduled);
+    boolean isPendingBroadcastProcessLocked(int pid) {
+        return mFgBroadcastQueue.isPendingBroadcastProcessLocked(pid)
+                || mBgBroadcastQueue.isPendingBroadcastProcessLocked(pid);
+    }
 
-        if (mBroadcastsScheduled) {
-            return;
+    void skipPendingBroadcastLocked(int pid) {
+            Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
+            for (BroadcastQueue queue : mBroadcastQueues) {
+                queue.skipPendingBroadcastLocked(pid);
+            }
+    }
+
+    // The app just attached; send any pending broadcasts that it should receive
+    boolean sendPendingBroadcastsLocked(ProcessRecord app) {
+        boolean didSomething = false;
+        for (BroadcastQueue queue : mBroadcastQueues) {
+            didSomething |= queue.sendPendingBroadcastsLocked(app);
         }
-        mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
-        mBroadcastsScheduled = true;
+        return didSomething;
     }
 
     public Intent registerReceiver(IApplicationThread caller, String callerPackage,
@@ -12162,13 +12845,12 @@
                 int N = allSticky.size();
                 for (int i=0; i<N; i++) {
                     Intent intent = (Intent)allSticky.get(i);
-                    BroadcastRecord r = new BroadcastRecord(intent, null,
+                    BroadcastQueue queue = broadcastQueueForIntent(intent);
+                    BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                             null, -1, -1, null, receivers, null, 0, null, null,
                             false, true, true);
-                    if (mParallelBroadcasts.size() == 0) {
-                        scheduleBroadcastsLocked();
-                    }
-                    mParallelBroadcasts.add(r);
+                    queue.enqueueParallelBroadcastLocked(r);
+                    queue.scheduleBroadcastsLocked();
                 }
             }
 
@@ -12179,38 +12861,46 @@
     public void unregisterReceiver(IIntentReceiver receiver) {
         if (DEBUG_BROADCAST) Slog.v(TAG, "Unregister receiver: " + receiver);
 
-        boolean doNext = false;
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            boolean doTrim = false;
 
-        synchronized(this) {
-            ReceiverList rl
+            synchronized(this) {
+                ReceiverList rl
                 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
-            if (rl != null) {
-                if (rl.curBroadcast != null) {
-                    BroadcastRecord r = rl.curBroadcast;
-                    doNext = finishReceiverLocked(
-                        receiver.asBinder(), r.resultCode, r.resultData,
-                        r.resultExtras, r.resultAbort, true);
-                }
+                if (rl != null) {
+                    if (rl.curBroadcast != null) {
+                        BroadcastRecord r = rl.curBroadcast;
+                        final boolean doNext = finishReceiverLocked(
+                                receiver.asBinder(), r.resultCode, r.resultData,
+                                r.resultExtras, r.resultAbort, true);
+                        if (doNext) {
+                            doTrim = true;
+                            r.queue.processNextBroadcast(false);
+                        }
+                    }
 
-                if (rl.app != null) {
-                    rl.app.receivers.remove(rl);
-                }
-                removeReceiverLocked(rl);
-                if (rl.linkedToDeath) {
-                    rl.linkedToDeath = false;
-                    rl.receiver.asBinder().unlinkToDeath(rl, 0);
+                    if (rl.app != null) {
+                        rl.app.receivers.remove(rl);
+                    }
+                    removeReceiverLocked(rl);
+                    if (rl.linkedToDeath) {
+                        rl.linkedToDeath = false;
+                        rl.receiver.asBinder().unlinkToDeath(rl, 0);
+                    }
                 }
             }
-        }
 
-        if (!doNext) {
-            return;
+            // If we actually concluded any broadcasts, we might now be able
+            // to trim the recipients' apps from our working set
+            if (doTrim) {
+                trimApplications();
+                return;
+            }
+
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
-        
-        final long origId = Binder.clearCallingIdentity();
-        processNextBroadcast(false);
-        trimApplications();
-        Binder.restoreCallingIdentity(origId);
     }
 
     void removeReceiverLocked(ReceiverList rl) {
@@ -12440,28 +13130,17 @@
             // If we are not serializing this broadcast, then send the
             // registered receivers separately so they don't wait for the
             // components to be launched.
-            BroadcastRecord r = new BroadcastRecord(intent, callerApp,
+            final BroadcastQueue queue = broadcastQueueForIntent(intent);
+            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                     callerPackage, callingPid, callingUid, requiredPermission,
                     registeredReceivers, resultTo, resultCode, resultData, map,
                     ordered, sticky, false);
             if (DEBUG_BROADCAST) Slog.v(
-                    TAG, "Enqueueing parallel broadcast " + r
-                    + ": prev had " + mParallelBroadcasts.size());
-            boolean replaced = false;
-            if (replacePending) {
-                for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
-                    if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
-                        if (DEBUG_BROADCAST) Slog.v(TAG,
-                                "***** DROPPING PARALLEL: " + intent);
-                        mParallelBroadcasts.set(i, r);
-                        replaced = true;
-                        break;
-                    }
-                }
-            }
+                    TAG, "Enqueueing parallel broadcast " + r);
+            final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
             if (!replaced) {
-                mParallelBroadcasts.add(r);
-                scheduleBroadcastsLocked();
+                queue.enqueueParallelBroadcastLocked(r);
+                queue.scheduleBroadcastsLocked();
             }
             registeredReceivers = null;
             NR = 0;
@@ -12541,32 +13220,22 @@
 
         if ((receivers != null && receivers.size() > 0)
                 || resultTo != null) {
-            BroadcastRecord r = new BroadcastRecord(intent, callerApp,
+            BroadcastQueue queue = broadcastQueueForIntent(intent);
+            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                     callerPackage, callingPid, callingUid, requiredPermission,
                     receivers, resultTo, resultCode, resultData, map, ordered,
                     sticky, false);
             if (DEBUG_BROADCAST) Slog.v(
                     TAG, "Enqueueing ordered broadcast " + r
-                    + ": prev had " + mOrderedBroadcasts.size());
+                    + ": prev had " + queue.mOrderedBroadcasts.size());
             if (DEBUG_BROADCAST) {
                 int seq = r.intent.getIntExtra("seq", -1);
                 Slog.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
             }
-            boolean replaced = false;
-            if (replacePending) {
-                for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {
-                    if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
-                        if (DEBUG_BROADCAST) Slog.v(TAG,
-                                "***** DROPPING ORDERED: " + intent);
-                        mOrderedBroadcasts.set(i, r);
-                        replaced = true;
-                        break;
-                    }
-                }
-            }
+            boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r); 
             if (!replaced) {
-                mOrderedBroadcasts.add(r);
-                scheduleBroadcastsLocked();
+                queue.enqueueOrderedBroadcastLocked(r);
+                queue.scheduleBroadcastsLocked();
             }
         }
 
@@ -12673,54 +13342,14 @@
     private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
             String resultData, Bundle resultExtras, boolean resultAbort,
             boolean explicit) {
-        if (mOrderedBroadcasts.size() == 0) {
-            if (explicit) {
-                Slog.w(TAG, "finishReceiver called but no pending broadcasts");
-            }
+        final BroadcastRecord r = broadcastRecordForReceiverLocked(receiver);
+        if (r == null) {
+            Slog.w(TAG, "finishReceiver called but not found on queue");
             return false;
         }
-        BroadcastRecord r = mOrderedBroadcasts.get(0);
-        if (r.receiver == null) {
-            if (explicit) {
-                Slog.w(TAG, "finishReceiver called but none active");
-            }
-            return false;
-        }
-        if (r.receiver != receiver) {
-            Slog.w(TAG, "finishReceiver called but active receiver is different");
-            return false;
-        }
-        int state = r.state;
-        r.state = BroadcastRecord.IDLE;
-        if (state == BroadcastRecord.IDLE) {
-            if (explicit) {
-                Slog.w(TAG, "finishReceiver called but state is IDLE");
-            }
-        }
-        r.receiver = null;
-        r.intent.setComponent(null);
-        if (r.curApp != null) {
-            r.curApp.curReceiver = null;
-        }
-        if (r.curFilter != null) {
-            r.curFilter.receiverList.curBroadcast = null;
-        }
-        r.curFilter = null;
-        r.curApp = null;
-        r.curComponent = null;
-        r.curReceiver = null;
-        mPendingBroadcast = null;
 
-        r.resultCode = resultCode;
-        r.resultData = resultData;
-        r.resultExtras = resultExtras;
-        r.resultAbort = resultAbort;
-
-        // We will process the next receiver right now if this is finishing
-        // an app receiver (which is always asynchronous) or after we have
-        // come back from calling a receiver.
-        return state == BroadcastRecord.APP_RECEIVE
-                || state == BroadcastRecord.CALL_DONE_RECEIVE;
+        return r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort,
+                explicit);
     }
 
     public void finishReceiver(IBinder who, int resultCode, String resultData,
@@ -12732,153 +13361,25 @@
             throw new IllegalArgumentException("File descriptors passed in Bundle");
         }
 
-        boolean doNext;
-
         final long origId = Binder.clearCallingIdentity();
+        try {
+            boolean doNext = false;
+            BroadcastRecord r = null;
 
-        synchronized(this) {
-            doNext = finishReceiverLocked(
-                who, resultCode, resultData, resultExtras, resultAbort, true);
-        }
-
-        if (doNext) {
-            processNextBroadcast(false);
-        }
-        trimApplications();
-
-        Binder.restoreCallingIdentity(origId);
-    }
-
-    private final void logBroadcastReceiverDiscardLocked(BroadcastRecord r) {
-        if (r.nextReceiver > 0) {
-            Object curReceiver = r.receivers.get(r.nextReceiver-1);
-            if (curReceiver instanceof BroadcastFilter) {
-                BroadcastFilter bf = (BroadcastFilter) curReceiver;
-                EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
-                        System.identityHashCode(r),
-                        r.intent.getAction(),
-                        r.nextReceiver - 1,
-                        System.identityHashCode(bf));
-            } else {
-                EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
-                        System.identityHashCode(r),
-                        r.intent.getAction(),
-                        r.nextReceiver - 1,
-                        ((ResolveInfo)curReceiver).toString());
-            }
-        } else {
-            Slog.w(TAG, "Discarding broadcast before first receiver is invoked: "
-                    + r);
-            EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
-                    System.identityHashCode(r),
-                    r.intent.getAction(),
-                    r.nextReceiver,
-                    "NONE");
-        }
-    }
-
-    private final void setBroadcastTimeoutLocked(long timeoutTime) {
-        if (! mPendingBroadcastTimeoutMessage) {
-            Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
-            mHandler.sendMessageAtTime(msg, timeoutTime);
-            mPendingBroadcastTimeoutMessage = true;
-        }
-    }
-
-    private final void cancelBroadcastTimeoutLocked() {
-        if (mPendingBroadcastTimeoutMessage) {
-            mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
-            mPendingBroadcastTimeoutMessage = false;
-        }
-    }
-
-    private final void broadcastTimeoutLocked(boolean fromMsg) {
-        if (fromMsg) {
-            mPendingBroadcastTimeoutMessage = false;
-        }
-
-        if (mOrderedBroadcasts.size() == 0) {
-            return;
-        }
-
-        long now = SystemClock.uptimeMillis();
-        BroadcastRecord r = mOrderedBroadcasts.get(0);
-        if (fromMsg) {
-            if (mDidDexOpt) {
-                // Delay timeouts until dexopt finishes.
-                mDidDexOpt = false;
-                long timeoutTime = SystemClock.uptimeMillis() + BROADCAST_TIMEOUT;
-                setBroadcastTimeoutLocked(timeoutTime);
-                return;
-            }
-            if (! mProcessesReady) {
-                // Only process broadcast timeouts if the system is ready. That way
-                // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended
-                // to do heavy lifting for system up.
-                return;
-            }
-
-            long timeoutTime = r.receiverTime + BROADCAST_TIMEOUT;
-            if (timeoutTime > now) {
-                // We can observe premature timeouts because we do not cancel and reset the
-                // broadcast timeout message after each receiver finishes.  Instead, we set up
-                // an initial timeout then kick it down the road a little further as needed
-                // when it expires.
-                if (DEBUG_BROADCAST) Slog.v(TAG,
-                        "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
-                        + timeoutTime);
-                setBroadcastTimeoutLocked(timeoutTime);
-                return;
-            }
-        }
-
-        Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
-                + ", started " + (now - r.receiverTime) + "ms ago");
-        r.receiverTime = now;
-        r.anrCount++;
-
-        // Current receiver has passed its expiration date.
-        if (r.nextReceiver <= 0) {
-            Slog.w(TAG, "Timeout on receiver with nextReceiver <= 0");
-            return;
-        }
-
-        ProcessRecord app = null;
-        String anrMessage = null;
-
-        Object curReceiver = r.receivers.get(r.nextReceiver-1);
-        Slog.w(TAG, "Receiver during timeout: " + curReceiver);
-        logBroadcastReceiverDiscardLocked(r);
-        if (curReceiver instanceof BroadcastFilter) {
-            BroadcastFilter bf = (BroadcastFilter)curReceiver;
-            if (bf.receiverList.pid != 0
-                    && bf.receiverList.pid != MY_PID) {
-                synchronized (this.mPidsSelfLocked) {
-                    app = this.mPidsSelfLocked.get(
-                            bf.receiverList.pid);
+            synchronized(this) {
+                r = broadcastRecordForReceiverLocked(who);
+                if (r != null) {
+                    doNext = r.queue.finishReceiverLocked(r, resultCode,
+                        resultData, resultExtras, resultAbort, true);
                 }
             }
-        } else {
-            app = r.curApp;
-        }
-        
-        if (app != null) {
-            anrMessage = "Broadcast of " + r.intent.toString();
-        }
 
-        if (mPendingBroadcast == r) {
-            mPendingBroadcast = null;
-        }
-
-        // Move on to the next receiver.
-        finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
-                r.resultExtras, r.resultAbort, true);
-        scheduleBroadcastsLocked();
-
-        if (anrMessage != null) {
-            // Post the ANR to the handler since we do not want to process ANRs while
-            // potentially holding our lock.
-            mHandler.post(new AppNotResponding(app, anrMessage));
+            if (doNext) {
+                r.queue.processNextBroadcast(false);
+            }
+            trimApplications();
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
     }
 
@@ -13013,333 +13514,6 @@
         }
     }
 
-    private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
-        if (r.callingUid < 0) {
-            // This was from a registerReceiver() call; ignore it.
-            return;
-        }
-        System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
-                MAX_BROADCAST_HISTORY-1);
-        r.finishTime = SystemClock.uptimeMillis();
-        mBroadcastHistory[0] = r;
-    }
-    
-    private final void processNextBroadcast(boolean fromMsg) {
-        synchronized(this) {
-            BroadcastRecord r;
-
-            if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast: "
-                    + mParallelBroadcasts.size() + " broadcasts, "
-                    + mOrderedBroadcasts.size() + " ordered broadcasts");
-
-            updateCpuStats();
-            
-            if (fromMsg) {
-                mBroadcastsScheduled = false;
-            }
-
-            // First, deliver any non-serialized broadcasts right away.
-            while (mParallelBroadcasts.size() > 0) {
-                r = mParallelBroadcasts.remove(0);
-                r.dispatchTime = SystemClock.uptimeMillis();
-                r.dispatchClockTime = System.currentTimeMillis();
-                final int N = r.receivers.size();
-                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast "
-                        + r);
-                for (int i=0; i<N; i++) {
-                    Object target = r.receivers.get(i);
-                    if (DEBUG_BROADCAST)  Slog.v(TAG,
-                            "Delivering non-ordered to registered "
-                            + target + ": " + r);
-                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
-                }
-                addBroadcastToHistoryLocked(r);
-                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast "
-                        + r);
-            }
-
-            // Now take care of the next serialized one...
-
-            // If we are waiting for a process to come up to handle the next
-            // broadcast, then do nothing at this point.  Just in case, we
-            // check that the process we're waiting for still exists.
-            if (mPendingBroadcast != null) {
-                if (DEBUG_BROADCAST_LIGHT) {
-                    Slog.v(TAG, "processNextBroadcast: waiting for "
-                            + mPendingBroadcast.curApp);
-                }
-
-                boolean isDead;
-                synchronized (mPidsSelfLocked) {
-                    isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
-                }
-                if (!isDead) {
-                    // It's still alive, so keep waiting
-                    return;
-                } else {
-                    Slog.w(TAG, "pending app " + mPendingBroadcast.curApp
-                            + " died before responding to broadcast");
-                    mPendingBroadcast.state = BroadcastRecord.IDLE;
-                    mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
-                    mPendingBroadcast = null;
-                }
-            }
-
-            boolean looped = false;
-            
-            do {
-                if (mOrderedBroadcasts.size() == 0) {
-                    // No more broadcasts pending, so all done!
-                    scheduleAppGcsLocked();
-                    if (looped) {
-                        // If we had finished the last ordered broadcast, then
-                        // make sure all processes have correct oom and sched
-                        // adjustments.
-                        updateOomAdjLocked();
-                    }
-                    return;
-                }
-                r = mOrderedBroadcasts.get(0);
-                boolean forceReceive = false;
-
-                // Ensure that even if something goes awry with the timeout
-                // detection, we catch "hung" broadcasts here, discard them,
-                // and continue to make progress.
-                //
-                // This is only done if the system is ready so that PRE_BOOT_COMPLETED
-                // receivers don't get executed with timeouts. They're intended for
-                // one time heavy lifting after system upgrades and can take
-                // significant amounts of time.
-                int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
-                if (mProcessesReady && r.dispatchTime > 0) {
-                    long now = SystemClock.uptimeMillis();
-                    if ((numReceivers > 0) &&
-                            (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
-                        Slog.w(TAG, "Hung broadcast discarded after timeout failure:"
-                                + " now=" + now
-                                + " dispatchTime=" + r.dispatchTime
-                                + " startTime=" + r.receiverTime
-                                + " intent=" + r.intent
-                                + " numReceivers=" + numReceivers
-                                + " nextReceiver=" + r.nextReceiver
-                                + " state=" + r.state);
-                        broadcastTimeoutLocked(false); // forcibly finish this broadcast
-                        forceReceive = true;
-                        r.state = BroadcastRecord.IDLE;
-                    }
-                }
-
-                if (r.state != BroadcastRecord.IDLE) {
-                    if (DEBUG_BROADCAST) Slog.d(TAG,
-                            "processNextBroadcast() called when not idle (state="
-                            + r.state + ")");
-                    return;
-                }
-
-                if (r.receivers == null || r.nextReceiver >= numReceivers
-                        || r.resultAbort || forceReceive) {
-                    // No more receivers for this broadcast!  Send the final
-                    // result if requested...
-                    if (r.resultTo != null) {
-                        try {
-                            if (DEBUG_BROADCAST) {
-                                int seq = r.intent.getIntExtra("seq", -1);
-                                Slog.i(TAG, "Finishing broadcast " + r.intent.getAction()
-                                        + " seq=" + seq + " app=" + r.callerApp);
-                            }
-                            performReceiveLocked(r.callerApp, r.resultTo,
-                                new Intent(r.intent), r.resultCode,
-                                r.resultData, r.resultExtras, false, false);
-                            // Set this to null so that the reference
-                            // (local and remote) isnt kept in the mBroadcastHistory.
-                            r.resultTo = null;
-                        } catch (RemoteException e) {
-                            Slog.w(TAG, "Failure sending broadcast result of " + r.intent, e);
-                        }
-                    }
-                    
-                    if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
-                    cancelBroadcastTimeoutLocked();
-
-                    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast "
-                            + r);
-                    
-                    // ... and on to the next...
-                    addBroadcastToHistoryLocked(r);
-                    mOrderedBroadcasts.remove(0);
-                    r = null;
-                    looped = true;
-                    continue;
-                }
-            } while (r == null);
-
-            // Get the next receiver...
-            int recIdx = r.nextReceiver++;
-
-            // Keep track of when this receiver started, and make sure there
-            // is a timeout message pending to kill it if need be.
-            r.receiverTime = SystemClock.uptimeMillis();
-            if (recIdx == 0) {
-                r.dispatchTime = r.receiverTime;
-                r.dispatchClockTime = System.currentTimeMillis();
-                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast "
-                        + r);
-            }
-            if (! mPendingBroadcastTimeoutMessage) {
-                long timeoutTime = r.receiverTime + BROADCAST_TIMEOUT;
-                if (DEBUG_BROADCAST) Slog.v(TAG,
-                        "Submitting BROADCAST_TIMEOUT_MSG for " + r + " at " + timeoutTime);
-                setBroadcastTimeoutLocked(timeoutTime);
-            }
-
-            Object nextReceiver = r.receivers.get(recIdx);
-            if (nextReceiver instanceof BroadcastFilter) {
-                // Simple case: this is a registered receiver who gets
-                // a direct call.
-                BroadcastFilter filter = (BroadcastFilter)nextReceiver;
-                if (DEBUG_BROADCAST)  Slog.v(TAG,
-                        "Delivering ordered to registered "
-                        + filter + ": " + r);
-                deliverToRegisteredReceiverLocked(r, filter, r.ordered);
-                if (r.receiver == null || !r.ordered) {
-                    // The receiver has already finished, so schedule to
-                    // process the next one.
-                    if (DEBUG_BROADCAST) Slog.v(TAG, "Quick finishing: ordered="
-                            + r.ordered + " receiver=" + r.receiver);
-                    r.state = BroadcastRecord.IDLE;
-                    scheduleBroadcastsLocked();
-                }
-                return;
-            }
-
-            // Hard case: need to instantiate the receiver, possibly
-            // starting its application process to host it.
-
-            ResolveInfo info =
-                (ResolveInfo)nextReceiver;
-
-            boolean skip = false;
-            int perm = checkComponentPermission(info.activityInfo.permission,
-                    r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
-                    info.activityInfo.exported);
-            if (perm != PackageManager.PERMISSION_GRANTED) {
-                if (!info.activityInfo.exported) {
-                    Slog.w(TAG, "Permission Denial: broadcasting "
-                            + r.intent.toString()
-                            + " from " + r.callerPackage + " (pid=" + r.callingPid
-                            + ", uid=" + r.callingUid + ")"
-                            + " is not exported from uid " + info.activityInfo.applicationInfo.uid
-                            + " due to receiver " + info.activityInfo.packageName
-                            + "/" + info.activityInfo.name);
-                } else {
-                    Slog.w(TAG, "Permission Denial: broadcasting "
-                            + r.intent.toString()
-                            + " from " + r.callerPackage + " (pid=" + r.callingPid
-                            + ", uid=" + r.callingUid + ")"
-                            + " requires " + info.activityInfo.permission
-                            + " due to receiver " + info.activityInfo.packageName
-                            + "/" + info.activityInfo.name);
-                }
-                skip = true;
-            }
-            if (info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
-                r.requiredPermission != null) {
-                try {
-                    perm = AppGlobals.getPackageManager().
-                            checkPermission(r.requiredPermission,
-                                    info.activityInfo.applicationInfo.packageName);
-                } catch (RemoteException e) {
-                    perm = PackageManager.PERMISSION_DENIED;
-                }
-                if (perm != PackageManager.PERMISSION_GRANTED) {
-                    Slog.w(TAG, "Permission Denial: receiving "
-                            + r.intent + " to "
-                            + info.activityInfo.applicationInfo.packageName
-                            + " requires " + r.requiredPermission
-                            + " due to sender " + r.callerPackage
-                            + " (uid " + r.callingUid + ")");
-                    skip = true;
-                }
-            }
-            if (r.curApp != null && r.curApp.crashing) {
-                // If the target process is crashing, just skip it.
-                if (DEBUG_BROADCAST)  Slog.v(TAG,
-                        "Skipping deliver ordered " + r + " to " + r.curApp
-                        + ": process crashing");
-                skip = true;
-            }
-
-            if (skip) {
-                if (DEBUG_BROADCAST)  Slog.v(TAG,
-                        "Skipping delivery of ordered " + r + " for whatever reason");
-                r.receiver = null;
-                r.curFilter = null;
-                r.state = BroadcastRecord.IDLE;
-                scheduleBroadcastsLocked();
-                return;
-            }
-
-            r.state = BroadcastRecord.APP_RECEIVE;
-            String targetProcess = info.activityInfo.processName;
-            r.curComponent = new ComponentName(
-                    info.activityInfo.applicationInfo.packageName,
-                    info.activityInfo.name);
-            r.curReceiver = info.activityInfo;
-
-            // Broadcast is being executed, its package can't be stopped.
-            try {
-                AppGlobals.getPackageManager().setPackageStoppedState(
-                        r.curComponent.getPackageName(), false);
-            } catch (RemoteException e) {
-            } catch (IllegalArgumentException e) {
-                Slog.w(TAG, "Failed trying to unstop package "
-                        + r.curComponent.getPackageName() + ": " + e);
-            }
-
-            // Is this receiver's application already running?
-            ProcessRecord app = getProcessRecordLocked(targetProcess,
-                    info.activityInfo.applicationInfo.uid);
-            if (app != null && app.thread != null) {
-                try {
-                    app.addPackage(info.activityInfo.packageName);
-                    processCurBroadcastLocked(r, app);
-                    return;
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Exception when sending broadcast to "
-                          + r.curComponent, e);
-                }
-
-                // If a dead object exception was thrown -- fall through to
-                // restart the application.
-            }
-
-            // Not running -- get it started, to be executed when the app comes up.
-            if (DEBUG_BROADCAST)  Slog.v(TAG,
-                    "Need to start app " + targetProcess + " for broadcast " + r);
-            if ((r.curApp=startProcessLocked(targetProcess,
-                    info.activityInfo.applicationInfo, true,
-                    r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
-                    "broadcast", r.curComponent,
-                    (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
-                            == null) {
-                // Ah, this recipient is unavailable.  Finish it if necessary,
-                // and mark the broadcast record as ready for the next.
-                Slog.w(TAG, "Unable to launch app "
-                        + info.activityInfo.applicationInfo.packageName + "/"
-                        + info.activityInfo.applicationInfo.uid + " for broadcast "
-                        + r.intent + ": process is bad");
-                logBroadcastReceiverDiscardLocked(r);
-                finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
-                        r.resultExtras, r.resultAbort, true);
-                scheduleBroadcastsLocked();
-                r.state = BroadcastRecord.IDLE;
-                return;
-            }
-
-            mPendingBroadcast = r;
-            mPendingBroadcastRecvIndex = recIdx;
-        }
-    }
 
     // =========================================================
     // INSTRUMENTATION
@@ -13663,6 +13837,28 @@
     // LIFETIME MANAGEMENT
     // =========================================================
 
+    // Returns which broadcast queue the app is the current [or imminent] receiver
+    // on, or 'null' if the app is not an active broadcast recipient.
+    private BroadcastQueue isReceivingBroadcast(ProcessRecord app) {
+        BroadcastRecord r = app.curReceiver;
+        if (r != null) {
+            return r.queue;
+        }
+
+        // It's not the current receiver, but it might be starting up to become one
+        synchronized (this) {
+            for (BroadcastQueue queue : mBroadcastQueues) {
+                r = queue.mPendingBroadcast;
+                if (r != null && r.curApp == app) {
+                    // found it; report which queue it's in
+                    return queue;
+                }
+            }
+        }
+
+        return null;
+    }
+
     private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj,
             ProcessRecord TOP_APP, boolean recursed, boolean doingAll) {
         if (mAdjSeq == app.adjSeq) {
@@ -13728,6 +13924,7 @@
         // important to least, and assign an appropriate OOM adjustment.
         int adj;
         int schedGroup;
+        BroadcastQueue queue;
         if (app == TOP_APP) {
             // The last app on the list is the foreground app.
             adj = ProcessList.FOREGROUND_APP_ADJ;
@@ -13739,12 +13936,14 @@
             adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_DEFAULT;
             app.adjType = "instrumentation";
-        } else if (app.curReceiver != null ||
-                (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
+        } else if ((queue = isReceivingBroadcast(app)) != null) {
             // An app that is currently receiving a broadcast also
-            // counts as being in the foreground.
+            // counts as being in the foreground for OOM killer purposes.
+            // It's placed in a sched group based on the nature of the
+            // broadcast as reflected by which queue it's active in.
             adj = ProcessList.FOREGROUND_APP_ADJ;
-            schedGroup = Process.THREAD_GROUP_DEFAULT;
+            schedGroup = (queue == mFgBroadcastQueue)
+                    ? Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
             app.adjType = "broadcast";
         } else if (app.executingServices.size() > 0) {
             // An app that is currently executing a service callback also
@@ -14185,8 +14384,13 @@
      * Returns true if things are idle enough to perform GCs.
      */
     private final boolean canGcNowLocked() {
-        return mParallelBroadcasts.size() == 0
-                && mOrderedBroadcasts.size() == 0
+        boolean processingBroadcasts = false;
+        for (BroadcastQueue q : mBroadcastQueues) {
+            if (q.mParallelBroadcasts.size() != 0 || q.mOrderedBroadcasts.size() != 0) {
+                processingBroadcasts = true;
+            }
+        }
+        return !processingBroadcasts
                 && (mSleeping || (mMainStack.mResumedActivity != null &&
                         mMainStack.mResumedActivity.idle));
     }
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index bcb0134..6738e4f 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -59,6 +59,7 @@
     IBinder receiver;       // who is currently running, null if none.
     int state;
     int anrCount;           // has this broadcast record hit any ANRs?
+    ActivityManagerService.BroadcastQueue queue;   // the outbound queue handling this broadcast
 
     static final int IDLE = 0;
     static final int APP_RECEIVE = 1;
@@ -161,11 +162,13 @@
         }
     }
 
-    BroadcastRecord(Intent _intent, ProcessRecord _callerApp, String _callerPackage,
+    BroadcastRecord(ActivityManagerService.BroadcastQueue _queue,
+            Intent _intent, ProcessRecord _callerApp, String _callerPackage,
             int _callingPid, int _callingUid, String _requiredPermission,
             List _receivers, IIntentReceiver _resultTo, int _resultCode,
             String _resultData, Bundle _resultExtras, boolean _serialized,
             boolean _sticky, boolean _initialSticky) {
+        queue = _queue;
         intent = _intent;
         callerApp = _callerApp;
         callerPackage = _callerPackage;
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index a71ccb5..5c9396f 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -154,6 +154,7 @@
     private static final int VERSION_ADDED_SNOOZE = 2;
     private static final int VERSION_ADDED_RESTRICT_BACKGROUND = 3;
     private static final int VERSION_ADDED_METERED = 4;
+    private static final int VERSION_SPLIT_SNOOZE = 5;
 
     private static final long KB_IN_BYTES = 1024;
     private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
@@ -176,6 +177,8 @@
     private static final String ATTR_WARNING_BYTES = "warningBytes";
     private static final String ATTR_LIMIT_BYTES = "limitBytes";
     private static final String ATTR_LAST_SNOOZE = "lastSnooze";
+    private static final String ATTR_LAST_WARNING_SNOOZE = "lastWarningSnooze";
+    private static final String ATTR_LAST_LIMIT_SNOOZE = "lastLimitSnooze";
     private static final String ATTR_METERED = "metered";
     private static final String ATTR_UID = "uid";
     private static final String ATTR_POLICY = "policy";
@@ -184,7 +187,9 @@
 
     // @VisibleForTesting
     public static final String ACTION_ALLOW_BACKGROUND =
-            "com.android.server.action.ACTION_ALLOW_BACKGROUND";
+            "com.android.server.net.action.ALLOW_BACKGROUND";
+    public static final String ACTION_SNOOZE_WARNING =
+            "com.android.server.net.action.SNOOZE_WARNING";
 
     private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
 
@@ -333,6 +338,11 @@
         final IntentFilter allowFilter = new IntentFilter(ACTION_ALLOW_BACKGROUND);
         mContext.registerReceiver(mAllowReceiver, allowFilter, MANAGE_NETWORK_POLICY, mHandler);
 
+        // listen for snooze warning from notifications
+        final IntentFilter snoozeWarningFilter = new IntentFilter(ACTION_SNOOZE_WARNING);
+        mContext.registerReceiver(mSnoozeWarningReceiver, snoozeWarningFilter,
+                MANAGE_NETWORK_POLICY, mHandler);
+
     }
 
     private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
@@ -418,6 +428,21 @@
     };
 
     /**
+     * Receiver that watches for {@link Notification} control of
+     * {@link NetworkPolicy#lastWarningSnooze}.
+     */
+    private BroadcastReceiver mSnoozeWarningReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // on background handler thread, and verified MANAGE_NETWORK_POLICY
+            // permission above.
+
+            final NetworkTemplate template = intent.getParcelableExtra(EXTRA_NETWORK_TEMPLATE);
+            performSnooze(template, TYPE_WARNING);
+        }
+    };
+
+    /**
      * Observer that watches for {@link INetworkManagementService} alerts.
      */
     private INetworkManagementEventObserver mAlertObserver = new NetworkAlertObserver() {
@@ -458,7 +483,7 @@
             final long totalBytes = getTotalBytes(policy.template, start, end);
 
             if (policy.isOverLimit(totalBytes)) {
-                if (policy.lastSnooze >= start) {
+                if (policy.lastLimitSnooze >= start) {
                     enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes);
                 } else {
                     enqueueNotification(policy, TYPE_LIMIT, totalBytes);
@@ -468,7 +493,7 @@
             } else {
                 notifyUnderLimitLocked(policy.template);
 
-                if (policy.warningBytes != WARNING_DISABLED && totalBytes >= policy.warningBytes) {
+                if (policy.isOverWarning(totalBytes) && policy.lastWarningSnooze < start) {
                     enqueueNotification(policy, TYPE_WARNING, totalBytes);
                 }
             }
@@ -534,7 +559,7 @@
         final String tag = buildNotificationTag(policy, type);
         final Notification.Builder builder = new Notification.Builder(mContext);
         builder.setOnlyAlertOnce(true);
-        builder.setOngoing(true);
+        builder.setWhen(0L);
 
         final Resources res = mContext.getResources();
         switch (type) {
@@ -547,9 +572,14 @@
                 builder.setContentTitle(title);
                 builder.setContentText(body);
 
-                final Intent intent = buildViewDataUsageIntent(policy.template);
+                final Intent snoozeIntent = buildSnoozeWarningIntent(policy.template);
+                builder.setDeleteIntent(PendingIntent.getBroadcast(
+                        mContext, 0, snoozeIntent, PendingIntent.FLAG_UPDATE_CURRENT));
+
+                final Intent viewIntent = buildViewDataUsageIntent(policy.template);
                 builder.setContentIntent(PendingIntent.getActivity(
-                        mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
+                        mContext, 0, viewIntent, PendingIntent.FLAG_UPDATE_CURRENT));
+
                 break;
             }
             case TYPE_LIMIT: {
@@ -574,6 +604,7 @@
                         break;
                 }
 
+                builder.setOngoing(true);
                 builder.setSmallIcon(R.drawable.stat_notify_disabled);
                 builder.setTicker(title);
                 builder.setContentTitle(title);
@@ -608,6 +639,7 @@
                         break;
                 }
 
+                builder.setOngoing(true);
                 builder.setSmallIcon(R.drawable.stat_notify_error);
                 builder.setTicker(title);
                 builder.setContentTitle(title);
@@ -720,10 +752,11 @@
             final long totalBytes = getTotalBytes(policy.template, start, end);
 
             // disable data connection when over limit and not snoozed
-            final boolean overLimit = policy.isOverLimit(totalBytes) && policy.lastSnooze < start;
-            final boolean enabled = !overLimit;
+            final boolean overLimitWithoutSnooze = policy.isOverLimit(totalBytes)
+                    && policy.lastLimitSnooze < start;
+            final boolean networkEnabled = !overLimitWithoutSnooze;
 
-            setNetworkTemplateEnabled(policy.template, enabled);
+            setNetworkTemplateEnabled(policy.template, networkEnabled);
         }
     }
 
@@ -827,7 +860,7 @@
                     // metered network, but no policy limit; we still need to
                     // restrict apps, so push really high quota.
                     quotaBytes = Long.MAX_VALUE;
-                } else if (policy.lastSnooze >= start) {
+                } else if (policy.lastLimitSnooze >= start) {
                     // snoozing past quota, but we still need to restrict apps,
                     // so push really high quota.
                     quotaBytes = Long.MAX_VALUE;
@@ -896,8 +929,8 @@
             final int cycleDay = time.monthDay;
 
             final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
-            mNetworkPolicy.put(template, new NetworkPolicy(
-                    template, cycleDay, warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, true));
+            mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay, warningBytes,
+                    LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true));
             writePolicyLocked();
         }
     }
@@ -935,11 +968,13 @@
                         final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY);
                         final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES);
                         final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES);
-                        final long lastSnooze;
-                        if (version >= VERSION_ADDED_SNOOZE) {
-                            lastSnooze = readLongAttribute(in, ATTR_LAST_SNOOZE);
+                        final long lastLimitSnooze;
+                        if (version >= VERSION_SPLIT_SNOOZE) {
+                            lastLimitSnooze = readLongAttribute(in, ATTR_LAST_LIMIT_SNOOZE);
+                        } else if (version >= VERSION_ADDED_SNOOZE) {
+                            lastLimitSnooze = readLongAttribute(in, ATTR_LAST_SNOOZE);
                         } else {
-                            lastSnooze = SNOOZE_NEVER;
+                            lastLimitSnooze = SNOOZE_NEVER;
                         }
                         final boolean metered;
                         if (version >= VERSION_ADDED_METERED) {
@@ -955,11 +990,18 @@
                                     metered = false;
                             }
                         }
+                        final long lastWarningSnooze;
+                        if (version >= VERSION_SPLIT_SNOOZE) {
+                            lastWarningSnooze = readLongAttribute(in, ATTR_LAST_WARNING_SNOOZE);
+                        } else {
+                            lastWarningSnooze = SNOOZE_NEVER;
+                        }
 
                         final NetworkTemplate template = new NetworkTemplate(
                                 networkTemplate, subscriberId);
-                        mNetworkPolicy.put(template, new NetworkPolicy(
-                                template, cycleDay, warningBytes, limitBytes, lastSnooze, metered));
+                        mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay,
+                                warningBytes, limitBytes, lastWarningSnooze, lastLimitSnooze,
+                                metered));
 
                     } else if (TAG_UID_POLICY.equals(tag)) {
                         final int uid = readIntAttribute(in, ATTR_UID);
@@ -1014,7 +1056,7 @@
             out.startDocument(null, true);
 
             out.startTag(null, TAG_POLICY_LIST);
-            writeIntAttribute(out, ATTR_VERSION, VERSION_ADDED_METERED);
+            writeIntAttribute(out, ATTR_VERSION, VERSION_SPLIT_SNOOZE);
             writeBooleanAttribute(out, ATTR_RESTRICT_BACKGROUND, mRestrictBackground);
 
             // write all known network policies
@@ -1030,7 +1072,8 @@
                 writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay);
                 writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes);
                 writeLongAttribute(out, ATTR_LIMIT_BYTES, policy.limitBytes);
-                writeLongAttribute(out, ATTR_LAST_SNOOZE, policy.lastSnooze);
+                writeLongAttribute(out, ATTR_LAST_WARNING_SNOOZE, policy.lastWarningSnooze);
+                writeLongAttribute(out, ATTR_LAST_LIMIT_SNOOZE, policy.lastLimitSnooze);
                 writeBooleanAttribute(out, ATTR_METERED, policy.metered);
                 out.endTag(null, TAG_NETWORK_POLICY);
             }
@@ -1141,9 +1184,12 @@
     }
 
     @Override
-    public void snoozePolicy(NetworkTemplate template) {
+    public void snoozeLimit(NetworkTemplate template) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+        performSnooze(template, TYPE_LIMIT);
+    }
 
+    private void performSnooze(NetworkTemplate template, int type) {
         maybeRefreshTrustedTime();
         final long currentTime = currentTimeMillis();
         synchronized (mRulesLock) {
@@ -1153,7 +1199,16 @@
                 throw new IllegalArgumentException("unable to find policy for " + template);
             }
 
-            policy.lastSnooze = currentTime;
+            switch (type) {
+                case TYPE_WARNING:
+                    policy.lastWarningSnooze = currentTime;
+                    break;
+                case TYPE_LIMIT:
+                    policy.lastLimitSnooze = currentTime;
+                    break;
+                default:
+                    throw new IllegalArgumentException("unexpected type");
+            }
 
             updateNetworkEnabledLocked();
             updateNetworkRulesLocked();
@@ -1246,12 +1301,17 @@
         }
 
         synchronized (mRulesLock) {
-            if (argSet.contains("unsnooze")) {
+            if (argSet.contains("--unsnooze")) {
                 for (NetworkPolicy policy : mNetworkPolicy.values()) {
-                    policy.lastSnooze = SNOOZE_NEVER;
+                    policy.clearSnooze();
                 }
+
+                updateNetworkEnabledLocked();
+                updateNetworkRulesLocked();
+                updateNotificationsLocked();
                 writePolicyLocked();
-                fout.println("Wiped snooze timestamps");
+
+                fout.println("Cleared snooze timestamps");
                 return;
             }
 
@@ -1599,6 +1659,12 @@
         return new Intent(ACTION_ALLOW_BACKGROUND);
     }
 
+    private static Intent buildSnoozeWarningIntent(NetworkTemplate template) {
+        final Intent intent = new Intent(ACTION_SNOOZE_WARNING);
+        intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
+        return intent;
+    }
+
     private static Intent buildNetworkOverLimitIntent(NetworkTemplate template) {
         final Intent intent = new Intent();
         intent.setComponent(new ComponentName(
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index c9b79e8..414ed1e 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -121,6 +121,7 @@
 
     private static final int MSG_PERFORM_POLL = 1;
     private static final int MSG_UPDATE_IFACES = 2;
+    private static final int MSG_REGISTER_GLOBAL_ALERT = 3;
 
     /** Flags to control detail level of poll event. */
     private static final int FLAG_PERSIST_NETWORK = 0x1;
@@ -510,7 +511,13 @@
     @Override
     public void forceUpdate() {
         mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
-        performPoll(FLAG_PERSIST_ALL);
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            performPoll(FLAG_PERSIST_ALL);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     /**
@@ -594,7 +601,7 @@
                 mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget();
 
                 // re-arm global alert for next update
-                registerGlobalAlert();
+                mHandler.obtainMessage(MSG_REGISTER_GLOBAL_ALERT).sendToTarget();
             }
         }
     };
@@ -945,6 +952,10 @@
                     updateIfaces();
                     return true;
                 }
+                case MSG_REGISTER_GLOBAL_ALERT: {
+                    registerGlobalAlert();
+                    return true;
+                }
                 default: {
                     return false;
                 }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 19d94a1..620d74c 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -95,6 +95,7 @@
 import android.util.Slog;
 import android.util.SparseIntArray;
 import android.util.TypedValue;
+import android.view.Choreographer;
 import android.view.Display;
 import android.view.Gravity;
 import android.view.IApplicationToken;
@@ -141,7 +142,8 @@
 
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
-        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
+        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs,
+        Choreographer.OnAnimateListener {
     static final String TAG = "WindowManager";
     static final boolean DEBUG = false;
     static final boolean DEBUG_ADD_REMOVE = false;
@@ -456,7 +458,7 @@
     int mDeferredRotationPauseCount;
 
     boolean mLayoutNeeded = true;
-    boolean mAnimationPending = false;
+    boolean mTraversalScheduled = false;
     boolean mDisplayFrozen = false;
     boolean mWaitingForConfig = false;
     boolean mWindowsFreezingScreen = false;
@@ -503,7 +505,9 @@
     final DisplayMetrics mTmpDisplayMetrics = new DisplayMetrics();
     final DisplayMetrics mCompatDisplayMetrics = new DisplayMetrics();
 
-    H mH = new H();
+    final H mH = new H();
+
+    final Choreographer mChoreographer = Choreographer.getInstance();
 
     WindowState mCurrentFocus = null;
     WindowState mLastFocus = null;
@@ -559,6 +563,7 @@
 
     float mWindowAnimationScale = 1.0f;
     float mTransitionAnimationScale = 1.0f;
+    float mAnimatorDurationScale = 1.0f;
 
     final InputManager mInputManager;
 
@@ -691,6 +696,7 @@
             Looper.prepare();
             WindowManagerService s = new WindowManagerService(mContext, mPM,
                     mHaveInputMethods, mAllowBootMessages);
+            s.mChoreographer.addOnAnimateListener(s);
             android.os.Process.setThreadPriority(
                     android.os.Process.THREAD_PRIORITY_DISPLAY);
             android.os.Process.setCanSelfBackground(false);
@@ -774,6 +780,8 @@
                 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
         mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(),
                 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
+        mAnimatorDurationScale = Settings.System.getFloat(context.getContentResolver(),
+                Settings.System.ANIMATOR_DURATION_SCALE, mTransitionAnimationScale);
 
         // Track changes to DevicePolicyManager state so we can enable/disable keyguard.
         IntentFilter filter = new IntentFilter();
@@ -4657,6 +4665,7 @@
         switch (which) {
             case 0: mWindowAnimationScale = fixScale(scale); break;
             case 1: mTransitionAnimationScale = fixScale(scale); break;
+            case 2: mAnimatorDurationScale = fixScale(scale); break;
         }
 
         // Persist setting
@@ -4676,6 +4685,9 @@
             if (scales.length >= 2) {
                 mTransitionAnimationScale = fixScale(scales[1]);
             }
+            if (scales.length >= 3) {
+                mAnimatorDurationScale = fixScale(scales[2]);
+            }
         }
 
         // Persist setting
@@ -4686,12 +4698,14 @@
         switch (which) {
             case 0: return mWindowAnimationScale;
             case 1: return mTransitionAnimationScale;
+            case 2: return mAnimatorDurationScale;
         }
         return 0;
     }
 
     public float[] getAnimationScales() {
-        return new float[] { mWindowAnimationScale, mTransitionAnimationScale };
+        return new float[] { mWindowAnimationScale, mTransitionAnimationScale,
+                mAnimatorDurationScale };
     }
 
     public int getSwitchState(int sw) {
@@ -5390,7 +5404,7 @@
                 if (mScreenRotationAnimation.setRotation(rotation, mFxSession,
                         MAX_ANIMATION_DURATION, mTransitionAnimationScale,
                         mCurDisplayWidth, mCurDisplayHeight)) {
-                    requestAnimationLocked(0);
+                    mChoreographer.scheduleAnimation();
                 }
             }
             Surface.setOrientation(0, rotation);
@@ -6513,7 +6527,7 @@
     final class H extends Handler {
         public static final int REPORT_FOCUS_CHANGE = 2;
         public static final int REPORT_LOSING_FOCUS = 3;
-        public static final int ANIMATE = 4;
+        public static final int DO_TRAVERSAL = 4;
         public static final int ADD_STARTING = 5;
         public static final int REMOVE_STARTING = 6;
         public static final int FINISHED_STARTING = 7;
@@ -6607,9 +6621,9 @@
                     }
                 } break;
 
-                case ANIMATE: {
+                case DO_TRAVERSAL: {
                     synchronized(mWindowMap) {
-                        mAnimationPending = false;
+                        mTraversalScheduled = false;
                         performLayoutAndPlaceSurfacesLocked();
                     }
                 } break;
@@ -6825,12 +6839,14 @@
                             Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
                     Settings.System.putFloat(mContext.getContentResolver(),
                             Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
+                    Settings.System.putFloat(mContext.getContentResolver(),
+                            Settings.System.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale);
                     break;
                 }
 
                 case FORCE_GC: {
                     synchronized(mWindowMap) {
-                        if (mAnimationPending) {
+                        if (mChoreographer.isAnimationScheduled()) {
                             // If we are animating, don't do the gc now but
                             // delay a bit so we don't interrupt the animation.
                             mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
@@ -7389,7 +7405,7 @@
             } else {
                 mInLayout = false;
                 if (mLayoutNeeded) {
-                    requestAnimationLocked(0);
+                    requestTraversalLocked();
                 }
             }
             if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
@@ -8822,10 +8838,9 @@
             needRelayout = adjustWallpaperWindowsLocked() != 0;
         }
         if (needRelayout) {
-            requestAnimationLocked(0);
+            requestTraversalLocked();
         } else if (animating) {
-            final int refreshTimeUs = (int)(1000 / mDisplay.getRefreshRate());
-            requestAnimationLocked(currentTime + refreshTimeUs - SystemClock.uptimeMillis());
+            mChoreographer.scheduleAnimation();
         }
 
         // Finally update all input windows now that the window changes have stabilized.
@@ -8944,10 +8959,17 @@
         }
     }
 
-    void requestAnimationLocked(long delay) {
-        if (!mAnimationPending) {
-            mAnimationPending = true;
-            mH.sendMessageDelayed(mH.obtainMessage(H.ANIMATE), delay);
+    void requestTraversalLocked() {
+        if (!mTraversalScheduled) {
+            mTraversalScheduled = true;
+            mH.sendEmptyMessage(H.DO_TRAVERSAL);
+        }
+    }
+
+    @Override
+    public void onAnimate() {
+        synchronized(mWindowMap) {
+            performLayoutAndPlaceSurfacesLocked();
         }
     }
 
@@ -9267,7 +9289,7 @@
             if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
             if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
                     mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) {
-                requestAnimationLocked(0);
+                mChoreographer.scheduleAnimation();
             } else {
                 mScreenRotationAnimation = null;
                 updateRotation = true;
@@ -9759,9 +9781,10 @@
             pw.print("  mLastWindowForcedOrientation"); pw.print(mLastWindowForcedOrientation);
                     pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
             pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
-            pw.print("  mAnimationPending="); pw.print(mAnimationPending);
+            pw.print("  mTraversalScheduled="); pw.print(mTraversalScheduled);
                     pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale);
                     pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale);
+                    pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
             pw.print("  mNextAppTransition=0x");
                     pw.print(Integer.toHexString(mNextAppTransition));
                     pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 1067cad..6868cf6 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -1593,7 +1593,7 @@
             mService.applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true);
         }
         if (requestAnim) {
-            mService.requestAnimationLocked(0);
+            mService.mChoreographer.scheduleAnimation();
         }
         return true;
     }
@@ -1634,7 +1634,7 @@
             }
         }
         if (requestAnim) {
-            mService.requestAnimationLocked(0);
+            mService.mChoreographer.scheduleAnimation();
         }
         return true;
     }
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 95d651a..8b4c074 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -23,6 +23,10 @@
 LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 
+ifeq ($(TARGET_HAS_WAITFORVSYNC), true)
+	LOCAL_CFLAGS += -DHAS_WAITFORVSYNC
+endif
+
 ifeq ($(TARGET_BOARD_PLATFORM), omap3)
 	LOCAL_CFLAGS += -DNO_RGBX_8888
 endif
@@ -31,10 +35,8 @@
 endif
 ifeq ($(TARGET_BOARD_PLATFORM), s5pc110)
 	LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY -DNEVER_DEFAULT_TO_ASYNC_MODE
-	LOCAL_CFLAGS += -DREFRESH_RATE=56
 endif
 
-
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
 	libhardware \
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
index f4afeea..09f1906 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2012 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.
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <assert.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -22,15 +21,6 @@
 
 #include <unistd.h>
 #include <fcntl.h>
-#include <signal.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/resource.h>
-
-#include <linux/unistd.h>
 
 #include <utils/Log.h>
 
@@ -45,39 +35,30 @@
 
 // ----------------------------------------------------------------------------
 
-DisplayHardwareBase::DisplayEventThreadBase::DisplayEventThreadBase(
+DisplayHardwareBase::DisplayEventThread::DisplayEventThread(
         const sp<SurfaceFlinger>& flinger)
     : Thread(false), mFlinger(flinger) {
 }
 
-DisplayHardwareBase::DisplayEventThreadBase::~DisplayEventThreadBase() {
+DisplayHardwareBase::DisplayEventThread::~DisplayEventThread() {
 }
 
-// ----------------------------------------------------------------------------
-
-DisplayHardwareBase::DisplayEventThread::DisplayEventThread(
-        const sp<SurfaceFlinger>& flinger)
-    : DisplayEventThreadBase(flinger)
-{
+void DisplayHardwareBase::DisplayEventThread::onFirstRef() {
+    if (initCheck() == NO_ERROR) {
+        run("DisplayEventThread", PRIORITY_URGENT_DISPLAY);
+    } else {
+        ALOGW("/sys/power/wait_for_fb_{wake|sleep} don't exist");
+    }
 }
 
-DisplayHardwareBase::DisplayEventThread::~DisplayEventThread()
-{
+status_t DisplayHardwareBase::DisplayEventThread::initCheck() const {
+    return ((access(kSleepFileName, R_OK) == 0 &&
+            access(kWakeFileName, R_OK) == 0)) ? NO_ERROR : NO_INIT;
 }
 
-bool DisplayHardwareBase::DisplayEventThread::threadLoop()
-{
-    int err = 0;
-    char buf;
-    int fd;
+bool DisplayHardwareBase::DisplayEventThread::threadLoop() {
 
-    fd = open(kSleepFileName, O_RDONLY, 0);
-    do {
-      err = read(fd, &buf, 1);
-    } while (err < 0 && errno == EINTR);
-    close(fd);
-    ALOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
-    if (err >= 0) {
+    if (waitForFbSleep() == NO_ERROR) {
         sp<SurfaceFlinger> flinger = mFlinger.promote();
         ALOGD("About to give-up screen, flinger = %p", flinger.get());
         if (flinger != 0) {
@@ -85,39 +66,51 @@
             flinger->screenReleased(0);
             mBarrier.wait();
         }
+        if (waitForFbWake() == NO_ERROR) {
+            sp<SurfaceFlinger> flinger = mFlinger.promote();
+            ALOGD("Screen about to return, flinger = %p", flinger.get());
+            if (flinger != 0) {
+                flinger->screenAcquired(0);
+            }
+            return true;
+        }
     }
-    fd = open(kWakeFileName, O_RDONLY, 0);
+
+    // error, exit the thread
+    return false;
+}
+
+status_t DisplayHardwareBase::DisplayEventThread::waitForFbSleep() {
+    int err = 0;
+    char buf;
+    int fd = open(kSleepFileName, O_RDONLY, 0);
+    // if the file doesn't exist, the error will be caught in read() below
     do {
-      err = read(fd, &buf, 1);
+        err = read(fd, &buf, 1);
     } while (err < 0 && errno == EINTR);
     close(fd);
-    ALOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
-    if (err >= 0) {
-        sp<SurfaceFlinger> flinger = mFlinger.promote();
-        ALOGD("Screen about to return, flinger = %p", flinger.get());
-        if (flinger != 0)
-            flinger->screenAcquired(0);
-    }
-    return true;
+    ALOGE_IF(err<0, "*** ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
+    return err < 0 ? -errno : int(NO_ERROR);
 }
 
-status_t DisplayHardwareBase::DisplayEventThread::releaseScreen() const
-{
+status_t DisplayHardwareBase::DisplayEventThread::waitForFbWake() {
+    int err = 0;
+    char buf;
+    int fd = open(kWakeFileName, O_RDONLY, 0);
+    // if the file doesn't exist, the error will be caught in read() below
+    do {
+        err = read(fd, &buf, 1);
+    } while (err < 0 && errno == EINTR);
+    close(fd);
+    ALOGE_IF(err<0, "*** ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
+    return err < 0 ? -errno : int(NO_ERROR);
+}
+
+status_t DisplayHardwareBase::DisplayEventThread::releaseScreen() const {
     mBarrier.open();
     return NO_ERROR;
 }
 
-status_t DisplayHardwareBase::DisplayEventThread::readyToRun()
-{
-    return NO_ERROR;
-}
-
-status_t DisplayHardwareBase::DisplayEventThread::initCheck() const
-{
-    return ((access(kSleepFileName, R_OK) == 0 &&
-            access(kWakeFileName, R_OK) == 0)) ? NO_ERROR : NO_INIT;
-}
-
 // ----------------------------------------------------------------------------
 
 DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger,
@@ -127,35 +120,27 @@
     mDisplayEventThread = new DisplayEventThread(flinger);
 }
 
-DisplayHardwareBase::~DisplayHardwareBase()
-{
+DisplayHardwareBase::~DisplayHardwareBase() {
     // request exit
     mDisplayEventThread->requestExitAndWait();
 }
 
-bool DisplayHardwareBase::canDraw() const
-{
+bool DisplayHardwareBase::canDraw() const {
     return mScreenAcquired;
 }
 
-void DisplayHardwareBase::releaseScreen() const
-{
+void DisplayHardwareBase::releaseScreen() const {
     status_t err = mDisplayEventThread->releaseScreen();
     if (err >= 0) {
         mScreenAcquired = false;
     }
 }
 
-void DisplayHardwareBase::acquireScreen() const
-{
-    status_t err = mDisplayEventThread->acquireScreen();
-    if (err >= 0) {
-        mScreenAcquired = true;
-    }
+void DisplayHardwareBase::acquireScreen() const {
+    mScreenAcquired = true;
 }
 
-bool DisplayHardwareBase::isScreenAcquired() const
-{
+bool DisplayHardwareBase::isScreenAcquired() const {
     return mScreenAcquired;
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
index ef2df43..91ea602 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2012 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.
@@ -20,8 +20,6 @@
 #include <stdint.h>
 #include <utils/RefBase.h>
 #include <utils/threads.h>
-#include <linux/kd.h>
-#include <linux/vt.h>
 #include "Barrier.h"
 
 namespace android {
@@ -31,11 +29,11 @@
 class DisplayHardwareBase
 {
 public:
-                DisplayHardwareBase(
-                        const sp<SurfaceFlinger>& flinger,
-                        uint32_t displayIndex);
+    DisplayHardwareBase(
+            const sp<SurfaceFlinger>& flinger,
+            uint32_t displayIndex);
 
-                ~DisplayHardwareBase();
+    ~DisplayHardwareBase();
 
     // console management
     void releaseScreen() const;
@@ -46,34 +44,22 @@
 
 
 private:
-    class DisplayEventThreadBase : public Thread {
-    protected:
+    class DisplayEventThread : public Thread {
         wp<SurfaceFlinger> mFlinger;
-    public:
-        DisplayEventThreadBase(const sp<SurfaceFlinger>& flinger);
-        virtual ~DisplayEventThreadBase();
-        virtual void onFirstRef() {
-            run("DisplayEventThread", PRIORITY_URGENT_DISPLAY);
-        }
-        virtual status_t acquireScreen() const { return NO_ERROR; };
-        virtual status_t releaseScreen() const { return NO_ERROR; };
-        virtual status_t initCheck() const = 0;
-    };
-
-    class DisplayEventThread : public DisplayEventThreadBase 
-    {
         mutable Barrier mBarrier;
+        status_t waitForFbSleep();
+        status_t waitForFbWake();
     public:
-                DisplayEventThread(const sp<SurfaceFlinger>& flinger);
+        DisplayEventThread(const sp<SurfaceFlinger>& flinger);
         virtual ~DisplayEventThread();
+        virtual void onFirstRef();
         virtual bool threadLoop();
-        virtual status_t readyToRun();
-        virtual status_t releaseScreen() const;
-        virtual status_t initCheck() const;
+        status_t releaseScreen() const;
+        status_t initCheck() const;
     };
 
-    sp<DisplayEventThreadBase>  mDisplayEventThread;
-    mutable int                 mScreenAcquired;
+    sp<DisplayEventThread>  mDisplayEventThread;
+    mutable int             mScreenAcquired;
 };
 
 }; // namespace android
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 6796d7d..af0da0b 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -36,6 +36,7 @@
 EventThread::EventThread(const sp<SurfaceFlinger>& flinger)
     : mFlinger(flinger),
       mHw(flinger->graphicPlane(0).displayHardware()),
+      mLastVSyncTimestamp(0),
       mDeliveredEvents(0)
 {
 }
@@ -44,6 +45,20 @@
     run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
 }
 
+sp<DisplayEventConnection> EventThread::createEventConnection() const {
+    return new DisplayEventConnection(const_cast<EventThread*>(this));
+}
+
+nsecs_t EventThread::getLastVSyncTimestamp() const {
+    Mutex::Autolock _l(mLock);
+    return mLastVSyncTimestamp;
+}
+
+nsecs_t EventThread::getVSyncPeriod() const {
+    return mHw.getRefreshPeriod();
+
+}
+
 status_t EventThread::registerDisplayEventConnection(
         const sp<DisplayEventConnection>& connection) {
     Mutex::Autolock _l(mLock);
@@ -80,8 +95,11 @@
         Mutex::Autolock _l(mLock);
         ConnectionInfo* info = getConnectionInfoLocked(connection);
         if (info) {
-            info->count = (count == 0) ? -1 : count;
-            mCondition.signal();
+            const int32_t new_count = (count == 0) ? -1 : count;
+            if (info->count != new_count) {
+                info->count = new_count;
+                mCondition.signal();
+            }
         }
     }
 }
@@ -90,10 +108,8 @@
         const wp<DisplayEventConnection>& connection) {
     Mutex::Autolock _l(mLock);
     ConnectionInfo* info = getConnectionInfoLocked(connection);
-    if (info) {
-        if (info->count < 0) {
-            info->count = 0;
-        }
+    if (info && info->count < 0) {
+        info->count = 0;
         mCondition.signal();
     }
 }
@@ -132,11 +148,12 @@
             timestamp = mHw.waitForRefresh();
             mLock.lock();
             mDeliveredEvents++;
+            mLastVSyncTimestamp = timestamp;
 
             // now see if we still need to report this VSYNC event
-            bool reportVsync = false;
-            size_t count = mDisplayEventConnections.size();
+            const size_t count = mDisplayEventConnections.size();
             for (size_t i=0 ; i<count ; i++) {
+                bool reportVsync = false;
                 const ConnectionInfo& info(
                         mDisplayEventConnections.valueAt(i));
                 if (info.count >= 1) {
@@ -157,11 +174,7 @@
                     displayEventConnections.add(mDisplayEventConnections.keyAt(i));
                 }
             }
-
-            if (reportVsync) {
-                break;
-            }
-        } while (true);
+        } while (!displayEventConnections.size());
 
         // dispatch vsync events to listeners...
         vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 35bd299..3a3071e 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -36,6 +36,7 @@
 
 class SurfaceFlinger;
 class DisplayHardware;
+class DisplayEventConnection;
 
 // ---------------------------------------------------------------------------
 
@@ -45,6 +46,8 @@
 public:
     EventThread(const sp<SurfaceFlinger>& flinger);
 
+    sp<DisplayEventConnection> createEventConnection() const;
+
     status_t registerDisplayEventConnection(
             const sp<DisplayEventConnection>& connection);
 
@@ -56,6 +59,10 @@
 
     void requestNextVsync(const wp<DisplayEventConnection>& connection);
 
+    nsecs_t getLastVSyncTimestamp() const;
+
+    nsecs_t getVSyncPeriod() const;
+
     void dump(String8& result, char* buffer, size_t SIZE) const;
 
 private:
@@ -88,6 +95,7 @@
 
     // protected by mLock
     KeyedVector< wp<DisplayEventConnection>, ConnectionInfo > mDisplayEventConnections;
+    nsecs_t mLastVSyncTimestamp;
 
     // main thread only
     size_t mDeliveredEvents;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 8e87b88..64f72d5 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -55,6 +55,7 @@
         mCurrentTransform(0),
         mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
         mCurrentOpacity(true),
+        mRefreshPending(0),
         mFrameLatencyNeeded(false),
         mFrameLatencyOffset(0),
         mFormat(PIXEL_FORMAT_NONE),
@@ -108,7 +109,7 @@
 
 void Layer::onFrameQueued() {
     android_atomic_inc(&mQueuedFrames);
-    mFlinger->signalEvent();
+    mFlinger->signalLayerUpdate();
 }
 
 // called with SurfaceFlinger::mStateLock as soon as the layer is entered
@@ -402,16 +403,37 @@
 // pageflip handling...
 // ----------------------------------------------------------------------------
 
+bool Layer::onPreComposition()
+{
+    // if there was more than one pending update, request a refresh
+    if (mRefreshPending >= 2) {
+        mRefreshPending = 0;
+        return true;
+    }
+    mRefreshPending = 0;
+    return false;
+}
+
 void Layer::lockPageFlip(bool& recomputeVisibleRegions)
 {
     if (mQueuedFrames > 0) {
+
+        // if we've already called updateTexImage() without going through
+        // a composition step, we have to skip this layer at this point
+        // because we cannot call updateTeximage() without a corresponding
+        // compositionComplete() call.
+        // we'll trigger an update in onPreComposition().
+        if (mRefreshPending++) {
+            return;
+        }
+
         // Capture the old state of the layer for comparisons later
         const bool oldOpacity = isOpaque();
         sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
 
         // signal another event if we have more frames pending
         if (android_atomic_dec(&mQueuedFrames) > 1) {
-            mFlinger->signalEvent();
+            mFlinger->signalLayerUpdate();
         }
 
         if (mSurfaceTexture->updateTexImage() < NO_ERROR) {
@@ -514,6 +536,10 @@
 void Layer::unlockPageFlip(
         const Transform& planeTransform, Region& outDirtyRegion)
 {
+    if (mRefreshPending >= 2) {
+        return;
+    }
+
     Region dirtyRegion(mPostedDirtyRegion);
     if (!dirtyRegion.isEmpty()) {
         mPostedDirtyRegion.clear();
@@ -547,9 +573,9 @@
     snprintf(buffer, SIZE,
             "      "
             "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
-            " transform-hint=0x%02x, queued-frames=%d\n",
+            " transform-hint=0x%02x, queued-frames=%d, mRefreshPending=%d\n",
             mFormat, w0, h0, s0,f0,
-            getTransformHint(), mQueuedFrames);
+            getTransformHint(), mQueuedFrames, mRefreshPending);
 
     result.append(buffer);
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2dd4da1..bf30608 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -80,6 +80,7 @@
     virtual wp<IBinder> getSurfaceTextureBinder() const;
 
     virtual void onLayerDisplayed();
+    virtual bool onPreComposition();
 
     // only for debugging
     inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
@@ -115,14 +116,17 @@
     uint32_t mCurrentTransform;
     uint32_t mCurrentScalingMode;
     bool mCurrentOpacity;
+    size_t mRefreshPending;
     bool mFrameLatencyNeeded;
     int mFrameLatencyOffset;
+
     struct Statistics {
         Statistics() : timestamp(0), set(0), vsync(0) { }
         nsecs_t timestamp;  // buffer timestamp
         nsecs_t set;        // buffer displayed timestamp
         nsecs_t vsync;      // vsync immediately before set
     };
+
     // protected by mLock
     Statistics mFrameStats[128];
 
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index d32fcdd..44aafdf 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -47,8 +47,7 @@
       mOrientation(0),
       mPlaneOrientation(0),
       mTransactionFlags(0),
-      mPremultipliedAlpha(true), mName("unnamed"), mDebug(false),
-      mInvalidate(0)
+      mPremultipliedAlpha(true), mName("unnamed"), mDebug(false)
 {
     const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
     mFlags = hw.getFlags();
@@ -262,23 +261,11 @@
     mTransformedBounds = tr.makeBounds(w, h);
 }
 
-void LayerBase::lockPageFlip(bool& recomputeVisibleRegions)
-{
+void LayerBase::lockPageFlip(bool& recomputeVisibleRegions) {
 }
 
 void LayerBase::unlockPageFlip(
-        const Transform& planeTransform, Region& outDirtyRegion)
-{
-    if ((android_atomic_and(~1, &mInvalidate)&1) == 1) {
-        outDirtyRegion.orSelf(visibleRegionScreen);
-    }
-}
-
-void LayerBase::invalidate()
-{
-    if ((android_atomic_or(1, &mInvalidate)&1) == 0) {
-        mFlinger->signalEvent();
-    }
+        const Transform& planeTransform, Region& outDirtyRegion) {
 }
 
 void LayerBase::drawRegion(const Region& reg) const
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 6b62c9d..b8f7680 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -103,8 +103,6 @@
             Rect visibleBounds() const;
             void drawRegion(const Region& reg) const;
 
-            void invalidate();
-
     virtual sp<LayerBaseClient> getLayerBaseClient() const { return 0; }
     virtual sp<Layer> getLayer() const { return 0; }
 
@@ -204,9 +202,16 @@
 
     /** called with the state lock when the surface is removed from the
      *  current list */
-    virtual void onRemoved() { };
+    virtual void onRemoved() { }
 
-    virtual void onLayerDisplayed() { };
+    /** called after page-flip
+     */
+    virtual void onLayerDisplayed() { }
+
+    /** called before composition.
+     * returns true if the layer has pending updates.
+     */
+    virtual bool onPreComposition() { return false; }
 
     /** always call base class first */
     virtual void dump(String8& result, char* scratch, size_t size) const;
@@ -275,10 +280,6 @@
     mutable     bool            mDebug;
 
 
-                // atomic
-    volatile    int32_t         mInvalidate;
-                
-
 public:
     // called from class SurfaceFlinger
     virtual ~LayerBase();
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index cbd530c..1ff3567 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -18,12 +18,18 @@
 #include <errno.h>
 #include <sys/types.h>
 
+#include <binder/IPCThreadState.h>
+
 #include <utils/threads.h>
 #include <utils/Timers.h>
 #include <utils/Log.h>
-#include <binder/IPCThreadState.h>
+
+#include <gui/IDisplayEventConnection.h>
+#include <gui/BitTube.h>
 
 #include "MessageQueue.h"
+#include "EventThread.h"
+#include "SurfaceFlinger.h"
 
 namespace android {
 
@@ -43,36 +49,69 @@
 
 // ---------------------------------------------------------------------------
 
+void MessageQueue::Handler::signalRefresh() {
+    if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) {
+        mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));
+    }
+}
+
+void MessageQueue::Handler::signalInvalidate() {
+    if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) {
+        mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
+    }
+}
+
+void MessageQueue::Handler::handleMessage(const Message& message) {
+    switch (message.what) {
+        case INVALIDATE:
+            android_atomic_and(~eventMaskInvalidate, &mEventMask);
+            mQueue.mFlinger->onMessageReceived(message.what);
+            break;
+        case REFRESH:
+            android_atomic_and(~eventMaskRefresh, &mEventMask);
+            mQueue.mFlinger->onMessageReceived(message.what);
+            break;
+    }
+}
+
+// ---------------------------------------------------------------------------
+
 MessageQueue::MessageQueue()
-    : mLooper(new Looper(true)), mWorkPending(0)
 {
 }
 
 MessageQueue::~MessageQueue() {
 }
 
+void MessageQueue::init(const sp<SurfaceFlinger>& flinger)
+{
+    mFlinger = flinger;
+    mLooper = new Looper(true);
+    mHandler = new Handler(*this);
+}
+
+void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
+{
+    mEventThread = eventThread;
+    mEvents = eventThread->createEventConnection();
+    mEventTube = mEvents->getDataChannel();
+    mLooper->addFd(mEventTube->getFd(), 0, ALOOPER_EVENT_INPUT,
+            MessageQueue::cb_eventReceiver, this);
+}
+
 void MessageQueue::waitMessage() {
     do {
         IPCThreadState::self()->flushCommands();
-
         int32_t ret = mLooper->pollOnce(-1);
         switch (ret) {
             case ALOOPER_POLL_WAKE:
             case ALOOPER_POLL_CALLBACK:
-                // callback and/or wake
-                if (android_atomic_and(0, &mWorkPending)) {
-                    return;
-                }
                 continue;
-
+            case ALOOPER_POLL_ERROR:
+                ALOGE("ALOOPER_POLL_ERROR");
             case ALOOPER_POLL_TIMEOUT:
                 // timeout (should not happen)
                 continue;
-
-            case ALOOPER_POLL_ERROR:
-                ALOGE("ALOOPER_POLL_ERROR");
-                continue;
-
             default:
                 // should not happen
                 ALOGE("Looper::pollOnce() returned unknown status %d", ret);
@@ -93,11 +132,31 @@
     return NO_ERROR;
 }
 
-status_t MessageQueue::invalidate() {
-    if (android_atomic_or(1, &mWorkPending) == 0) {
-        mLooper->wake();
+void MessageQueue::invalidate() {
+    mHandler->signalInvalidate();
+}
+
+void MessageQueue::refresh() {
+    mEvents->requestNextVsync();
+}
+
+int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
+    MessageQueue* queue = reinterpret_cast<MessageQueue *>(data);
+    return queue->eventReceiver(fd, events);
+}
+
+int MessageQueue::eventReceiver(int fd, int events) {
+    ssize_t n;
+    DisplayEventReceiver::Event buffer[8];
+    while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) {
+        for (int i=0 ; i<n ; i++) {
+            if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
+                mHandler->signalRefresh();
+                break;
+            }
+        }
     }
-    return NO_ERROR;
+    return 1;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h
index 2317d81..ea29e7e 100644
--- a/services/surfaceflinger/MessageQueue.h
+++ b/services/surfaceflinger/MessageQueue.h
@@ -25,10 +25,16 @@
 #include <utils/Timers.h>
 #include <utils/Looper.h>
 
+#include <gui/DisplayEventReceiver.h>
+
 #include "Barrier.h"
 
 namespace android {
 
+class IDisplayEventConnection;
+class EventThread;
+class SurfaceFlinger;
+
 // ---------------------------------------------------------------------------
 
 class MessageBase : public MessageHandler
@@ -54,16 +60,48 @@
 // ---------------------------------------------------------------------------
 
 class MessageQueue {
+    class Handler : public MessageHandler {
+        enum {
+            eventMaskInvalidate = 0x1,
+            eventMaskRefresh    = 0x2
+        };
+        MessageQueue& mQueue;
+        int32_t mEventMask;
+    public:
+        Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { }
+        virtual void handleMessage(const Message& message);
+        void signalRefresh();
+        void signalInvalidate();
+    };
+
+    friend class Handler;
+
+    sp<SurfaceFlinger> mFlinger;
     sp<Looper> mLooper;
-    volatile int32_t mWorkPending;
+    sp<EventThread> mEventThread;
+    sp<IDisplayEventConnection> mEvents;
+    sp<BitTube> mEventTube;
+    sp<Handler> mHandler;
+
+
+    static int cb_eventReceiver(int fd, int events, void* data);
+    int eventReceiver(int fd, int events);
 
 public:
+    enum {
+        INVALIDATE = 0,
+        REFRESH    = 1,
+    };
+
     MessageQueue();
     ~MessageQueue();
+    void init(const sp<SurfaceFlinger>& flinger);
+    void setEventThread(const sp<EventThread>& events);
 
     void waitMessage();
     status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime=0);
-    status_t invalidate();
+    void invalidate();
+    void refresh();
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 887aee7..870235b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -125,11 +125,34 @@
     ALOGI_IF(mDebugDDMS,         "DDMS debugging enabled");
 }
 
+void SurfaceFlinger::onFirstRef()
+{
+    mEventQueue.init(this);
+
+    run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
+
+    // Wait for the main thread to be done with its initialization
+    mReadyToRunBarrier.wait();
+}
+
+
 SurfaceFlinger::~SurfaceFlinger()
 {
     glDeleteTextures(1, &mWormholeTexName);
 }
 
+void SurfaceFlinger::binderDied(const wp<IBinder>& who)
+{
+    // the window manager died on us. prepare its eulogy.
+
+    // reset screen orientation
+    Vector<ComposerState> state;
+    setTransactionState(state, eOrientationDefault, 0);
+
+    // restart the boot-animation
+    property_set("ctl.start", "bootanim");
+}
+
 sp<IMemoryHeap> SurfaceFlinger::getCblk() const
 {
     return mServerHeap;
@@ -183,26 +206,6 @@
     property_set("ctl.stop", "bootanim");
 }
 
-void SurfaceFlinger::binderDied(const wp<IBinder>& who)
-{
-    // the window manager died on us. prepare its eulogy.
-
-    // reset screen orientation
-    Vector<ComposerState> state;
-    setTransactionState(state, eOrientationDefault, 0);
-
-    // restart the boot-animation
-    property_set("ctl.start", "bootanim");
-}
-
-void SurfaceFlinger::onFirstRef()
-{
-    run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
-
-    // Wait for the main thread to be done with its initialization
-    mReadyToRunBarrier.wait();
-}
-
 static inline uint16_t pack565(int r, int g, int b) {
     return (r<<11)|(g<<5)|b;
 }
@@ -296,6 +299,7 @@
 
     // start the EventThread
     mEventThread = new EventThread(this);
+    mEventQueue.setEventThread(mEventThread);
 
     /*
      *  We're now ready to accept clients...
@@ -310,34 +314,6 @@
 }
 
 // ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Events Handler
-#endif
-
-void SurfaceFlinger::waitForEvent() {
-    mEventQueue.waitMessage();
-}
-
-void SurfaceFlinger::signalEvent() {
-    mEventQueue.invalidate();
-}
-
-status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
-        nsecs_t reltime, uint32_t flags) {
-    return mEventQueue.postMessage(msg, reltime);
-}
-
-status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
-        nsecs_t reltime, uint32_t flags) {
-    status_t res = mEventQueue.postMessage(msg, reltime);
-    if (res == NO_ERROR) {
-        msg->wait();
-    }
-    return res;
-}
-
-// ----------------------------------------------------------------------------
 
 bool SurfaceFlinger::authenticateSurfaceTexture(
         const sp<ISurfaceTexture>& surfaceTexture) const {
@@ -383,60 +359,97 @@
 // ----------------------------------------------------------------------------
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
-    sp<DisplayEventConnection> result(new DisplayEventConnection(mEventThread));
-    return result;
+    return mEventThread->createEventConnection();
 }
 
 // ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Main loop
-#endif
+
+void SurfaceFlinger::waitForEvent() {
+    mEventQueue.waitMessage();
+}
+
+void SurfaceFlinger::signalTransaction() {
+    mEventQueue.invalidate();
+}
+
+void SurfaceFlinger::signalLayerUpdate() {
+    mEventQueue.invalidate();
+}
+
+void SurfaceFlinger::signalRefresh() {
+    mEventQueue.refresh();
+}
+
+status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
+        nsecs_t reltime, uint32_t flags) {
+    return mEventQueue.postMessage(msg, reltime);
+}
+
+status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
+        nsecs_t reltime, uint32_t flags) {
+    status_t res = mEventQueue.postMessage(msg, reltime);
+    if (res == NO_ERROR) {
+        msg->wait();
+    }
+    return res;
+}
 
 bool SurfaceFlinger::threadLoop()
 {
     waitForEvent();
-
-    // check for transactions
-    if (CC_UNLIKELY(mConsoleSignals)) {
-        handleConsoleEvents();
-    }
-
-    // if we're in a global transaction, don't do anything.
-    const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
-    uint32_t transactionFlags = peekTransactionFlags(mask);
-    if (CC_UNLIKELY(transactionFlags)) {
-        handleTransaction(transactionFlags);
-    }
-
-    // post surfaces (if needed)
-    handlePageFlip();
-
-    if (mDirtyRegion.isEmpty()) {
-        // nothing new to do.
-        return true;
-    }
-
-    if (CC_UNLIKELY(mHwWorkListDirty)) {
-        // build the h/w work list
-        handleWorkList();
-    }
-
-    const DisplayHardware& hw(graphicPlane(0).displayHardware());
-    if (CC_LIKELY(hw.canDraw())) {
-        // repaint the framebuffer (if needed)
-        handleRepaint();
-        // inform the h/w that we're done compositing
-        hw.compositionComplete();
-        postFramebuffer();
-    } else {
-        // pretend we did the post
-        hw.compositionComplete();
-        hw.waitForRefresh();
-    }
     return true;
 }
 
+void SurfaceFlinger::onMessageReceived(int32_t what)
+{
+    switch (what) {
+        case MessageQueue::INVALIDATE: {
+            // check for transactions
+            if (CC_UNLIKELY(mConsoleSignals)) {
+                handleConsoleEvents();
+            }
+
+            // if we're in a global transaction, don't do anything.
+            const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
+            uint32_t transactionFlags = peekTransactionFlags(mask);
+            if (CC_UNLIKELY(transactionFlags)) {
+                handleTransaction(transactionFlags);
+            }
+
+            // post surfaces (if needed)
+            handlePageFlip();
+
+            if (!mDirtyRegion.isEmpty()) {
+                signalRefresh();
+            }
+        } break;
+
+        case MessageQueue::REFRESH: {
+            if (!mDirtyRegion.isEmpty()) {
+                // NOTE: it is mandatory to call hw.compositionComplete()
+                // after handleRefresh()
+                handleRefresh();
+
+                const DisplayHardware& hw(graphicPlane(0).displayHardware());
+                if (CC_UNLIKELY(mHwWorkListDirty)) {
+                    // build the h/w work list
+                    handleWorkList();
+                }
+                if (CC_LIKELY(hw.canDraw())) {
+                    // repaint the framebuffer (if needed)
+                    handleRepaint();
+                    // inform the h/w that we're done compositing
+                    hw.compositionComplete();
+                    postFramebuffer();
+                } else {
+                    // pretend we did the post
+                    hw.compositionComplete();
+                }
+            }
+        } break;
+    }
+}
+
 void SurfaceFlinger::postFramebuffer()
 {
     // this should never happen. we do the flip anyways so we don't
@@ -718,13 +731,13 @@
 
 void SurfaceFlinger::handlePageFlip()
 {
-    bool visibleRegions = mVisibleRegionsDirty;
-    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
-    visibleRegions |= lockPageFlip(currentLayers);
+    const DisplayHardware& hw = graphicPlane(0).displayHardware();
+    const Region screenRegion(hw.bounds());
 
-        const DisplayHardware& hw = graphicPlane(0).displayHardware();
-        const Region screenRegion(hw.bounds());
-        if (visibleRegions) {
+    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
+    const bool visibleRegions = lockPageFlip(currentLayers);
+
+        if (visibleRegions || mVisibleRegionsDirty) {
             Region opaqueRegion;
             computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion);
 
@@ -771,7 +784,7 @@
 {
     const GraphicPlane& plane(graphicPlane(0));
     const Transform& planeTransform(plane.transform());
-    size_t count = currentLayers.size();
+    const size_t count = currentLayers.size();
     sp<LayerBase> const* layers = currentLayers.array();
     for (size_t i=0 ; i<count ; i++) {
         const sp<LayerBase>& layer(layers[i]);
@@ -779,6 +792,23 @@
     }
 }
 
+void SurfaceFlinger::handleRefresh()
+{
+    bool needInvalidate = false;
+    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
+    const size_t count = currentLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        const sp<LayerBase>& layer(currentLayers[i]);
+        if (layer->onPreComposition()) {
+            needInvalidate = true;
+        }
+    }
+    if (needInvalidate) {
+        signalLayerUpdate();
+    }
+}
+
+
 void SurfaceFlinger::handleWorkList()
 {
     mHwWorkListDirty = false;
@@ -1176,7 +1206,7 @@
 {
     uint32_t old = android_atomic_or(flags, &mTransactionFlags);
     if ((old & flags)==0) { // wake the server up
-        signalEvent();
+        signalTransaction();
     }
     return old;
 }
@@ -1427,14 +1457,14 @@
 {
     // this may be called by a signal handler, we can't do too much in here
     android_atomic_or(eConsoleReleased, &mConsoleSignals);
-    signalEvent();
+    signalTransaction();
 }
 
 void SurfaceFlinger::screenAcquired(int dpy)
 {
     // this may be called by a signal handler, we can't do too much in here
     android_atomic_or(eConsoleAcquired, &mConsoleSignals);
-    signalEvent();
+    signalTransaction();
 }
 
 status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
@@ -1770,7 +1800,7 @@
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     const Rect bounds(hw.getBounds());
     setInvalidateRegion(Region(bounds));
-    signalEvent();
+    signalTransaction();
 }
 
 void SurfaceFlinger::setInvalidateRegion(const Region& reg) {
@@ -2246,7 +2276,7 @@
 
     // make sure to redraw the whole screen when the animation is done
     mDirtyRegion.set(hw.bounds());
-    signalEvent();
+    signalTransaction();
 
     return NO_ERROR;
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index c24a9de..fcd9361 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -190,6 +190,8 @@
             status_t renderScreenToTextureLocked(DisplayID dpy,
                     GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
 
+            void onMessageReceived(int32_t what);
+
             status_t postMessageAsync(const sp<MessageBase>& msg,
                     nsecs_t reltime=0, uint32_t flags = 0);
 
@@ -283,7 +285,10 @@
 public:     // hack to work around gcc 4.0.3 bug
     const GraphicPlane&     graphicPlane(int dpy) const;
           GraphicPlane&     graphicPlane(int dpy);
-          void              signalEvent();
+
+          void              signalTransaction();
+          void              signalLayerUpdate();
+          void              signalRefresh();
           void              repaintEverything();
 
 private:
@@ -300,6 +305,7 @@
             void        handlePageFlip();
             bool        lockPageFlip(const LayerVector& currentLayers);
             void        unlockPageFlip(const LayerVector& currentLayers);
+            void        handleRefresh();
             void        handleWorkList();
             void        handleRepaint();
             void        postFramebuffer();
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index 259b937..49e8e63 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -94,6 +94,10 @@
             *outTransform = orientation;
         }
         switch(api) {
+            case NATIVE_WINDOW_API_CPU:
+                // SurfaceTextureClient supports only 2 buffers for CPU connections
+                this->setBufferCountServer(2);
+                break;
             case NATIVE_WINDOW_API_MEDIA:
             case NATIVE_WINDOW_API_CAMERA:
                 // Camera preview and videos are rate-limited on the producer
diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp
index 4f79080..b0d54c4 100644
--- a/services/surfaceflinger/tests/vsync/vsync.cpp
+++ b/services/surfaceflinger/tests/vsync/vsync.cpp
@@ -55,6 +55,8 @@
     loop->addFd(myDisplayEvent.getFd(), 0, ALOOPER_EVENT_INPUT, receiver,
             &myDisplayEvent);
 
+    myDisplayEvent.setVsyncRate(1);
+
     do {
         //printf("about to poll...\n");
         int32_t ret = loop->pollOnce(-1);
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 36a2567..2bf8b1c 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -21,7 +21,6 @@
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.NetworkPolicy.LIMIT_DISABLED;
-import static android.net.NetworkPolicy.SNOOZE_NEVER;
 import static android.net.NetworkPolicy.WARNING_DISABLED;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
@@ -256,41 +255,49 @@
     }
 
     public void testPidForegroundCombined() throws Exception {
+        IdleFuture idle;
+
         // push all uid into background
+        idle = expectIdle();
         mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
         mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
         mProcessObserver.onForegroundActivitiesChanged(PID_3, UID_B, false);
-        waitUntilIdle();
+        idle.get();
         assertFalse(mService.isUidForeground(UID_A));
         assertFalse(mService.isUidForeground(UID_B));
 
         // push one of the shared pids into foreground
+        idle = expectIdle();
         mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, true);
-        waitUntilIdle();
+        idle.get();
         assertTrue(mService.isUidForeground(UID_A));
         assertFalse(mService.isUidForeground(UID_B));
 
         // and swap another uid into foreground
+        idle = expectIdle();
         mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
         mProcessObserver.onForegroundActivitiesChanged(PID_3, UID_B, true);
-        waitUntilIdle();
+        idle.get();
         assertFalse(mService.isUidForeground(UID_A));
         assertTrue(mService.isUidForeground(UID_B));
 
         // push both pid into foreground
+        idle = expectIdle();
         mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
         mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, true);
-        waitUntilIdle();
+        idle.get();
         assertTrue(mService.isUidForeground(UID_A));
 
         // pull one out, should still be foreground
+        idle = expectIdle();
         mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
-        waitUntilIdle();
+        idle.get();
         assertTrue(mService.isUidForeground(UID_A));
 
         // pull final pid out, should now be background
+        idle = expectIdle();
         mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
-        waitUntilIdle();
+        idle.get();
         assertFalse(mService.isUidForeground(UID_A));
     }
 
@@ -434,7 +441,7 @@
         final long expectedCycle = parseTime("2007-11-05T00:00:00.000Z");
 
         final NetworkPolicy policy = new NetworkPolicy(
-                sTemplateWifi, 5, 1024L, 1024L, SNOOZE_NEVER, false);
+                sTemplateWifi, 5, 1024L, 1024L, false);
         final long actualCycle = computeLastCycleBoundary(currentTime, policy);
         assertTimeEquals(expectedCycle, actualCycle);
     }
@@ -445,7 +452,7 @@
         final long expectedCycle = parseTime("2007-10-20T00:00:00.000Z");
 
         final NetworkPolicy policy = new NetworkPolicy(
-                sTemplateWifi, 20, 1024L, 1024L, SNOOZE_NEVER, false);
+                sTemplateWifi, 20, 1024L, 1024L, false);
         final long actualCycle = computeLastCycleBoundary(currentTime, policy);
         assertTimeEquals(expectedCycle, actualCycle);
     }
@@ -456,7 +463,7 @@
         final long expectedCycle = parseTime("2007-01-30T00:00:00.000Z");
 
         final NetworkPolicy policy = new NetworkPolicy(
-                sTemplateWifi, 30, 1024L, 1024L, SNOOZE_NEVER, false);
+                sTemplateWifi, 30, 1024L, 1024L, false);
         final long actualCycle = computeLastCycleBoundary(currentTime, policy);
         assertTimeEquals(expectedCycle, actualCycle);
     }
@@ -467,14 +474,14 @@
         final long expectedCycle = parseTime("2007-02-28T23:59:59.000Z");
 
         final NetworkPolicy policy = new NetworkPolicy(
-                sTemplateWifi, 30, 1024L, 1024L, SNOOZE_NEVER, false);
+                sTemplateWifi, 30, 1024L, 1024L, false);
         final long actualCycle = computeLastCycleBoundary(currentTime, policy);
         assertTimeEquals(expectedCycle, actualCycle);
     }
 
     public void testNextCycleSane() throws Exception {
         final NetworkPolicy policy = new NetworkPolicy(
-                sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER, false);
+                sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, false);
         final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
 
         // walk forwards, ensuring that cycle boundaries don't get stuck
@@ -489,7 +496,7 @@
 
     public void testLastCycleSane() throws Exception {
         final NetworkPolicy policy = new NetworkPolicy(
-                sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER, false);
+                sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, false);
         final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
 
         // walk backwards, ensuring that cycle boundaries look sane
@@ -547,7 +554,7 @@
 
         replay();
         setNetworkPolicies(new NetworkPolicy(
-                sTemplateWifi, CYCLE_DAY, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES, SNOOZE_NEVER, false));
+                sTemplateWifi, CYCLE_DAY, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES, false));
         future.get();
         verifyAndReset();
     }
@@ -604,9 +611,8 @@
             future = expectMeteredIfacesChanged();
 
             replay();
-            setNetworkPolicies(
-                    new NetworkPolicy(sTemplateWifi, CYCLE_DAY, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES,
-                            SNOOZE_NEVER, false));
+            setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, 1 * MB_IN_BYTES,
+                    2 * MB_IN_BYTES, false));
             future.get();
             verifyAndReset();
         }
@@ -698,7 +704,7 @@
             tagFuture = expectEnqueueNotification();
 
             replay();
-            mService.snoozePolicy(sTemplateWifi);
+            mService.snoozeLimit(sTemplateWifi);
             assertNotificationType(TYPE_LIMIT_SNOOZED, tagFuture.get());
             future.get();
             verifyAndReset();
@@ -736,9 +742,8 @@
             future = expectMeteredIfacesChanged(TEST_IFACE);
 
             replay();
-            setNetworkPolicies(
-                    new NetworkPolicy(sTemplateWifi, CYCLE_DAY, WARNING_DISABLED, LIMIT_DISABLED,
-                            SNOOZE_NEVER, true));
+            setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, WARNING_DISABLED,
+                    LIMIT_DISABLED, true));
             future.get();
             verifyAndReset();
         }
@@ -890,10 +895,10 @@
     /**
      * Wait until {@link #mService} internal {@link Handler} is idle.
      */
-    private void waitUntilIdle() throws Exception {
+    private IdleFuture expectIdle() {
         final IdleFuture future = new IdleFuture();
         mService.addIdleHandler(future);
-        future.get();
+        return future;
     }
 
     private static void assertTimeEquals(long expected, long actual) {
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index 3128592..1a4b574 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -47,6 +47,9 @@
         "none", "poor", "moderate", "good", "great"
     };
 
+    /** @hide */
+    public static final int INVALID_SNR = 0x7FFFFFFF;
+
     private int mGsmSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
     private int mGsmBitErrorRate;   // bit error rate (0-7, 99) as defined in TS 27.007 8.5
     private int mCdmaDbm;   // This value is the RSSI value
@@ -96,7 +99,7 @@
         mLteSignalStrength = -1;
         mLteRsrp = -1;
         mLteRsrq = -1;
-        mLteRssnr = -1;
+        mLteRssnr = INVALID_SNR;
         mLteCqi = -1;
         isGsm = true;
     }
@@ -136,7 +139,8 @@
             int evdoDbm, int evdoEcio, int evdoSnr,
             boolean gsm) {
         this(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
-                evdoDbm, evdoEcio, evdoSnr, -1, -1, -1, -1, -1, gsm);
+                evdoDbm, evdoEcio, evdoSnr, -1, -1,
+                -1, INVALID_SNR, -1, gsm);
     }
 
     /**
@@ -292,7 +296,7 @@
             if ((mLteSignalStrength == -1)
                     && (mLteRsrp == -1)
                     && (mLteRsrq == -1)
-                    && (mLteRssnr == -1)
+                    && (mLteRssnr == INVALID_SNR)
                     && (mLteCqi == -1)) {
                 level = getGsmLevel();
             } else {
@@ -327,7 +331,7 @@
             if ((mLteSignalStrength == -1)
                     && (mLteRsrp == -1)
                     && (mLteRsrq == -1)
-                    && (mLteRssnr == -1)
+                    && (mLteRssnr == INVALID_SNR)
                     && (mLteCqi == -1)) {
                 asuLevel = getGsmAsuLevel();
             } else {
@@ -363,7 +367,7 @@
             if ((mLteSignalStrength == -1)
                     && (mLteRsrp == -1)
                     && (mLteRsrq == -1)
-                    && (mLteRssnr == -1)
+                    && (mLteRssnr == INVALID_SNR)
                     && (mLteCqi == -1)) {
                 dBm = getGsmDbm();
             } else {
@@ -566,16 +570,31 @@
      */
     public int getLteLevel() {
         int levelLteRsrp = 0;
+        int levelLteRssnr = 0;
 
         if (mLteRsrp == -1) levelLteRsrp = 0;
-        else if (mLteRsrp >= -90) levelLteRsrp = SIGNAL_STRENGTH_GREAT;
-        else if (mLteRsrp >= -100) levelLteRsrp = SIGNAL_STRENGTH_GOOD;
-        else if (mLteRsrp >= -110) levelLteRsrp = SIGNAL_STRENGTH_MODERATE;
-        else if (mLteRsrp >= -118) levelLteRsrp = SIGNAL_STRENGTH_POOR;
-        else levelLteRsrp = 0;
+        else if (mLteRsrp >= -95) levelLteRsrp = SIGNAL_STRENGTH_GREAT;
+        else if (mLteRsrp >= -105) levelLteRsrp = SIGNAL_STRENGTH_GOOD;
+        else if (mLteRsrp >= -115) levelLteRsrp = SIGNAL_STRENGTH_MODERATE;
+        else levelLteRsrp = SIGNAL_STRENGTH_POOR;
 
-        if (DBG) log("Lte level: "+levelLteRsrp);
-        return levelLteRsrp;
+        if (mLteRssnr == INVALID_SNR) levelLteRssnr = 0;
+        else if (mLteRssnr >= 45) levelLteRssnr = SIGNAL_STRENGTH_GREAT;
+        else if (mLteRssnr >= 10) levelLteRssnr = SIGNAL_STRENGTH_GOOD;
+        else if (mLteRssnr >= -30) levelLteRssnr = SIGNAL_STRENGTH_MODERATE;
+        else levelLteRssnr = SIGNAL_STRENGTH_POOR;
+
+        int level;
+        if (mLteRsrp == -1)
+            level = levelLteRssnr;
+        else if (mLteRssnr == INVALID_SNR)
+            level = levelLteRsrp;
+        else
+            level = (levelLteRssnr < levelLteRsrp) ? levelLteRssnr : levelLteRsrp;
+
+        if (DBG) log("Lte rsrp level: "+levelLteRsrp
+                + " snr level: " + levelLteRssnr + " level: " + level);
+        return level;
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index ee39850..a0efab2 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -93,11 +93,6 @@
     static final int USSD_MODE_NOTIFY       = 0;
     static final int USSD_MODE_REQUEST      = 1;
 
-    // SIM Refresh results, passed up from RIL.
-    static final int SIM_REFRESH_FILE_UPDATED   = 0;  // Single file updated
-    static final int SIM_REFRESH_INIT           = 1;  // SIM initialized; reload all
-    static final int SIM_REFRESH_RESET          = 2;  // SIM reset; may be locked
-
     // GSM SMS fail cause for acknowledgeLastIncomingSMS. From TS 23.040, 9.2.3.22.
     static final int GSM_SMS_FAIL_CAUSE_MEMORY_CAPACITY_EXCEEDED    = 0xD3;
     static final int GSM_SMS_FAIL_CAUSE_USIM_APP_TOOLKIT_BUSY       = 0xD4;
@@ -764,6 +759,15 @@
      *  retMsg.obj = AsyncResult ar
      *  ar.exception carries exception on failure
      *  ar.userObject contains the orignal value of result.obj
+     *  ar.result is String containing IMSI on success
+     */
+    void getIMSIForApp(String aid, Message result);
+
+    /**
+     *  returned message
+     *  retMsg.obj = AsyncResult ar
+     *  ar.exception carries exception on failure
+     *  ar.userObject contains the orignal value of result.obj
      *  ar.result is String containing IMEI on success
      */
     void getIMEI(Message result);
@@ -1055,6 +1059,14 @@
             String data, String pin2, Message response);
 
     /**
+     * parameters equivalent to 27.007 AT+CRSM command
+     * response.obj will be an AsyncResult
+     * response.obj.userObj will be a IccIoResult on success
+     */
+    void iccIOForApp (int command, int fileid, String path, int p1, int p2, int p3,
+            String data, String pin2, String aid, Message response);
+
+    /**
      * (AsyncResult)response.obj).result is an int[] with element [0] set to
      * 1 for "CLIP is provisioned", and 0 for "CLIP is not provisioned".
      *
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index f4308a0..a9ef762 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -48,7 +48,7 @@
     protected String mLogTag;
     protected boolean mDbg;
 
-    private IccCardStatus mIccCardStatus = null;
+    protected IccCardStatus mIccCardStatus = null;
     protected State mState = null;
     private final Object mStateMonitor = new Object();
 
@@ -911,4 +911,24 @@
     private void log(String msg) {
         Log.d(mLogTag, "[IccCard] " + msg);
     }
+
+    protected abstract int getCurrentApplicationIndex();
+
+    public String getAid() {
+        String aid = "";
+        int appIndex = getCurrentApplicationIndex();
+
+        if (appIndex >= 0 && appIndex < IccCardStatus.CARD_MAX_APPS) {
+            IccCardApplication app = mIccCardStatus.getApplication(appIndex);
+            if (app != null) {
+                aid = app.aid;
+            } else {
+                Log.e(mLogTag, "[IccCard] getAid: no current application index=" + appIndex);
+            }
+        } else {
+            Log.e(mLogTag, "[IccCard] getAid: Invalid Subscription Application index=" + appIndex);
+        }
+
+        return aid;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/IccCardStatus.java b/telephony/java/com/android/internal/telephony/IccCardStatus.java
index c751a21..a3bdd76 100644
--- a/telephony/java/com/android/internal/telephony/IccCardStatus.java
+++ b/telephony/java/com/android/internal/telephony/IccCardStatus.java
@@ -24,7 +24,7 @@
  * {@hide}
  */
 public class IccCardStatus {
-    static final int CARD_MAX_APPS = 8;
+    public static final int CARD_MAX_APPS = 8;
 
     public enum CardState {
         CARDSTATE_ABSENT,
diff --git a/telephony/java/com/android/internal/telephony/IccFileHandler.java b/telephony/java/com/android/internal/telephony/IccFileHandler.java
index 93b9b79..380bfd1 100644
--- a/telephony/java/com/android/internal/telephony/IccFileHandler.java
+++ b/telephony/java/com/android/internal/telephony/IccFileHandler.java
@@ -145,8 +145,9 @@
             = obtainMessage(EVENT_GET_RECORD_SIZE_DONE,
                         new LoadLinearFixedContext(fileid, recordNum, onLoaded));
 
-        phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
-                        0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
+        phone.mCM.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
+                        0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null,
+                        phone.getIccCard().getAid(), response);
     }
 
     /**
@@ -164,9 +165,10 @@
                         onLoaded));
 
         // TODO(): Verify when path changes are done.
-        phone.mCM.iccIO(COMMAND_GET_RESPONSE, IccConstants.EF_IMG, "img",
+        phone.mCM.iccIOForApp(COMMAND_GET_RESPONSE, IccConstants.EF_IMG, "img",
                 recordNum, READ_RECORD_MODE_ABSOLUTE,
-                GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null, response);
+                GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null,
+                phone.getIccCard().getAid(), response);
     }
 
     /**
@@ -182,8 +184,9 @@
         Message response
                 = obtainMessage(EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE,
                         new LoadLinearFixedContext(fileid, onLoaded));
-        phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
-                    0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
+        phone.mCM.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
+                    0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, phone.getIccCard().getAid(),
+                    response);
     }
 
     /**
@@ -199,8 +202,9 @@
         Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE,
                         new LoadLinearFixedContext(fileid,onLoaded));
 
-        phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
-                        0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
+        phone.mCM.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
+                        0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null,
+                        phone.getIccCard().getAid(), response);
     }
 
     /**
@@ -217,8 +221,9 @@
         Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE,
                         fileid, 0, onLoaded);
 
-        phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
-                        0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
+        phone.mCM.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
+                        0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null,
+                        phone.getIccCard().getAid(), response);
     }
 
     /**
@@ -236,8 +241,8 @@
         Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0,
                 onLoaded);
 
-        phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, "img", highOffset, lowOffset,
-                length, null, null, response);
+        phone.mCM.iccIOForApp(COMMAND_READ_BINARY, fileid, "img", highOffset, lowOffset,
+                length, null, null, phone.getIccCard().getAid(), response);
     }
 
     /**
@@ -251,9 +256,10 @@
      */
     public void updateEFLinearFixed(int fileid, int recordNum, byte[] data,
             String pin2, Message onComplete) {
-        phone.mCM.iccIO(COMMAND_UPDATE_RECORD, fileid, getEFPath(fileid),
+        phone.mCM.iccIOForApp(COMMAND_UPDATE_RECORD, fileid, getEFPath(fileid),
                         recordNum, READ_RECORD_MODE_ABSOLUTE, data.length,
-                        IccUtils.bytesToHexString(data), pin2, onComplete);
+                        IccUtils.bytesToHexString(data), pin2,
+                        phone.getIccCard().getAid(), onComplete);
     }
 
     /**
@@ -262,9 +268,10 @@
      * @param data must be exactly as long as the EF
      */
     public void updateEFTransparent(int fileid, byte[] data, Message onComplete) {
-        phone.mCM.iccIO(COMMAND_UPDATE_BINARY, fileid, getEFPath(fileid),
+        phone.mCM.iccIOForApp(COMMAND_UPDATE_BINARY, fileid, getEFPath(fileid),
                         0, 0, data.length,
-                        IccUtils.bytesToHexString(data), null, onComplete);
+                        IccUtils.bytesToHexString(data), null,
+                        phone.getIccCard().getAid(), onComplete);
     }
 
 
@@ -395,10 +402,11 @@
                      lc.results = new ArrayList<byte[]>(lc.countRecords);
                  }
 
-                 phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, getEFPath(lc.efid),
+                 phone.mCM.iccIOForApp(COMMAND_READ_RECORD, lc.efid, getEFPath(lc.efid),
                          lc.recordNum,
                          READ_RECORD_MODE_ABSOLUTE,
                          lc.recordSize, null, null,
+                         phone.getIccCard().getAid(),
                          obtainMessage(EVENT_READ_RECORD_DONE, lc));
                  break;
             case EVENT_GET_BINARY_SIZE_DONE:
@@ -433,8 +441,9 @@
                 size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
                        + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
 
-                phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
+                phone.mCM.iccIOForApp(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
                                 0, 0, size, null, null,
+                                phone.getIccCard().getAid(),
                                 obtainMessage(EVENT_READ_BINARY_DONE,
                                               fileid, 0, response));
             break;
@@ -468,10 +477,11 @@
                     if (lc.recordNum > lc.countRecords) {
                         sendResult(response, lc.results, null);
                     } else {
-                        phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, getEFPath(lc.efid),
+                        phone.mCM.iccIOForApp(COMMAND_READ_RECORD, lc.efid, getEFPath(lc.efid),
                                     lc.recordNum,
                                     READ_RECORD_MODE_ABSOLUTE,
                                     lc.recordSize, null, null,
+                                    phone.getIccCard().getAid(),
                                     obtainMessage(EVENT_READ_RECORD_DONE, lc));
                     }
                 }
diff --git a/telephony/java/com/android/internal/telephony/IccRefreshResponse.java b/telephony/java/com/android/internal/telephony/IccRefreshResponse.java
new file mode 100644
index 0000000..6806703
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccRefreshResponse.java
@@ -0,0 +1,42 @@
+/*
+ * 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 com.android.internal.telephony;
+
+/**
+ * See also RIL_SimRefresh in include/telephony/ril.h
+ *
+ * {@hide}
+ */
+
+public class IccRefreshResponse {
+
+    public static final int REFRESH_RESULT_FILE_UPDATE = 0; /* Single file was updated */
+    public static final int REFRESH_RESULT_INIT = 1;        /* The Icc has been initialized */
+    public static final int REFRESH_RESULT_RESET = 2;       /* The Icc was reset */
+
+    public int             refreshResult;      /* Sim Refresh result */
+    public int             efId;               /* EFID */
+    public String          aid;                /* null terminated string, e.g.,
+                                                  from 0xA0, 0x00 -> 0x41,
+                                                  0x30, 0x30, 0x30 */
+                                               /* Example: a0000000871002f310ffff89080000ff */
+
+    @Override
+    public String toString() {
+        return "{" + refreshResult + ", " + aid +", " + efId + "}";
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 718a4fd..f587fe1 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -52,6 +52,7 @@
 import com.android.internal.telephony.gsm.SuppServiceNotification;
 import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
 import com.android.internal.telephony.cdma.CdmaInformationRecords;
+import com.android.internal.telephony.IccRefreshResponse;
 
 import java.io.ByteArrayInputStream;
 import java.io.DataInputStream;
@@ -879,9 +880,19 @@
 
     public void
     getIMSI(Message result) {
+        getIMSIForApp(null, result);
+    }
+
+    public void
+    getIMSIForApp(String aid, Message result) {
         RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMSI, result);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+        rr.mp.writeInt(1);
+        rr.mp.writeString(aid);
+
+        if (RILJ_LOGD) riljLog(rr.serialString() +
+                              "> getIMSI: " + requestToString(rr.mRequest)
+                              + " aid: " + aid);
 
         send(rr);
     }
@@ -1434,6 +1445,11 @@
     public void
     iccIO (int command, int fileid, String path, int p1, int p2, int p3,
             String data, String pin2, Message result) {
+        iccIOForApp(command, fileid, path, p1, p2, p3, data, pin2, null, result);
+    }
+    public void
+    iccIOForApp (int command, int fileid, String path, int p1, int p2, int p3,
+            String data, String pin2, String aid, Message result) {
         //Note: This RIL request has not been renamed to ICC,
         //       but this request is also valid for SIM and RUIM
         RILRequest rr
@@ -1447,12 +1463,15 @@
         rr.mp.writeInt(p3);
         rr.mp.writeString(data);
         rr.mp.writeString(pin2);
+        rr.mp.writeString(aid);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> iccIO: " + requestToString(rr.mRequest)
+        if (RILJ_LOGD) riljLog(rr.serialString() + "> iccIO: "
+                + requestToString(rr.mRequest)
                 + " 0x" + Integer.toHexString(command)
                 + " 0x" + Integer.toHexString(fileid) + " "
                 + " path: " + path + ","
-                + p1 + "," + p2 + "," + p3);
+                + p1 + "," + p2 + "," + p3
+                + " aid: " + aid);
 
         send(rr);
     }
@@ -2419,7 +2438,7 @@
             case RIL_UNSOL_STK_EVENT_NOTIFY: ret = responseString(p); break;
             case RIL_UNSOL_STK_CALL_SETUP: ret = responseInts(p); break;
             case RIL_UNSOL_SIM_SMS_STORAGE_FULL: ret =  responseVoid(p); break;
-            case RIL_UNSOL_SIM_REFRESH: ret =  responseInts(p); break;
+            case RIL_UNSOL_SIM_REFRESH: ret =  responseSimRefresh(p); break;
             case RIL_UNSOL_CALL_RING: ret =  responseCallRing(p); break;
             case RIL_UNSOL_RESTRICTED_STATE_CHANGED: ret = responseInts(p); break;
             case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:  ret =  responseVoid(p); break;
@@ -2976,6 +2995,16 @@
     }
 
     private Object
+    responseSimRefresh(Parcel p) {
+        IccRefreshResponse response = new IccRefreshResponse();
+
+        response.refreshResult = p.readInt();
+        response.efId   = p.readInt();
+        response.aid = p.readString();
+        return response;
+    }
+
+    private Object
     responseCallList(Parcel p) {
         int num;
         int voiceSettings;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index 6b73cc5..7da23d0 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -124,7 +124,9 @@
 
     @Override
     protected void setSignalStrengthDefaultValues() {
-        mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, false);
+        // TODO Make a constructor only has boolean gsm as parameter
+        mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1,
+                -1, -1, -1, SignalStrength.INVALID_SNR, -1, false);
     }
 
     @Override
@@ -429,8 +431,13 @@
             setSignalStrengthDefaultValues();
         } else {
             int[] ints = (int[])ar.result;
-            int lteCqi = 99, lteRsrp = -1;
-            int lteRssi = 99;
+
+            int lteRssi = -1;
+            int lteRsrp = -1;
+            int lteRsrq = -1;
+            int lteRssnr = SignalStrength.INVALID_SNR;
+            int lteCqi = -1;
+
             int offset = 2;
             int cdmaDbm = (ints[offset] > 0) ? -ints[offset] : -120;
             int cdmaEcio = (ints[offset + 1] > 0) ? -ints[offset + 1] : -160;
@@ -438,10 +445,13 @@
             int evdoEcio = (ints[offset + 3] > 0) ? -ints[offset + 3] : -1;
             int evdoSnr = ((ints[offset + 4] > 0) && (ints[offset + 4] <= 8)) ? ints[offset + 4]
                     : -1;
+
             if (networkType == ServiceState.RADIO_TECHNOLOGY_LTE) {
-                lteRssi = (ints[offset + 5] >= 0) ? ints[offset + 5] : 99;
-                lteRsrp = (ints[offset + 6] < 0) ? ints[offset + 6] : -1;
-                lteCqi = (ints[offset + 7] >= 0) ? ints[offset + 7] : 99;
+                lteRssi = ints[offset+5];
+                lteRsrp = ints[offset+6];
+                lteRsrq = ints[offset+7];
+                lteRssnr = ints[offset+8];
+                lteCqi = ints[offset+9];
             }
 
             if (networkType != ServiceState.RADIO_TECHNOLOGY_LTE) {
@@ -449,7 +459,7 @@
                         evdoSnr, false);
             } else {
                 mSignalStrength = new SignalStrength(99, -1, cdmaDbm, cdmaEcio, evdoRssi, evdoEcio,
-                        evdoSnr, lteRssi, lteRsrp, -1, -1, lteCqi, true);
+                        evdoSnr, lteRssi, lteRsrp, lteRsrq, lteRssnr, lteCqi, true);
             }
         }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java
index b57af0e..8375fd0 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java
@@ -55,8 +55,8 @@
         if (fileid == EF_CSIM_EPRL) {
             // Entire PRL could be huge. We are only interested in
             // the first 4 bytes of the record.
-            phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
-                            0, 0, 4, null, null,
+            phone.mCM.iccIOForApp(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
+                            0, 0, 4, null, null, phone.getIccCard().getAid(),
                             obtainMessage(EVENT_READ_BINARY_DONE,
                                           fileid, 0, onLoaded));
         } else {
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
index 02eb86d..674fada 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
@@ -44,5 +44,13 @@
     public String getServiceProviderName () {
         return mPhone.mIccRecords.getServiceProviderName();
     }
+
+    @Override
+    protected int getCurrentApplicationIndex() {
+        if (mIccCardStatus == null) {
+            return -1;
+        }
+        return mIccCardStatus.getCdmaSubscriptionAppIndex();
+    }
  }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java b/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java
index 3e2a29b..375cc07 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java
@@ -57,8 +57,9 @@
         Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0,
                 onLoaded);
 
-        phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, "img", 0, 0,
-                GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null, response);
+        phone.mCM.iccIOForApp(COMMAND_GET_RESPONSE, fileid, "img", 0, 0,
+                GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null,
+                phone.getIccCard().getAid(), response);
     }
 
     @Override
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
index b057e46..17a200e 100755
--- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
@@ -29,6 +29,7 @@
 import com.android.internal.telephony.AdnRecordCache;
 import com.android.internal.telephony.AdnRecordLoader;
 import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.IccRefreshResponse;
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.cdma.RuimCard;
 import com.android.internal.telephony.MccTable;
@@ -300,7 +301,7 @@
                 isRecordLoadResponse = false;
                 ar = (AsyncResult)msg.obj;
                 if (ar.exception == null) {
-                    handleRuimRefresh((int[])(ar.result));
+                    handleRuimRefresh((IccRefreshResponse)ar.result);
                 }
                 break;
 
@@ -409,24 +410,30 @@
         ((CDMAPhone) phone).notifyMessageWaitingIndicator();
     }
 
-    private void handleRuimRefresh(int[] result) {
-        if (result == null || result.length == 0) {
-            if (DBG) log("handleRuimRefresh without input");
+    private void handleRuimRefresh(IccRefreshResponse refreshResponse) {
+        if (refreshResponse == null) {
+            if (DBG) log("handleRuimRefresh received without input");
             return;
         }
 
-        switch ((result[0])) {
-            case CommandsInterface.SIM_REFRESH_FILE_UPDATED:
+        if (refreshResponse.aid != null &&
+                !refreshResponse.aid.equals(phone.getIccCard().getAid())) {
+            // This is for different app. Ignore.
+            return;
+        }
+
+        switch (refreshResponse.refreshResult) {
+            case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE:
                 if (DBG) log("handleRuimRefresh with SIM_REFRESH_FILE_UPDATED");
                 adnCache.reset();
                 fetchRuimRecords();
                 break;
-            case CommandsInterface.SIM_REFRESH_INIT:
+            case IccRefreshResponse.REFRESH_RESULT_INIT:
                 if (DBG) log("handleRuimRefresh with SIM_REFRESH_INIT");
                 // need to reload all files (that we care about)
                 fetchRuimRecords();
                 break;
-            case CommandsInterface.SIM_REFRESH_RESET:
+            case IccRefreshResponse.REFRESH_RESULT_RESET:
                 if (DBG) log("handleRuimRefresh with SIM_REFRESH_RESET");
                 phone.mCM.setRadioPower(false, null);
                 /* Note: no need to call setRadioPower(true).  Assuming the desired
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 92e16ce..0ebeabe 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -675,7 +675,9 @@
     }
 
     private void setSignalStrengthDefaultValues() {
-        mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, true);
+        // TODO Make a constructor only has boolean gsm as parameter
+        mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1,
+                -1, -1, -1, SignalStrength.INVALID_SNR, -1, true);
     }
 
     /**
@@ -1013,7 +1015,7 @@
         int lteSignalStrength = -1;
         int lteRsrp = -1;
         int lteRsrq = -1;
-        int lteRssnr = -1;
+        int lteRssnr = SignalStrength.INVALID_SNR;
         int lteCqi = -1;
 
         if (ar.exception != null) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index 7c423c7..de8401e 100755
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -39,6 +39,7 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneBase;
 import com.android.internal.telephony.SmsMessageBase;
+import com.android.internal.telephony.IccRefreshResponse;
 
 import java.util.ArrayList;
 
@@ -1049,7 +1050,7 @@
                 ar = (AsyncResult)msg.obj;
                 if (DBG) log("Sim REFRESH with exception: " + ar.exception);
                 if (ar.exception == null) {
-                    handleSimRefresh((int[])(ar.result));
+                    handleSimRefresh((IccRefreshResponse)ar.result);
                 }
                 break;
             case EVENT_GET_CFIS_DONE:
@@ -1130,27 +1131,31 @@
         }
     }
 
-    private void handleSimRefresh(int[] result) {
-        if (result == null || result.length == 0) {
-	    if (DBG) log("handleSimRefresh without input");
+    private void handleSimRefresh(IccRefreshResponse refreshResponse){
+        if (refreshResponse == null) {
+            if (DBG) log("handleSimRefresh received without input");
             return;
         }
 
-        switch ((result[0])) {
-            case CommandsInterface.SIM_REFRESH_FILE_UPDATED:
- 		if (DBG) log("handleSimRefresh with SIM_REFRESH_FILE_UPDATED");
-                // result[1] contains the EFID of the updated file.
-                int efid = result[1];
-                handleFileUpdate(efid);
+        if (refreshResponse.aid != null &&
+                !refreshResponse.aid.equals(phone.getIccCard().getAid())) {
+            // This is for different app. Ignore.
+            return;
+        }
+
+        switch (refreshResponse.refreshResult) {
+            case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE:
+                if (DBG) log("handleSimRefresh with SIM_FILE_UPDATED");
+                handleFileUpdate(refreshResponse.efId);
                 break;
-            case CommandsInterface.SIM_REFRESH_INIT:
-		if (DBG) log("handleSimRefresh with SIM_REFRESH_INIT");
+            case IccRefreshResponse.REFRESH_RESULT_INIT:
+                if (DBG) log("handleSimRefresh with SIM_REFRESH_INIT");
                 // need to reload all files (that we care about)
                 adnCache.reset();
                 fetchSimRecords();
                 break;
-            case CommandsInterface.SIM_REFRESH_RESET:
-		if (DBG) log("handleSimRefresh with SIM_REFRESH_RESET");
+            case IccRefreshResponse.REFRESH_RESULT_RESET:
+                if (DBG) log("handleSimRefresh with SIM_REFRESH_RESET");
                 phone.mCM.setRadioPower(false, null);
                 /* Note: no need to call setRadioPower(true).  Assuming the desired
                 * radio power state is still ON (as tracked by ServiceStateTracker),
@@ -1162,7 +1167,7 @@
                 break;
             default:
                 // unknown refresh operation
-		if (DBG) log("handleSimRefresh with unknown operation");
+                if (DBG) log("handleSimRefresh with unknown operation");
                 break;
         }
     }
@@ -1304,7 +1309,7 @@
 
         logv("fetchSimRecords " + recordsToLoad);
 
-        phone.mCM.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE));
+        phone.mCM.getIMSIForApp(phone.getIccCard().getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
         recordsToLoad++;
 
         iccFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
index e34e10a..0e68e07 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimCard.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
@@ -39,4 +39,11 @@
         return mPhone.mIccRecords.getServiceProviderName();
     }
 
+    @Override
+    protected int getCurrentApplicationIndex() {
+        if (mIccCardStatus == null) {
+            return -1;
+        }
+        return mIccCardStatus.getGsmUmtsSubscriptionAppIndex();
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
index 9201984..99f4e0f 100644
--- a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
@@ -84,6 +84,9 @@
     public void getIMSI(Message result) {
     }
 
+    public void getIMSIForApp(String aid, Message result) {
+    }
+
     public void getIMEI(Message result) {
     }
 
@@ -213,6 +216,9 @@
     public void iccIO (int command, int fileid, String path, int p1, int p2,
             int p3, String data, String pin2, Message result) {
     }
+    public void iccIOForApp (int command, int fileid, String path, int p1, int p2,
+            int p3, String data, String pin2, String aid, Message result) {
+    }
 
     public void getCLIR(Message result) {
     }
diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
index 60d9d24..4f61509 100644
--- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -504,6 +504,9 @@
         resultSuccess(result, null);
     }
 
+    public void getIMSI(Message result) {
+        getIMSIForApp(null, result);
+    }
     /**
      *  returned message
      *  retMsg.obj = AsyncResult ar
@@ -511,7 +514,7 @@
      *  ar.userObject contains the original value of result.obj
      *  ar.result is String containing IMSI on success
      */
-    public void getIMSI(Message result) {
+    public void getIMSIForApp(String aid, Message result) {
         resultSuccess(result, "012345678901234");
     }
 
@@ -1042,13 +1045,18 @@
         unimplemented(result);
     }
 
+    public void iccIO(int command, int fileid, String path, int p1, int p2, int p3, String data,
+            String pin2, Message response) {
+        iccIOForApp(command, fileid, path, p1, p2, p3, data,pin2, null, response);
+    }
+
     /**
      * parameters equivalent to 27.007 AT+CRSM command
      * response.obj will be an AsyncResult
      * response.obj.userObj will be a SimIoResult on success
      */
-    public void iccIO (int command, int fileid, String path, int p1, int p2,
-                       int p3, String data, String pin2, Message result) {
+    public void iccIOForApp (int command, int fileid, String path, int p1, int p2,
+                       int p3, String data, String pin2, String aid, Message result) {
         unimplemented(result);
     }
 
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
index a385f55..5b76272 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -511,8 +511,9 @@
     @SmallTest
     public void testFormatNumber() {
         assertEquals("(650) 291-0000", PhoneNumberUtils.formatNumber("650 2910000", "US"));
-        assertEquals("123-4567", PhoneNumberUtils.formatNumber("1234567", "US"));
-        assertEquals("(800) 466-4114", PhoneNumberUtils.formatNumber("800-GOOG-114", "US"));
+        assertEquals("223-4567", PhoneNumberUtils.formatNumber("2234567", "US"));
+        // formatNumber doesn't format alpha numbers, but keep them as they are.
+        assertEquals("800-GOOG-114", PhoneNumberUtils.formatNumber("800-GOOG-114", "US"));
     }
 
     @SmallTest
@@ -592,9 +593,12 @@
         // addressing that, they are also classified as "potential" emergency numbers in the US.
         assertTrue(PhoneNumberUtils.isPotentialEmergencyNumber("91112345", "US"));
         assertTrue(PhoneNumberUtils.isPotentialEmergencyNumber("11212345", "US"));
+
         // A valid mobile phone number from Singapore shouldn't be classified as an emergency number
         // in Singapore, as 911 is not an emergency number there.
-        assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("91121234", "SG"));
+        // This test fails on devices that have ecclist property preloaded with 911.
+        // assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("91121234", "SG"));
+
         // A valid fixed-line phone number from Brazil shouldn't be classified as an emergency number
         // in Brazil, as 112 is not an emergency number there.
         assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("1121234567", "BR"));
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java
index d2e573c..6f0175e 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java
@@ -64,7 +64,7 @@
         assertEquals(result1, number.toString());
         assertEquals(result1.length(), Selection.getSelectionEnd(number));
         // Remove last 5 chars
-        final String result2 = "(650) 123";
+        final String result2 = "650-123";
         textWatcher.beforeTextChanged(number, number.length() - 4, 4, 0);
         number.delete(number.length() - 5, number.length());
         Selection.setSelection(number, number.length());
@@ -75,26 +75,26 @@
     }
 
     public void testInsertChars() {
-        final String init = "(650) 23";
-        final String expected1 = "(650) 123";
+        final String init = "650-23";
+        final String expected1 = "650-123";
         TextWatcher textWatcher = getTextWatcher();
 
         // Insert one char
         SpannableStringBuilder number = new SpannableStringBuilder(init);
-        textWatcher.beforeTextChanged(number, 4, 0, 1);
-        number.insert(4, "1"); // (6501) 23
-        Selection.setSelection(number, 5); // make the cursor at right of 1
-        textWatcher.onTextChanged(number, 4, 0, 1);
+        textWatcher.beforeTextChanged(number, 3, 0, 1);
+        number.insert(3, "1"); // 6501-23
+        Selection.setSelection(number, 4); // make the cursor at right of 1
+        textWatcher.onTextChanged(number, 3, 0, 1);
         textWatcher.afterTextChanged(number);
         assertEquals(expected1, number.toString());
         // the cursor should still at the right of '1'
-        assertEquals(7, Selection.getSelectionEnd(number));
+        assertEquals(5, Selection.getSelectionEnd(number));
 
         // Insert multiple chars
         final String expected2 = "(650) 145-6723";
-        textWatcher.beforeTextChanged(number, 7, 0, 4);
-        number.insert(7, "4567"); // change to (650) 1456723
-        Selection.setSelection(number, 11); // the cursor is at the right of '7'.
+        textWatcher.beforeTextChanged(number, 5, 0, 4);
+        number.insert(5, "4567"); // change to 650-1456723
+        Selection.setSelection(number, 9); // the cursor is at the right of '7'.
         textWatcher.onTextChanged(number, 7, 0, 4);
         textWatcher.afterTextChanged(number);
         assertEquals(expected2, number.toString());
@@ -168,7 +168,7 @@
         textWatcher.onTextChanged(number, 0, len, 0);
         textWatcher.afterTextChanged(number);
 
-        final String expected2 = "(650) 123-4";
+        final String expected2 = "650-1234";
         number = new SpannableStringBuilder(init);
         textWatcher.beforeTextChanged(number, 9, 0, 1);
         number.insert(9, "4"); // (650) 1234
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java
index b385cee..ea6836d 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java
@@ -612,4 +612,13 @@
     @Override
     public void getVoiceRadioTechnology(Message response) {
     }
+
+    @Override
+    public void getIMSIForApp(String aid, Message result) {
+    }
+
+    @Override
+    public void iccIOForApp(int command, int fileid, String path, int p1, int p2, int p3,
+            String data, String pin2, String aid, Message response) {
+    }
 }
diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-runner/src/android/test/mock/MockContentProvider.java
index 4ff943e..a8c388e 100644
--- a/test-runner/src/android/test/mock/MockContentProvider.java
+++ b/test-runner/src/android/test/mock/MockContentProvider.java
@@ -21,7 +21,7 @@
 import android.content.ContentProviderResult;
 import android.content.ContentValues;
 import android.content.Context;
-import android.content.ICancelationSignal;
+import android.content.ICancellationSignal;
 import android.content.IContentProvider;
 import android.content.OperationApplicationException;
 import android.content.pm.PathPermission;
@@ -93,7 +93,7 @@
 
         @Override
         public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
-                String sortOrder, ICancelationSignal cancelationSignal) throws RemoteException {
+                String sortOrder, ICancellationSignal cancellationSignal) throws RemoteException {
             return MockContentProvider.this.query(url, projection, selection,
                     selectionArgs, sortOrder);
         }
@@ -127,7 +127,7 @@
         }
 
         @Override
-        public ICancelationSignal createCancelationSignal() throws RemoteException {
+        public ICancellationSignal createCancellationSignal() throws RemoteException {
             return null;
         }
     }
diff --git a/test-runner/src/android/test/mock/MockIContentProvider.java b/test-runner/src/android/test/mock/MockIContentProvider.java
index 41bc27d..1aa0448 100644
--- a/test-runner/src/android/test/mock/MockIContentProvider.java
+++ b/test-runner/src/android/test/mock/MockIContentProvider.java
@@ -21,7 +21,7 @@
 import android.content.ContentValues;
 import android.content.EntityIterator;
 import android.content.IContentProvider;
-import android.content.ICancelationSignal;
+import android.content.ICancellationSignal;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.net.Uri;
@@ -73,7 +73,7 @@
     }
 
     public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
-            String sortOrder, ICancelationSignal cancelationSignal) {
+            String sortOrder, ICancellationSignal cancellationSignal) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
@@ -106,7 +106,7 @@
     }
 
     @Override
-    public ICancelationSignal createCancelationSignal() throws RemoteException {
+    public ICancellationSignal createCancellationSignal() throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 }
diff --git a/tests/BiDiTests/res/layout/basic.xml b/tests/BiDiTests/res/layout/basic.xml
index f503658..7d4d4db 100644
--- a/tests/BiDiTests/res/layout/basic.xml
+++ b/tests/BiDiTests/res/layout/basic.xml
@@ -19,6 +19,10 @@
         android:layout_width="fill_parent"
         android:layout_height="fill_parent">
 
+    <ScrollView
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent">
+
     <LinearLayout android:orientation="vertical"
                   android:layout_width="match_parent"
                   android:layout_height="match_parent">
@@ -131,4 +135,6 @@
 
     </LinearLayout>
 
+    </ScrollView>
+
 </FrameLayout>
diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml
index 1d4fc84..233cd0d 100644
--- a/tests/BiDiTests/res/values/strings.xml
+++ b/tests/BiDiTests/res/values/strings.xml
@@ -24,11 +24,11 @@
     <string name="button_before_text">Start</string>
     <string name="button_requestlayout_text">Request Layout</string>
     <string name="button_alert_dialog_text">AlertDialog</string>
-    <string name="textview_text">This is a text for a TextView</string>
-    <string name="textview_ltr_text">This is a text for a LTR TextView</string>
-    <string name="textview_rtl_text">This is a text for a RTL TextView</string>
-    <string name="textview_default_text">This is a text for a default TextView</string>
-    <string name="textview_password_default_text">This is a text for a password TextView</string>
+    <string name="textview_text">TextView</string>
+    <string name="textview_ltr_text">LTR TextView</string>
+    <string name="textview_rtl_text">RTL TextView</string>
+    <string name="textview_default_text">Default TextView</string>
+    <string name="textview_password_default_text">Password TextView</string>
     <string name="edittext_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
     <string name="normal_text">Normal String</string>
     <string name="normal_long_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 5bbcce3..643cb8d 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -30,6 +30,8 @@
         android:label="HwUi"
         android:hardwareAccelerated="true">
 
+        <meta-data android:name="android.graphics.renderThread" android:value="true" />
+
         <activity
                 android:name="PaintDrawFilterActivity"
                 android:label="_DrawFilter">
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java
index f96e68b..912d863 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java
@@ -84,7 +84,7 @@
                 Log.v(TAG, "RenderScript framew time core: " + t + " ms");
             }
             long avgValue = sum/ITERATION;
-            rsWriter.write("Averge frame time: " + avgValue + " ms\n");
+            rsWriter.write("Average frame time: " + avgValue + " ms\n");
             Log.v(TAG, "Average frame time: " + avgValue + " ms");
             rsWriter.close();
         } catch (IOException e) {
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
index 5ab2c58..2293678 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
@@ -65,6 +65,7 @@
         unitTests = new ArrayList<UnitTest>();
 
         unitTests.add(new UT_primitives(this, mRes, mCtx));
+        unitTests.add(new UT_constant(this, mRes, mCtx));
         unitTests.add(new UT_vector(this, mRes, mCtx));
         unitTests.add(new UT_rsdebug(this, mRes, mCtx));
         unitTests.add(new UT_rstime(this, mRes, mCtx));
@@ -73,6 +74,7 @@
         unitTests.add(new UT_refcount(this, mRes, mCtx));
         unitTests.add(new UT_foreach(this, mRes, mCtx));
         unitTests.add(new UT_atomic(this, mRes, mCtx));
+        unitTests.add(new UT_struct(this, mRes, mCtx));
         unitTests.add(new UT_math(this, mRes, mCtx));
         unitTests.add(new UT_fp_mad(this, mRes, mCtx));
         /*
@@ -92,7 +94,7 @@
         for (int i = 0; i < uta.length; i++) {
             ScriptField_ListAllocs_s.Item listElem = new ScriptField_ListAllocs_s.Item();
             listElem.text = Allocation.createFromString(mRS, uta[i].name, Allocation.USAGE_SCRIPT);
-            listElem.result = uta[i].result;
+            listElem.result = uta[i].getResult();
             mListAllocs.set(listElem, i, false);
             uta[i].setItem(listElem);
         }
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_constant.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_constant.java
new file mode 100644
index 0000000..adda5a3
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_constant.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 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_constant extends UnitTest {
+    private Resources mRes;
+
+    protected UT_constant(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Const", ctx);
+        mRes = res;
+    }
+
+    private void Assert(boolean b) {
+        if (!b) {
+            failTest();
+        }
+    }
+
+    public void run() {
+        Assert(ScriptC_constant.const_floatTest == 1.99f);
+        Assert(ScriptC_constant.const_doubleTest == 2.05);
+        Assert(ScriptC_constant.const_charTest == -8);
+        Assert(ScriptC_constant.const_shortTest == -16);
+        Assert(ScriptC_constant.const_intTest == -32);
+        Assert(ScriptC_constant.const_longTest == 17179869184l);
+        Assert(ScriptC_constant.const_longlongTest == 68719476736l);
+
+        Assert(ScriptC_constant.const_ucharTest == 8);
+        Assert(ScriptC_constant.const_ushortTest == 16);
+        Assert(ScriptC_constant.const_uintTest == 32);
+        Assert(ScriptC_constant.const_ulongTest == 4611686018427387904L);
+        Assert(ScriptC_constant.const_int64_tTest == -17179869184l);
+        Assert(ScriptC_constant.const_uint64_tTest == 117179869184l);
+
+        Assert(ScriptC_constant.const_boolTest == true);
+
+        passTest();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java
index b7a65a5..18829c2 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java
@@ -92,8 +92,7 @@
         ScriptC_primitives s = new ScriptC_primitives(pRS, mRes, R.raw.primitives);
         pRS.setMessageHandler(mRsMessage);
         if (!initializeGlobals(s)) {
-            // initializeGlobals failed
-            result = -1;
+            failTest();
         } else {
             s.invoke_primitives_test(0, 0);
             pRS.finish();
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_struct.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_struct.java
new file mode 100644
index 0000000..2a55686
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_struct.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 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_struct extends UnitTest {
+    private Resources mRes;
+
+    protected UT_struct(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Struct", ctx);
+        mRes = res;
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        ScriptC_struct s = new ScriptC_struct(pRS, mRes, R.raw.struct);
+        pRS.setMessageHandler(mRsMessage);
+
+        ScriptField_Point2 p = new ScriptField_Point2(pRS, 1);
+        ScriptField_Point2.Item i = new ScriptField_Point2.Item();
+        int val = 100;
+        i.x = val;
+        i.y = val;
+        p.set(i, 0, true);
+        s.bind_point2(p);
+        s.invoke_struct_test(val);
+        pRS.finish();
+        waitForMessage();
+
+        val = 200;
+        p.set_x(0, val, true);
+        p.set_y(0, val, true);
+        s.invoke_struct_test(val);
+        pRS.finish();
+        waitForMessage();
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java
index 748701d..0ac09ca 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java
@@ -307,7 +307,7 @@
         ScriptC_vector s = new ScriptC_vector(pRS, mRes, R.raw.vector);
         pRS.setMessageHandler(mRsMessage);
         if (!initializeGlobals(s)) {
-            result = -1;
+            failTest();
         } else {
             s.invoke_vector_test();
             pRS.finish();
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
index a97ffa7..edff83f 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
@@ -21,7 +21,7 @@
 
 public class UnitTest extends Thread {
     public String name;
-    public int result;
+    private int result;
     private ScriptField_ListAllocs_s.Item mItem;
     private RSTestCore mRSTC;
     private boolean msgHandled;
@@ -63,7 +63,7 @@
         }
     }
 
-    protected void updateUI() {
+    private void updateUI() {
         if (mItem != null) {
             mItem.result = result;
             msgHandled = true;
@@ -104,6 +104,22 @@
         }
     }
 
+    public int getResult() {
+        return result;
+    }
+
+    public void failTest() {
+        result = -1;
+        updateUI();
+    }
+
+    public void passTest() {
+        if (result != -1) {
+            result = 1;
+        }
+        updateUI();
+    }
+
     public void setItem(ScriptField_ListAllocs_s.Item item) {
         mItem = item;
     }
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/constant.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/constant.rs
new file mode 100644
index 0000000..732eaef
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/constant.rs
@@ -0,0 +1,19 @@
+#include "shared.rsh"
+
+const float floatTest = 1.99f;
+const double doubleTest = 2.05;
+const char charTest = -8;
+const short shortTest = -16;
+const int intTest = -32;
+const long longTest = 17179869184l; // 1 << 34
+const long long longlongTest = 68719476736l; // 1 << 36
+
+const uchar ucharTest = 8;
+const ushort ushortTest = 16;
+const uint uintTest = 32;
+const ulong ulongTest = 4611686018427387904L;
+const int64_t int64_tTest = -17179869184l; // - 1 << 34
+const uint64_t uint64_tTest = 117179869184l;
+
+const bool boolTest = true;
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/struct.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/struct.rs
new file mode 100644
index 0000000..1cd728e
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/struct.rs
@@ -0,0 +1,37 @@
+#include "shared.rsh"
+
+typedef struct Point2 {
+   int x;
+   int y;
+} Point_2;
+Point_2 *point2;
+
+static bool test_Point_2(int expected) {
+    bool failed = false;
+
+    rsDebug("Point: ", point2[0].x, point2[0].y);
+    _RS_ASSERT(point2[0].x == expected);
+    _RS_ASSERT(point2[0].y == expected);
+
+    if (failed) {
+        rsDebug("test_Point_2 FAILED", 0);
+    }
+    else {
+        rsDebug("test_Point_2 PASSED", 0);
+    }
+
+    return failed;
+}
+
+void struct_test(int expected) {
+    bool failed = false;
+    failed |= test_Point_2(expected);
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index d5345b2..c5a397c 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -53,17 +53,6 @@
     AXIS_END = AXIS_VERSION,
 };
 
-enum {
-    SDK_CUPCAKE = 3,
-    SDK_DONUT = 4,
-    SDK_ECLAIR = 5,
-    SDK_ECLAIR_0_1 = 6,
-    SDK_MR1 = 7,
-    SDK_FROYO = 8,
-    SDK_HONEYCOMB_MR2 = 13,
-    SDK_ICE_CREAM_SANDWICH = 14,
-};
-
 /**
  * This structure contains a specific variation of a single file out
  * of all the variations it can have that we can have.
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 2d1060b..8e3a1c9 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -14,6 +14,18 @@
 #include <utils/String8.h>
 #include <utils/Vector.h>
 
+enum {
+    SDK_CUPCAKE = 3,
+    SDK_DONUT = 4,
+    SDK_ECLAIR = 5,
+    SDK_ECLAIR_0_1 = 6,
+    SDK_MR1 = 7,
+    SDK_FROYO = 8,
+    SDK_HONEYCOMB_MR2 = 13,
+    SDK_ICE_CREAM_SANDWICH = 14,
+    SDK_ICE_CREAM_SANDWICH_MR1 = 15,
+};
+
 /*
  * Things we can do.
  */
@@ -82,7 +94,6 @@
     void setRequireLocalization(bool val) { mRequireLocalization = val; }
     bool getPseudolocalize(void) const { return mPseudolocalize; }
     void setPseudolocalize(bool val) { mPseudolocalize = val; }
-    bool getWantUTF16(void) const { return mWantUTF16; }
     void setWantUTF16(bool val) { mWantUTF16 = val; }
     bool getValues(void) const { return mValues; }
     void setValues(bool val) { mValues = val; }
@@ -103,6 +114,10 @@
     bool getGenDependencies() { return mGenDependencies; }
     void setGenDependencies(bool val) { mGenDependencies = val; }
 
+    bool getUTF16StringsOption() {
+        return mWantUTF16 || !isMinSdkAtLeast(SDK_FROYO);
+    }
+
     /*
      * Input options.
      */
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 89942de..607056a 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -479,6 +479,11 @@
 #ifndef HAVE_ANDROID_OS
         res.print(bundle->getValues());
 #endif
+
+    } else if (strcmp("strings", option) == 0) {
+        const ResStringPool* pool = res.getTableStringBlock(0);
+        printStringPool(pool);
+
     } else if (strcmp("xmltree", option) == 0) {
         if (bundle->getFileSpecCount() < 3) {
             fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
@@ -1382,7 +1387,7 @@
                 delete dir;
             }
         } else if (strcmp("badger", option) == 0) {
-            printf(CONSOLE_DATA);
+            printf("%s", CONSOLE_DATA);
         } else if (strcmp("configurations", option) == 0) {
             Vector<ResTable_config> configs;
             res.getConfigurations(&configs);
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 1ecf7da..c0fe538 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -847,8 +847,7 @@
      * request UTF-16 encoding and the parameters of this package
      * allow UTF-8 to be used.
      */
-    if (!bundle->getWantUTF16()
-            && bundle->isMinSdkAtLeast(SDK_FROYO)) {
+    if (!bundle->getUTF16StringsOption()) {
         xmlFlags |= XML_COMPILE_UTF8;
     }
 
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index fdb39ca..f59bba2 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2047,7 +2047,8 @@
                                   uint32_t attrID,
                                   const Vector<StringPool::entry_style_span>* style,
                                   String16* outStr, void* accessorCookie,
-                                  uint32_t attrType)
+                                  uint32_t attrType, const String8* configTypeName,
+                                  const ConfigDescription* config)
 {
     String16 finalStr;
 
@@ -2075,10 +2076,19 @@
     if (outValue->dataType == outValue->TYPE_STRING) {
         // Should do better merging styles.
         if (pool) {
-            if (style != NULL && style->size() > 0) {
-                outValue->data = pool->add(finalStr, *style);
+            String8 configStr;
+            if (config != NULL) {
+                configStr = config->toString();
             } else {
-                outValue->data = pool->add(finalStr, true);
+                configStr = "(null)";
+            }
+            NOISY(printf("Adding to pool string style #%d config %s: %s\n",
+                    style != NULL ? style->size() : 0,
+                    configStr.string(), String8(finalStr).string()));
+            if (style != NULL && style->size() > 0) {
+                outValue->data = pool->add(finalStr, *style, configTypeName, config);
+            } else {
+                outValue->data = pool->add(finalStr, true, configTypeName, config);
             }
         } else {
             // Caller will fill this in later.
@@ -2537,16 +2547,19 @@
         return err;
     }
 
+    const ConfigDescription nullConfig;
+
     const size_t N = mOrderedPackages.size();
     size_t pi;
 
     const static String16 mipmap16("mipmap");
 
-    bool useUTF8 = !bundle->getWantUTF16() && bundle->isMinSdkAtLeast(SDK_FROYO);
+    bool useUTF8 = !bundle->getUTF16StringsOption();
 
     // Iterate through all data, collecting all values (strings,
     // references, etc).
     StringPool valueStrings = StringPool(false, useUTF8);
+    Vector<sp<Entry> > allEntries;
     for (pi=0; pi<N; pi++) {
         sp<Package> p = mOrderedPackages.itemAt(pi);
         if (p->getTypes().size() == 0) {
@@ -2567,6 +2580,19 @@
             const String16 typeName(t->getName());
             typeStrings.add(typeName, false);
 
+            // This is a hack to tweak the sorting order of the final strings,
+            // to put stuff that is generally not language-specific first.
+            String8 configTypeName(typeName);
+            if (configTypeName == "drawable" || configTypeName == "layout"
+                    || configTypeName == "color" || configTypeName == "anim"
+                    || configTypeName == "interpolator" || configTypeName == "animator"
+                    || configTypeName == "xml" || configTypeName == "menu"
+                    || configTypeName == "mipmap" || configTypeName == "raw") {
+                configTypeName = "1complex";
+            } else {
+                configTypeName = "2value";
+            }
+
             const bool filterable = (typeName != mipmap16);
 
             const size_t N = t->getOrderedConfigs().size();
@@ -2586,10 +2612,21 @@
                         continue;
                     }
                     e->setNameIndex(keyStrings.add(e->getName(), true));
-                    status_t err = e->prepareFlatten(&valueStrings, this);
+
+                    // If this entry has no values for other configs,
+                    // and is the default config, then it is special.  Otherwise
+                    // we want to add it with the config info.
+                    ConfigDescription* valueConfig = NULL;
+                    if (N != 1 || config == nullConfig) {
+                        valueConfig = &config;
+                    }
+
+                    status_t err = e->prepareFlatten(&valueStrings, this,
+                            &configTypeName, &config);
                     if (err != NO_ERROR) {
                         return err;
                     }
+                    allEntries.add(e);
                 }
             }
         }
@@ -2598,6 +2635,17 @@
         p->setKeyStrings(keyStrings.createStringBlock());
     }
 
+    if (bundle->getOutputAPKFile() != NULL) {
+        // Now we want to sort the value strings for better locality.  This will
+        // cause the positions of the strings to change, so we need to go back
+        // through out resource entries and update them accordingly.  Only need
+        // to do this if actually writing the output file.
+        valueStrings.sortByConfig();
+        for (pi=0; pi<allEntries.size(); pi++) {
+            allEntries[pi]->remapStringValue(&valueStrings);
+        }
+    }
+
     ssize_t strAmt = 0;
     
     // Now build the array of package chunks.
@@ -3137,14 +3185,16 @@
     return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
 }
 
-status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable* table)
+status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable* table,
+        const String8* configTypeName, const ConfigDescription* config)
 {
     if (mType == TYPE_ITEM) {
         Item& it = mItem;
         AccessorCookie ac(it.sourcePos, String8(mName), String8(it.value));
         if (!table->stringToValue(&it.parsedValue, strings,
                                   it.value, false, true, 0,
-                                  &it.style, NULL, &ac, mItemFormat)) {
+                                  &it.style, NULL, &ac, mItemFormat,
+                                  configTypeName, config)) {
             return UNKNOWN_ERROR;
         }
     } else if (mType == TYPE_BAG) {
@@ -3155,7 +3205,8 @@
             AccessorCookie ac(it.sourcePos, String8(key), String8(it.value));
             if (!table->stringToValue(&it.parsedValue, strings,
                                       it.value, false, true, it.bagKeyId,
-                                      &it.style, NULL, &ac, it.format)) {
+                                      &it.style, NULL, &ac, it.format,
+                                      configTypeName, config)) {
                 return UNKNOWN_ERROR;
             }
         }
@@ -3167,6 +3218,29 @@
     return NO_ERROR;
 }
 
+status_t ResourceTable::Entry::remapStringValue(StringPool* strings)
+{
+    if (mType == TYPE_ITEM) {
+        Item& it = mItem;
+        if (it.parsedValue.dataType == Res_value::TYPE_STRING) {
+            it.parsedValue.data = strings->mapOriginalPosToNewPos(it.parsedValue.data);
+        }
+    } else if (mType == TYPE_BAG) {
+        const size_t N = mBag.size();
+        for (size_t i=0; i<N; i++) {
+            Item& it = mBag.editValueAt(i);
+            if (it.parsedValue.dataType == Res_value::TYPE_STRING) {
+                it.parsedValue.data = strings->mapOriginalPosToNewPos(it.parsedValue.data);
+            }
+        }
+    } else {
+        mPos.error("Error: entry %s is not a single item or a bag.\n",
+                   String8(mName).string());
+        return UNKNOWN_ERROR;
+    }
+    return NO_ERROR;
+}
+
 ssize_t ResourceTable::Entry::flatten(Bundle* bundle, const sp<AaptFile>& data, bool isPublic)
 {
     size_t amt = 0;
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index 8123bb3..a3e0666 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -76,6 +76,37 @@
     class Type;
     class Entry;
 
+    struct ConfigDescription : public ResTable_config {
+        ConfigDescription() {
+            memset(this, 0, sizeof(*this));
+            size = sizeof(ResTable_config);
+        }
+        ConfigDescription(const ResTable_config&o) {
+            *static_cast<ResTable_config*>(this) = o;
+            size = sizeof(ResTable_config);
+        }
+        ConfigDescription(const ConfigDescription&o) {
+            *static_cast<ResTable_config*>(this) = o;
+        }
+
+        ConfigDescription& operator=(const ResTable_config& o) {
+            *static_cast<ResTable_config*>(this) = o;
+            size = sizeof(ResTable_config);
+            return *this;
+        }
+        ConfigDescription& operator=(const ConfigDescription& o) {
+            *static_cast<ResTable_config*>(this) = o;
+            return *this;
+        }
+
+        inline bool operator<(const ConfigDescription& o) const { return compare(o) < 0; }
+        inline bool operator<=(const ConfigDescription& o) const { return compare(o) <= 0; }
+        inline bool operator==(const ConfigDescription& o) const { return compare(o) == 0; }
+        inline bool operator!=(const ConfigDescription& o) const { return compare(o) != 0; }
+        inline bool operator>=(const ConfigDescription& o) const { return compare(o) >= 0; }
+        inline bool operator>(const ConfigDescription& o) const { return compare(o) > 0; }
+    };
+
     ResourceTable(Bundle* bundle, const String16& assetsPackage);
 
     status_t addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets);
@@ -183,7 +214,9 @@
                        uint32_t attrID,
                        const Vector<StringPool::entry_style_span>* style = NULL,
                        String16* outStr = NULL, void* accessorCookie = NULL,
-                       uint32_t attrType = ResTable_map::TYPE_ANY);
+                       uint32_t attrType = ResTable_map::TYPE_ANY,
+                       const String8* configTypeName = NULL,
+                       const ConfigDescription* config = NULL);
 
     status_t assignResourceIds();
     status_t addSymbols(const sp<AaptSymbols>& outSymbols = NULL);
@@ -305,7 +338,10 @@
         status_t assignResourceIds(ResourceTable* table,
                                    const String16& package);
 
-        status_t prepareFlatten(StringPool* strings, ResourceTable* table);
+        status_t prepareFlatten(StringPool* strings, ResourceTable* table,
+               const String8* configTypeName, const ConfigDescription* config);
+
+        status_t remapStringValue(StringPool* strings);
 
         ssize_t flatten(Bundle*, const sp<AaptFile>& data, bool isPublic);
 
@@ -322,37 +358,6 @@
         uint32_t mParentId;
         SourcePos mPos;
     };
-
-    struct ConfigDescription : public ResTable_config {
-        ConfigDescription() {
-            memset(this, 0, sizeof(*this));
-            size = sizeof(ResTable_config);
-        }
-        ConfigDescription(const ResTable_config&o) {
-            *static_cast<ResTable_config*>(this) = o;
-            size = sizeof(ResTable_config);
-        }
-        ConfigDescription(const ConfigDescription&o) {
-            *static_cast<ResTable_config*>(this) = o;
-        }
-        
-        ConfigDescription& operator=(const ResTable_config& o) {
-            *static_cast<ResTable_config*>(this) = o;
-            size = sizeof(ResTable_config);
-            return *this;
-        }
-        ConfigDescription& operator=(const ConfigDescription& o) {
-            *static_cast<ResTable_config*>(this) = o;
-            return *this;
-        }
-        
-        inline bool operator<(const ConfigDescription& o) const { return compare(o) < 0; }
-        inline bool operator<=(const ConfigDescription& o) const { return compare(o) <= 0; }
-        inline bool operator==(const ConfigDescription& o) const { return compare(o) == 0; }
-        inline bool operator!=(const ConfigDescription& o) const { return compare(o) != 0; }
-        inline bool operator>=(const ConfigDescription& o) const { return compare(o) >= 0; }
-        inline bool operator>(const ConfigDescription& o) const { return compare(o) > 0; }
-    };
     
     class ConfigList : public RefBase {
     public:
diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp
index 9a0a1c4..fe88e37 100644
--- a/tools/aapt/StringPool.cpp
+++ b/tools/aapt/StringPool.cpp
@@ -5,8 +5,10 @@
 //
 
 #include "StringPool.h"
+#include "ResourceTable.h"
 
 #include <utils/ByteOrder.h>
+#include <utils/SortedVector.h>
 
 #if HAVE_PRINTF_ZD
 #  define ZD "%zd"
@@ -30,31 +32,87 @@
 
 void printStringPool(const ResStringPool* pool)
 {
+    SortedVector<const void*> uniqueStrings;
+    const size_t N = pool->size();
+    for (size_t i=0; i<N; i++) {
+        size_t len;
+        if (pool->isUTF8()) {
+            uniqueStrings.add(pool->string8At(i, &len));
+        } else {
+            uniqueStrings.add(pool->stringAt(i, &len));
+        }
+    }
+
+    printf("String pool of " ZD " unique %s %s strings, " ZD " entries and "
+            ZD " styles using " ZD " bytes:\n",
+            (ZD_TYPE)uniqueStrings.size(), pool->isUTF8() ? "UTF-8" : "UTF-16",
+            pool->isSorted() ? "sorted" : "non-sorted",
+            (ZD_TYPE)N, (ZD_TYPE)pool->styleCount(), (ZD_TYPE)pool->bytes());
+
     const size_t NS = pool->size();
     for (size_t s=0; s<NS; s++) {
-        size_t len;
-        const char *str = (const char*)pool->string8At(s, &len);
-        if (str == NULL) {
-            str = String8(pool->stringAt(s, &len)).string();
-        }
-
-        printf("String #" ZD ": %s\n", (ZD_TYPE) s, str);
+        String8 str = pool->string8ObjectAt(s);
+        printf("String #" ZD ": %s\n", (ZD_TYPE) s, str.string());
     }
 }
 
+String8 StringPool::entry::makeConfigsString() const {
+    String8 configStr(configTypeName);
+    if (configStr.size() > 0) configStr.append(" ");
+    if (configs.size() > 0) {
+        for (size_t j=0; j<configs.size(); j++) {
+            if (j > 0) configStr.append(", ");
+            configStr.append(configs[j].toString());
+        }
+    } else {
+        configStr = "(none)";
+    }
+    return configStr;
+}
+
+int StringPool::entry::compare(const entry& o) const {
+    // Strings with styles go first, to reduce the size of the
+    // styles array.
+    if (hasStyles) {
+        return o.hasStyles ? 0 : -1;
+    }
+    if (o.hasStyles) {
+        return 1;
+    }
+    int comp = configTypeName.compare(o.configTypeName);
+    if (comp != 0) {
+        return comp;
+    }
+    const size_t LHN = configs.size();
+    const size_t RHN = o.configs.size();
+    size_t i=0;
+    while (i < LHN && i < RHN) {
+        comp = configs[i].compareLogical(o.configs[i]);
+        if (comp != 0) {
+            return comp;
+        }
+        i++;
+    }
+    if (LHN < RHN) return -1;
+    else if (LHN > RHN) return 1;
+    return 0;
+}
+
 StringPool::StringPool(bool sorted, bool utf8)
     : mSorted(sorted), mUTF8(utf8), mValues(-1), mIdents(-1)
 {
 }
 
-ssize_t StringPool::add(const String16& value, bool mergeDuplicates)
+ssize_t StringPool::add(const String16& value, bool mergeDuplicates,
+        const String8* configTypeName, const ResTable_config* config)
 {
-    return add(String16(), value, mergeDuplicates);
+    return add(String16(), value, mergeDuplicates, configTypeName, config);
 }
 
-ssize_t StringPool::add(const String16& value, const Vector<entry_style_span>& spans)
+ssize_t StringPool::add(const String16& value, const Vector<entry_style_span>& spans,
+        const String8* configTypeName, const ResTable_config* config)
 {
-    ssize_t res = add(String16(), value, false);
+    ssize_t res = add(String16(), value, false, configTypeName, config);
     if (res >= 0) {
         addStyleSpans(res, spans);
     }
@@ -62,7 +120,7 @@
 }
 
 ssize_t StringPool::add(const String16& ident, const String16& value,
-                        bool mergeDuplicates)
+        bool mergeDuplicates, const String8* configTypeName, const ResTable_config* config)
 {
     if (ident.size() > 0) {
         ssize_t idx = mIdents.valueFor(ident);
@@ -84,20 +142,43 @@
         }
     }
 
+    if (configTypeName != NULL) {
+        entry& ent = mEntries.editItemAt(eidx);
+        NOISY(printf("*** adding config type name %s, was %s\n",
+                configTypeName->string(), ent.configTypeName.string()));
+        if (ent.configTypeName.size() <= 0) {
+            ent.configTypeName = *configTypeName;
+        } else if (ent.configTypeName != *configTypeName) {
+            ent.configTypeName = " ";
+        }
+    }
+
+    if (config != NULL) {
+        // Add this to the set of configs associated with the string.
+        entry& ent = mEntries.editItemAt(eidx);
+        size_t addPos;
+        for (addPos=0; addPos<ent.configs.size(); addPos++) {
+            int cmp = ent.configs.itemAt(addPos).compareLogical(*config);
+            if (cmp >= 0) {
+                if (cmp > 0) {
+                    NOISY(printf("*** inserting config: %s\n", config->toString().string()));
+                    ent.configs.insertAt(*config, addPos);
+                }
+                break;
+            }
+        }
+        if (addPos >= ent.configs.size()) {
+            NOISY(printf("*** adding config: %s\n", config->toString().string()));
+            ent.configs.add(*config);
+        }
+    }
+
     const bool first = vidx < 0;
     if (first || !mergeDuplicates) {
         pos = mEntryArray.add(eidx);
         if (first) {
             vidx = mValues.add(value, pos);
-            const size_t N = mEntryArrayToValues.size();
-            for (size_t i=0; i<N; i++) {
-                size_t& e = mEntryArrayToValues.editItemAt(i);
-                if ((ssize_t)e >= vidx) {
-                    e++;
-                }
-            }
         }
-        mEntryArrayToValues.add(vidx);
         if (!mSorted) {
             entry& ent = mEntries.editItemAt(eidx);
             ent.indices.add(pos);
@@ -147,6 +228,7 @@
 
     entry_style& style = mEntryStyleArray.editItemAt(idx);
     style.spans.add(span);
+    mEntries.editItemAt(mEntryArray[idx]).hasStyles = true;
     return NO_ERROR;
 }
 
@@ -169,6 +251,132 @@
     return mIdents.size();
 }
 
+int StringPool::config_sort(const size_t* lhs, const size_t* rhs, void* state)
+{
+    StringPool* pool = (StringPool*)state;
+    const entry& lhe = pool->mEntries[pool->mEntryArray[*lhs]];
+    const entry& rhe = pool->mEntries[pool->mEntryArray[*rhs]];
+    return lhe.compare(rhe);
+}
+
+void StringPool::sortByConfig()
+{
+    LOG_ALWAYS_FATAL_IF(mSorted, "Can't sort string pool containing identifiers.");
+    LOG_ALWAYS_FATAL_IF(mIdents.size() > 0, "Can't sort string pool containing identifiers.");
+    LOG_ALWAYS_FATAL_IF(mOriginalPosToNewPos.size() > 0, "Can't sort string pool after already sorted.");
+
+    const size_t N = mEntryArray.size();
+
+    // This is a vector that starts out with a 1:1 mapping to entries
+    // in the array, which we will sort to come up with the desired order.
+    // At that point it maps from the new position in the array to the
+    // original position the entry appeared.
+    Vector<size_t> newPosToOriginalPos;
+    for (size_t i=0; i<mEntryArray.size(); i++) {
+        newPosToOriginalPos.add(i);
+    }
+
+    // Sort the array.
+    NOISY(printf("SORTING STRINGS BY CONFIGURATION...\n"));
+    newPosToOriginalPos.sort(config_sort, this);
+    NOISY(printf("DONE SORTING STRINGS BY CONFIGURATION.\n"));
+
+    // Create the reverse mapping from the original position in the array
+    // to the new position where it appears in the sorted array.  This is
+    // so that clients can re-map any positions they had previously stored.
+    mOriginalPosToNewPos = newPosToOriginalPos;
+    for (size_t i=0; i<N; i++) {
+        mOriginalPosToNewPos.editItemAt(newPosToOriginalPos[i]) = i;
+    }
+
+#if 0
+    SortedVector<entry> entries;
+
+    for (size_t i=0; i<N; i++) {
+        printf("#%d was %d: %s\n", i, newPosToOriginalPos[i],
+                mEntries[mEntryArray[newPosToOriginalPos[i]]].makeConfigsString().string());
+        entries.add(mEntries[mEntryArray[i]]);
+    }
+
+    for (size_t i=0; i<entries.size(); i++) {
+        printf("Sorted config #%d: %s\n", i,
+                entries[i].makeConfigsString().string());
+    }
+#endif
+
+    // Now we rebuild the arrays.
+    Vector<entry> newEntries;
+    Vector<size_t> newEntryArray;
+    Vector<entry_style> newEntryStyleArray;
+    DefaultKeyedVector<size_t, size_t> origOffsetToNewOffset;
+
+    for (size_t i=0; i<N; i++) {
+        // We are filling in new offset 'i'; oldI is where we can find it
+        // in the original data structure.
+        size_t oldI = newPosToOriginalPos[i];
+        // This is the actual entry associated with the old offset.
+        const entry& oldEnt = mEntries[mEntryArray[oldI]];
+        // This is the same entry the last time we added it to the
+        // new entry array, if any.
+        ssize_t newIndexOfOffset = origOffsetToNewOffset.indexOfKey(oldI);
+        size_t newOffset;
+        if (newIndexOfOffset < 0) {
+            // This is the first time we have seen the entry, so add
+            // it.
+            newOffset = newEntries.add(oldEnt);
+            newEntries.editItemAt(newOffset).indices.clear();
+        } else {
+            // We have seen this entry before, use the existing one
+            // instead of adding it again.
+            newOffset = origOffsetToNewOffset.valueAt(newIndexOfOffset);
+        }
+        // Update the indices to include this new position.
+        newEntries.editItemAt(newOffset).indices.add(i);
+        // And add the offset of the entry to the new entry array.
+        newEntryArray.add(newOffset);
+        // Add any old style to the new style array.
+        if (mEntryStyleArray.size() > 0) {
+            if (oldI < mEntryStyleArray.size()) {
+                newEntryStyleArray.add(mEntryStyleArray[oldI]);
+            } else {
+                newEntryStyleArray.add(entry_style());
+            }
+        }
+    }
+
+    // Now trim any entries at the end of the new style array that are
+    // not needed.
+    for (ssize_t i=newEntryStyleArray.size()-1; i>=0; i--) {
+        const entry_style& style = newEntryStyleArray[i];
+        if (style.spans.size() > 0) {
+            // That's it.
+            break;
+        }
+        // This one is not needed; remove.
+        newEntryStyleArray.removeAt(i);
+    }
+
+    // All done, install the new data structures and upate mValues with
+    // the new positions.
+    mEntries = newEntries;
+    mEntryArray = newEntryArray;
+    mEntryStyleArray = newEntryStyleArray;
+    mValues.clear();
+    for (size_t i=0; i<mEntries.size(); i++) {
+        const entry& ent = mEntries[i];
+        mValues.add(ent.value, ent.indices[0]);
+    }
+
+#if 0
+    printf("FINAL SORTED STRING CONFIGS:\n");
+    for (size_t i=0; i<mEntries.size(); i++) {
+        const entry& ent = mEntries[i];
+        printf("#" ZD " %s: %s\n", (ZD_TYPE)i, ent.makeConfigsString().string(),
+                String8(ent.value).string());
+    }
+#endif
+}
+
 sp<AaptFile> StringPool::createStringBlock()
 {
     sp<AaptFile> pool = new AaptFile(String8(), AaptGroupEntry(),
diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h
index 7275259..255bdbf 100644
--- a/tools/aapt/StringPool.h
+++ b/tools/aapt/StringPool.h
@@ -40,12 +40,28 @@
 public:
     struct entry {
         entry() : offset(0) { }
-        entry(const String16& _value) : value(_value), offset(0) { }
-        entry(const entry& o) : value(o.value), offset(o.offset), indices(o.indices) { }
+        entry(const String16& _value) : value(_value), offset(0), hasStyles(false) { }
+        entry(const entry& o) : value(o.value), offset(o.offset),
+                hasStyles(o.hasStyles), indices(o.indices),
+                configTypeName(o.configTypeName), configs(o.configs) { }
 
         String16 value;
         size_t offset;
+        bool hasStyles;
         Vector<size_t> indices;
+        String8 configTypeName;
+        Vector<ResTable_config> configs;
+
+        String8 makeConfigsString() const;
+
+        int compare(const entry& o) const;
+
+        inline bool operator<(const entry& o) const { return compare(o) < 0; }
+        inline bool operator<=(const entry& o) const { return compare(o) <= 0; }
+        inline bool operator==(const entry& o) const { return compare(o) == 0; }
+        inline bool operator!=(const entry& o) const { return compare(o) != 0; }
+        inline bool operator>=(const entry& o) const { return compare(o) >= 0; }
+        inline bool operator>(const entry& o) const { return compare(o) > 0; }
     };
 
     struct entry_style_span {
@@ -84,12 +100,15 @@
      * if this string pool is sorted, the returned index will not be valid
      * when the pool is finally written.
      */
-    ssize_t add(const String16& value, bool mergeDuplicates = false);
+    ssize_t add(const String16& value, bool mergeDuplicates = false,
+            const String8* configTypeName = NULL, const ResTable_config* config = NULL);
 
-    ssize_t add(const String16& value, const Vector<entry_style_span>& spans);
+    ssize_t add(const String16& value, const Vector<entry_style_span>& spans,
+            const String8* configTypeName = NULL, const ResTable_config* config = NULL);
 
     ssize_t add(const String16& ident, const String16& value,
-                bool mergeDuplicates = false);
+                bool mergeDuplicates = false,
+                const String8* configTypeName = NULL, const ResTable_config* config = NULL);
 
     status_t addStyleSpan(size_t idx, const String16& name,
                           uint32_t start, uint32_t end);
@@ -102,6 +121,18 @@
 
     size_t countIdentifiers() const;
 
+    // Sort the contents of the string block by the configuration associated
+    // with each item.  After doing this you can use mapOriginalPosToNewPos()
+    // to find out the new position given the position originall returned by
+    // add().
+    void sortByConfig();
+
+    // For use after sortByConfig() to map from the original position of
+    // a string to its new sorted position.
+    size_t mapOriginalPosToNewPos(size_t originalPos) const {
+        return mOriginalPosToNewPos.itemAt(originalPos);
+    }
+
     sp<AaptFile> createStringBlock();
 
     status_t writeStringBlock(const sp<AaptFile>& pool);
@@ -125,27 +156,41 @@
     const Vector<size_t>* offsetsForString(const String16& val) const;
 
 private:
+    static int config_sort(const size_t* lhs, const size_t* rhs, void* state);
+
     const bool                              mSorted;
     const bool                              mUTF8;
-    // Raw array of unique strings, in some arbitrary order.
+
+    // The following data structures represent the actual structures
+    // that will be generated for the final string pool.
+
+    // Raw array of unique strings, in some arbitrary order.  This is the
+    // actual strings that appear in the final string pool, in the order
+    // that they will be written.
     Vector<entry>                           mEntries;
     // Array of indices into mEntries, in the order they were
     // added to the pool.  This can be different than mEntries
     // if the same string was added multiple times (it will appear
     // once in mEntries, with multiple occurrences in this array).
+    // This is the lookup array that will be written for finding
+    // the string for each offset/position in the string pool.
     Vector<size_t>                          mEntryArray;
     // Optional style span information associated with each index of
     // mEntryArray.
     Vector<entry_style>                     mEntryStyleArray;
-    // Mapping from indices in mEntryArray to indices in mValues.
-    Vector<size_t>                          mEntryArrayToValues;
+
+    // The following data structures are used for book-keeping as the
+    // string pool is constructed.
+
     // Unique set of all the strings added to the pool, mapped to
     // the first index of mEntryArray where the value was added.
     DefaultKeyedVector<String16, ssize_t>   mValues;
     // Unique set of all (optional) identifiers of strings in the
     // pool, mapping to indices in mEntries.
     DefaultKeyedVector<String16, ssize_t>   mIdents;
-
+    // This array maps from the original position a string was placed at
+    // in mEntryArray to its new position after being sorted with sortByConfig().
+    Vector<size_t>                          mOriginalPosToNewPos;
 };
 
 #endif
diff --git a/tools/layoutlib/bridge/.settings/README.txt b/tools/layoutlib/bridge/.settings/README.txt
new file mode 100644
index 0000000..9120b20
--- /dev/null
+++ b/tools/layoutlib/bridge/.settings/README.txt
@@ -0,0 +1,2 @@
+Copy this in eclipse project as a .settings folder at the root.
+This ensure proper compilation compliance and warning/error levels.
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/.settings/org.eclipse.jdt.core.prefs b/tools/layoutlib/bridge/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..5381a0e
--- /dev/null
+++ b/tools/layoutlib/bridge/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,93 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.annotation.nonnull=com.android.annotations.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=com.android.annotations.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nonnullisdefault=disabled
+org.eclipse.jdt.core.compiler.annotation.nullable=com.android.annotations.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=enabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=error
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.nullSpecInsufficientInfo=warning
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=error
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/tools/layoutlib/bridge/src/android/animation/AnimationThread.java b/tools/layoutlib/bridge/src/android/animation/AnimationThread.java
index af83c61..b46134a 100644
--- a/tools/layoutlib/bridge/src/android/animation/AnimationThread.java
+++ b/tools/layoutlib/bridge/src/android/animation/AnimationThread.java
@@ -23,11 +23,10 @@
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.impl.RenderSessionImpl;
 
-import android.animation.ValueAnimator;
 import android.os.Handler;
 import android.os.Handler_Delegate;
-import android.os.Message;
 import android.os.Handler_Delegate.IHandlerCallback;
+import android.os.Message;
 
 import java.util.PriorityQueue;
 import java.util.Queue;
@@ -57,6 +56,7 @@
             mUptimeMillis = uptimeMillis;
         }
 
+        @Override
         public int compareTo(MessageBundle bundle) {
             if (mUptimeMillis < bundle.mUptimeMillis) {
                 return -1;
@@ -85,6 +85,7 @@
         Bridge.prepareThread();
         try {
             Handler_Delegate.setCallback(new IHandlerCallback() {
+                @Override
                 public void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) {
                     if (msg.what == ValueAnimator.ANIMATION_START /*||
                             FIXME: The ANIMATION_FRAME message no longer exists.  Instead,
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
index 9a8cf04..65a75b0 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
@@ -105,6 +105,7 @@
             mTileModeY = tileModeY;
         }
 
+        @Override
         public java.awt.PaintContext createContext(
                 java.awt.image.ColorModel      colorModel,
                 java.awt.Rectangle             deviceBounds,
@@ -148,13 +149,16 @@
                 mColorModel = colorModel;
             }
 
+            @Override
             public void dispose() {
             }
 
+            @Override
             public java.awt.image.ColorModel getColorModel() {
                 return mColorModel;
             }
 
+            @Override
             public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
                 java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
                         java.awt.image.BufferedImage.TYPE_INT_ARGB);
@@ -240,6 +244,7 @@
         }
 
 
+        @Override
         public int getTransparency() {
             return java.awt.Paint.TRANSLUCENT;
         }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index f797836..16f1575 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -291,6 +291,7 @@
             Paint paint) {
         draw(thisCanvas.mNativeCanvas, paint.mNativePaint, false /*compositeOnly*/,
                 false /*forceSrcMode*/, new GcSnapshot.Drawable() {
+                    @Override
                     public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                         for (int i = 0 ; i < count ; i += 4) {
                             graphics.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
@@ -619,6 +620,7 @@
         final int h = canvasDelegate.mBitmap.getImage().getHeight();
         draw(nativeCanvas, new GcSnapshot.Drawable() {
 
+            @Override
             public void draw(Graphics2D graphics, Paint_Delegate paint) {
                 // reset its transform just in case
                 graphics.setTransform(new AffineTransform());
@@ -651,6 +653,7 @@
 
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
+                    @Override
                     public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                         graphics.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
                     }
@@ -669,6 +672,7 @@
 
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
+                    @Override
                     public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                         int style = paintDelegate.getStyle();
 
@@ -693,6 +697,7 @@
         if (oval.right > oval.left && oval.bottom > oval.top) {
             draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                     new GcSnapshot.Drawable() {
+                        @Override
                         public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                             int style = paintDelegate.getStyle();
 
@@ -728,6 +733,7 @@
         if (oval.right > oval.left && oval.bottom > oval.top) {
             draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                     new GcSnapshot.Drawable() {
+                        @Override
                         public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                             int style = paintDelegate.getStyle();
 
@@ -757,6 +763,7 @@
 
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
+                    @Override
                     public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                         int style = paintDelegate.getStyle();
 
@@ -789,6 +796,7 @@
 
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
+                    @Override
                     public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                         Shape shape = pathDelegate.getJavaShape();
                         int style = paintDelegate.getStyle();
@@ -892,6 +900,7 @@
 
         draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
+                    @Override
                     public void draw(Graphics2D graphics, Paint_Delegate paint) {
                         if (paint != null && paint.isFilterBitmap()) {
                             graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
@@ -931,6 +940,7 @@
         final AffineTransform mtx = matrixDelegate.getAffineTransform();
 
         canvasDelegate.getSnapshot().draw(new GcSnapshot.Drawable() {
+                @Override
                 public void draw(Graphics2D graphics, Paint_Delegate paint) {
                     if (paint != null && paint.isFilterBitmap()) {
                         graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
@@ -970,6 +980,7 @@
             final float startX, final float startY, int flags, int paint) {
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
+            @Override
             public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                 // WARNING: the logic in this method is similar to Paint_Delegate.measureText.
                 // Any change to this method should be reflected in Paint.measureText
@@ -1279,6 +1290,7 @@
 
         draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, sBoolOut[0],
                 new GcSnapshot.Drawable() {
+                    @Override
                     public void draw(Graphics2D graphics, Paint_Delegate paint) {
                         if (paint != null && paint.isFilterBitmap()) {
                             graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
diff --git a/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java
index 38c092d..7475c22 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java
@@ -87,6 +87,7 @@
             mTileMode = tileMode;
         }
 
+        @Override
         public int getTransparency() {
             return java.awt.Paint.TRANSLUCENT;
         }
diff --git a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
index a2ba758..f117fca 100644
--- a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
@@ -132,6 +132,7 @@
             mDSize2 = mDx * mDx + mDy * mDy;
         }
 
+        @Override
         public java.awt.PaintContext createContext(
                 java.awt.image.ColorModel      colorModel,
                 java.awt.Rectangle             deviceBounds,
@@ -176,13 +177,16 @@
                 mColorModel = colorModel;
             }
 
+            @Override
             public void dispose() {
             }
 
+            @Override
             public java.awt.image.ColorModel getColorModel() {
                 return mColorModel;
             }
 
+            @Override
             public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
                 java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
                         java.awt.image.BufferedImage.TYPE_INT_ARGB);
diff --git a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
index 5e882ce..be27b54 100644
--- a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
@@ -215,6 +215,7 @@
         Paint_Delegate paint_delegate = Paint_Delegate.getDelegate(paint_instance_or_null);
 
         canvas_delegate.getSnapshot().draw(new GcSnapshot.Drawable() {
+                @Override
                 public void draw(Graphics2D graphics, Paint_Delegate paint) {
                     chunkObject.draw(bitmap_delegate.getImage(), graphics,
                             left, top, right - left, bottom - top, destDensity, srcDensity);
diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
index 9bf78b4..3fe45fa 100644
--- a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
@@ -118,6 +118,7 @@
             mRadius = radius;
         }
 
+        @Override
         public java.awt.PaintContext createContext(
                 java.awt.image.ColorModel     colorModel,
                 java.awt.Rectangle            deviceBounds,
@@ -162,13 +163,16 @@
                 mColorModel = colorModel;
             }
 
+            @Override
             public void dispose() {
             }
 
+            @Override
             public java.awt.image.ColorModel getColorModel() {
                 return mColorModel;
             }
 
+            @Override
             public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
                 java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
                         java.awt.image.BufferedImage.TYPE_INT_ARGB);
diff --git a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
index 966e06e..13ae12e 100644
--- a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
@@ -110,6 +110,7 @@
             mCy = cy;
         }
 
+        @Override
         public java.awt.PaintContext createContext(
                 java.awt.image.ColorModel     colorModel,
                 java.awt.Rectangle            deviceBounds,
@@ -154,13 +155,16 @@
                 mColorModel = colorModel;
             }
 
+            @Override
             public void dispose() {
             }
 
+            @Override
             public java.awt.image.ColorModel getColorModel() {
                 return mColorModel;
             }
 
+            @Override
             public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
                 java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
                         java.awt.image.BufferedImage.TYPE_INT_ARGB);
diff --git a/tools/layoutlib/bridge/src/android/view/SurfaceView.java b/tools/layoutlib/bridge/src/android/view/SurfaceView.java
index ce32da9..6aa4b3b 100644
--- a/tools/layoutlib/bridge/src/android/view/SurfaceView.java
+++ b/tools/layoutlib/bridge/src/android/view/SurfaceView.java
@@ -27,7 +27,7 @@
  * Mock version of the SurfaceView.
  * Only non override public methods from the real SurfaceView have been added in there.
  * Methods that take an unknown class as parameter or as return object, have been removed for now.
- * 
+ *
  * TODO: generate automatically.
  *
  */
@@ -36,7 +36,7 @@
     public SurfaceView(Context context) {
         this(context, null);
     }
-    
+
     public SurfaceView(Context context, AttributeSet attrs) {
         this(context, attrs , 0);
     }
@@ -44,53 +44,66 @@
     public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
     }
-    
+
     public SurfaceHolder getHolder() {
         return mSurfaceHolder;
     }
 
     private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
-        
+
+        @Override
         public boolean isCreating() {
             return false;
         }
 
+        @Override
         public void addCallback(Callback callback) {
         }
 
+        @Override
         public void removeCallback(Callback callback) {
         }
-        
+
+        @Override
         public void setFixedSize(int width, int height) {
         }
 
+        @Override
         public void setSizeFromLayout() {
         }
 
+        @Override
         public void setFormat(int format) {
         }
 
+        @Override
         public void setType(int type) {
         }
 
+        @Override
         public void setKeepScreenOn(boolean screenOn) {
         }
-        
+
+        @Override
         public Canvas lockCanvas() {
             return null;
         }
 
+        @Override
         public Canvas lockCanvas(Rect dirty) {
             return null;
         }
 
+        @Override
         public void unlockCanvasAndPost(Canvas canvas) {
         }
 
+        @Override
         public Surface getSurface() {
             return null;
         }
 
+        @Override
         public Rect getSurfaceFrame() {
             return null;
         }
diff --git a/tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java b/tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java
index 9efdcaf..3017292 100644
--- a/tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java
+++ b/tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java
@@ -43,28 +43,33 @@
 
     private static class FakeTextServicesManager implements ITextServicesManager {
 
+        @Override
         public void finishSpellCheckerService(ISpellCheckerSessionListener arg0)
                 throws RemoteException {
             // TODO Auto-generated method stub
 
         }
 
+        @Override
         public SpellCheckerInfo getCurrentSpellChecker(String arg0) throws RemoteException {
             // TODO Auto-generated method stub
             return null;
         }
 
+        @Override
         public SpellCheckerSubtype getCurrentSpellCheckerSubtype(String arg0, boolean arg1)
                 throws RemoteException {
             // TODO Auto-generated method stub
             return null;
         }
 
+        @Override
         public SpellCheckerInfo[] getEnabledSpellCheckers() throws RemoteException {
             // TODO Auto-generated method stub
             return null;
         }
 
+        @Override
         public void getSpellCheckerService(String arg0, String arg1,
                 ITextServicesSessionListener arg2, ISpellCheckerSessionListener arg3, Bundle arg4)
                 throws RemoteException {
@@ -72,26 +77,31 @@
 
         }
 
+        @Override
         public boolean isSpellCheckerEnabled() throws RemoteException {
             // TODO Auto-generated method stub
             return false;
         }
 
+        @Override
         public void setCurrentSpellChecker(String arg0, String arg1) throws RemoteException {
             // TODO Auto-generated method stub
 
         }
 
+        @Override
         public void setCurrentSpellCheckerSubtype(String arg0, int arg1) throws RemoteException {
             // TODO Auto-generated method stub
 
         }
 
+        @Override
         public void setSpellCheckerEnabled(boolean arg0) throws RemoteException {
             // TODO Auto-generated method stub
 
         }
 
+        @Override
         public IBinder asBinder() {
             // TODO Auto-generated method stub
             return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
index c64ab65..e28866e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
@@ -19,7 +19,7 @@
 import android.content.ContentProviderOperation;
 import android.content.ContentProviderResult;
 import android.content.ContentValues;
-import android.content.ICancelationSignal;
+import android.content.ICancellationSignal;
 import android.content.IContentProvider;
 import android.content.OperationApplicationException;
 import android.content.res.AssetFileDescriptor;
@@ -92,7 +92,7 @@
 
     @Override
     public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4,
-            ICancelationSignal arg5) throws RemoteException {
+            ICancellationSignal arg5) throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
@@ -124,7 +124,7 @@
     }
 
     @Override
-    public ICancelationSignal createCancelationSignal() throws RemoteException {
+    public ICancellationSignal createCancellationSignal() throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
index 2a52888..db0694c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
@@ -37,151 +37,179 @@
  */
 public class BridgeIInputMethodManager implements IInputMethodManager {
 
+    @Override
     public void addClient(IInputMethodClient arg0, IInputContext arg1, int arg2, int arg3)
             throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void finishInput(IInputMethodClient arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public InputMethodSubtype getCurrentInputMethodSubtype() throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public List<InputMethodInfo> getEnabledInputMethodList() throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo arg0,
             boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public List<InputMethodInfo> getInputMethodList() throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public InputMethodSubtype getLastInputMethodSubtype() throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public List getShortcutInputMethodsAndSubtypes() throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public void hideMySoftInput(IBinder arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public boolean hideSoftInput(IInputMethodClient arg0, int arg1, ResultReceiver arg2)
             throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean notifySuggestionPicked(SuggestionSpan arg0, String arg1, int arg2)
             throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public void registerSuggestionSpansForNotification(SuggestionSpan[] arg0)
             throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void removeClient(IInputMethodClient arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setAdditionalInputMethodSubtypes(String arg0, InputMethodSubtype[] arg1)
             throws RemoteException {
         // TODO Auto-generated method stub
     }
 
+    @Override
     public boolean setCurrentInputMethodSubtype(InputMethodSubtype arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public void setImeWindowStatus(IBinder arg0, int arg1, int arg2) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setInputMethod(IBinder arg0, String arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setInputMethodAndSubtype(IBinder arg0, String arg1, InputMethodSubtype arg2)
             throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public boolean setInputMethodEnabled(String arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public void showInputMethodAndSubtypeEnablerFromClient(IInputMethodClient arg0, String arg1)
             throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void showInputMethodPickerFromClient(IInputMethodClient arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void showMySoftInput(IBinder arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public boolean showSoftInput(IInputMethodClient arg0, int arg1, ResultReceiver arg2)
             throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public InputBindResult startInput(IInputMethodClient arg0, IInputContext arg1, EditorInfo arg2,
             boolean arg3, boolean arg4) throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public boolean switchToLastInputMethod(IBinder arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public void updateStatusIcon(IBinder arg0, String arg1, int arg2) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void windowGainedFocus(IInputMethodClient arg0, IBinder arg1, boolean arg2,
             boolean arg3, int arg4, boolean arg5, int arg6) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public IBinder asBinder() {
         // TODO Auto-generated method stub
         return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeLayoutParamsMapAttributes.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeLayoutParamsMapAttributes.java
index d208408..f5912e7 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeLayoutParamsMapAttributes.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeLayoutParamsMapAttributes.java
@@ -37,6 +37,7 @@
         mAttributes = attributes;
     }
 
+    @Override
     public String getAttributeValue(String namespace, String name) {
         if (BridgeConstants.NS_RESOURCES.equals(namespace)) {
             return mAttributes.get(name);
@@ -49,93 +50,114 @@
     // BridgeContext#obtainStyledAttributes(AttributeSet, int[], int, int)
     // Should they ever be called, we'll just implement them on a need basis.
 
+    @Override
     public int getAttributeCount() {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public String getAttributeName(int index) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public String getAttributeValue(int index) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public String getPositionDescription() {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getAttributeNameResource(int index) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getAttributeListValue(String namespace, String attribute,
             String[] options, int defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public boolean getAttributeBooleanValue(String namespace, String attribute,
             boolean defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getAttributeResourceValue(String namespace, String attribute,
             int defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getAttributeIntValue(String namespace, String attribute,
             int defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getAttributeUnsignedIntValue(String namespace, String attribute,
             int defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public float getAttributeFloatValue(String namespace, String attribute,
             float defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getAttributeListValue(int index,
             String[] options, int defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public boolean getAttributeBooleanValue(int index, boolean defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getAttributeResourceValue(int index, int defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getAttributeIntValue(int index, int defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getAttributeUnsignedIntValue(int index, int defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public float getAttributeFloatValue(int index, float defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public String getIdAttribute() {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public String getClassAttribute() {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getIdAttributeResourceValue(int defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getStyleAttribute() {
         throw new UnsupportedOperationException();
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index e13380e..79606a4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -24,72 +24,67 @@
 import android.os.RemoteException;
 import android.view.DragEvent;
 import android.view.IWindow;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
 
 /**
  * Implementation of {@link IWindow} to pass to the AttachInfo.
  */
 public final class BridgeWindow implements IWindow {
 
+    @Override
     public void dispatchAppVisibility(boolean arg0) throws RemoteException {
         // pass for now.
     }
 
+    @Override
     public void dispatchGetNewSurface() throws RemoteException {
         // pass for now.
     }
-
-    public void dispatchKey(KeyEvent arg0) throws RemoteException {
-        // pass for now.
-    }
-
-    public void dispatchPointer(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException {
-        // pass for now.
-    }
-
-    public void dispatchTrackball(MotionEvent arg0, long arg1, boolean arg2)
-    throws RemoteException {
-        // pass for now.
-    }
-
+    @Override
     public void executeCommand(String arg0, String arg1, ParcelFileDescriptor arg2)
             throws RemoteException {
         // pass for now.
     }
 
+    @Override
     public void resized(int arg0, int arg1, Rect arg2, Rect arg3, boolean arg4, Configuration arg5)
             throws RemoteException {
         // pass for now.
     }
 
+    @Override
     public void windowFocusChanged(boolean arg0, boolean arg1) throws RemoteException {
         // pass for now.
     }
 
+    @Override
     public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
             boolean sync) {
         // pass for now.
     }
 
+    @Override
     public void dispatchWallpaperCommand(String action, int x, int y,
             int z, Bundle extras, boolean sync) {
         // pass for now.
     }
 
+    @Override
     public void closeSystemDialogs(String reason) {
         // pass for now.
     }
 
+    @Override
     public void dispatchDragEvent(DragEvent event) {
         // pass for now.
     }
 
+    @Override
     public void dispatchSystemUiVisibilityChanged(int seq, int globalUi,
             int localValue, int localChanges) {
         // pass for now.
     }
 
+    @Override
     public IBinder asBinder() {
         // pass for now.
         return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
index 516725e..bef2c95 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -67,288 +67,345 @@
 
     // ---- implementation of IWindowManager that we care about ----
 
+    @Override
     public int getRotation() throws RemoteException {
         return mRotation;
     }
 
+    @Override
     public int getMaximumSizeDimension() throws RemoteException {
         return 0;
     }
 
+    @Override
     public void getDisplaySize(Point arg0) throws RemoteException {
     }
 
+    @Override
     public void getRealDisplaySize(Point arg0) throws RemoteException {
     }
 
     // ---- unused implementation of IWindowManager ----
 
+    @Override
     public boolean canStatusBarHide() throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, boolean arg4)
             throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void addWindowToken(IBinder arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void clearForcedDisplaySize() throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void closeSystemDialogs(String arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void disableKeyguard(IBinder arg0, String arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void executeAppTransition() throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void exitKeyguardSecurely(IOnKeyguardExitResult arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void freezeRotation(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public float getAnimationScale(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public float[] getAnimationScales() throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public int getAppOrientation(IApplicationToken arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public int getDPadKeycodeState(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public int getDPadScancodeState(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
 
+    @Override
     public InputDevice getInputDevice(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public int[] getInputDeviceIds() throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public int getKeycodeState(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public int getKeycodeStateForDevice(int arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
 
+    @Override
     public int getPendingAppTransition() throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
 
+    @Override
     public int getScancodeState(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public int getScancodeStateForDevice(int arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public int getSwitchState(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public int getSwitchStateForDevice(int arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public int getTrackballKeycodeState(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public int getTrackballScancodeState(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public boolean hasKeys(int[] arg0, boolean[] arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean inKeyguardRestrictedInputMode() throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean injectInputEventNoWait(InputEvent arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean injectKeyEvent(KeyEvent arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean injectPointerEvent(MotionEvent arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean injectTrackballEvent(MotionEvent arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean inputMethodClientHasFocus(IInputMethodClient arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean isKeyguardLocked() throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean isKeyguardSecure() throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean isViewServerRunning() throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public InputChannel monitorInput(String arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public void moveAppToken(int arg0, IBinder arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void moveAppTokensToBottom(List<IBinder> arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void moveAppTokensToTop(List<IBinder> arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public IWindowSession openSession(IInputMethodClient arg0, IInputContext arg1)
             throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public void overridePendingAppTransition(String arg0, int arg1, int arg2)
             throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void pauseKeyDispatching(IBinder arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void prepareAppTransition(int arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void reenableKeyguard(IBinder arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void removeAppToken(IBinder arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void removeWindowToken(IBinder arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void resumeKeyDispatching(IBinder arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public Bitmap screenshotApplications(IBinder arg0, int arg1, int arg2) throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public void setAnimationScale(int arg0, float arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setAnimationScales(float[] arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setAppGroupId(IBinder arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setAppOrientation(IApplicationToken arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setAppStartingWindow(IBinder arg0, String arg1, int arg2, CompatibilityInfo arg3,
             CharSequence arg4, int arg5, int arg6, int arg7, IBinder arg8, boolean arg9)
             throws RemoteException {
@@ -356,122 +413,147 @@
 
     }
 
+    @Override
     public void setAppVisibility(IBinder arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setAppWillBeHidden(IBinder arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setEventDispatching(boolean arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setFocusedApp(IBinder arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setForcedDisplaySize(int arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setInTouchMode(boolean arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setNewConfiguration(Configuration arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setPointerSpeed(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void updateRotation(boolean arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setStrictModeVisualIndicatorPreference(String arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void showStrictModeViolation(boolean arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void startAppFreezingScreen(IBinder arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public boolean startViewServer(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public void statusBarVisibilityChanged(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void stopAppFreezingScreen(IBinder arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public boolean stopViewServer() throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public void thawRotation() throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public Configuration updateOrientationFromAppTokens(Configuration arg0, IBinder arg1)
             throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public int watchRotation(IRotationWatcher arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
         // TODO Auto-generated method stub
     }
-    
+
+    @Override
     public IBinder asBinder() {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public int getPreferredOptionsPanelGravity() throws RemoteException {
         return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
     }
 
+    @Override
     public void dismissKeyguard() {
     }
 
+    @Override
     public boolean hasNavigationBar() {
         return false; // should this return something else?
     }
 
+    @Override
     public void lockNow() {
         // TODO Auto-generated method stub
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index a640a91..d3721ed 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -26,7 +26,6 @@
 import android.view.IWindow;
 import android.view.IWindowSession;
 import android.view.InputChannel;
-import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.SurfaceView;
 import android.view.WindowManager.LayoutParams;
@@ -37,6 +36,7 @@
  */
 public final class BridgeWindowSession implements IWindowSession {
 
+    @Override
     public int add(IWindow arg0, int seq, LayoutParams arg1, int arg2, Rect arg3,
             InputChannel outInputchannel)
             throws RemoteException {
@@ -44,40 +44,30 @@
         return 0;
     }
 
+    @Override
     public int addWithoutInputChannel(IWindow arg0, int seq, LayoutParams arg1, int arg2, Rect arg3)
             throws RemoteException {
         // pass for now.
         return 0;
     }
 
+    @Override
     public void finishDrawing(IWindow arg0) throws RemoteException {
         // pass for now.
     }
 
-    public void finishKey(IWindow arg0) throws RemoteException {
-        // pass for now.
-    }
-
+    @Override
     public boolean getInTouchMode() throws RemoteException {
         // pass for now.
         return false;
     }
 
+    @Override
     public boolean performHapticFeedback(IWindow window, int effectId, boolean always) {
         // pass for now.
         return false;
     }
-
-    public MotionEvent getPendingPointerMove(IWindow arg0) throws RemoteException {
-        // pass for now.
-        return null;
-    }
-
-    public MotionEvent getPendingTrackballMove(IWindow arg0) throws RemoteException {
-        // pass for now.
-        return null;
-    }
-
+    @Override
     public int relayout(IWindow arg0, int seq, LayoutParams arg1, int arg2, int arg3, int arg4,
             int arg4_5, Rect arg5, Rect arg6, Rect arg7, Configuration arg7b, Surface arg8)
             throws RemoteException {
@@ -85,35 +75,43 @@
         return 0;
     }
 
+    @Override
     public void performDeferredDestroy(IWindow window) {
         // pass for now.
     }
 
+    @Override
     public boolean outOfMemory(IWindow window) throws RemoteException {
         return false;
     }
 
+    @Override
     public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
         // pass for now.
     }
 
+    @Override
     public void remove(IWindow arg0) throws RemoteException {
         // pass for now.
     }
 
+    @Override
     public void setInTouchMode(boolean arg0) throws RemoteException {
         // pass for now.
     }
 
+    @Override
     public void setTransparentRegion(IWindow arg0, Region arg1) throws RemoteException {
         // pass for now.
     }
 
+    @Override
     public void setInsets(IWindow window, int touchable, Rect contentInsets,
             Rect visibleInsets, Region touchableRegion) {
         // pass for now.
     }
 
+    @Override
     public IBinder prepareDrag(IWindow window, int flags,
             int thumbnailWidth, int thumbnailHeight, Surface outSurface)
             throws RemoteException {
@@ -121,6 +119,7 @@
         return null;
     }
 
+    @Override
     public boolean performDrag(IWindow window, IBinder dragToken,
             float touchX, float touchY, float thumbCenterX, float thumbCenterY,
             ClipData data)
@@ -129,49 +128,47 @@
         return false;
     }
 
+    @Override
     public void reportDropResult(IWindow window, boolean consumed) throws RemoteException {
         // pass for now
     }
 
+    @Override
     public void dragRecipientEntered(IWindow window) throws RemoteException {
         // pass for now
     }
 
+    @Override
     public void dragRecipientExited(IWindow window) throws RemoteException {
         // pass for now
     }
 
+    @Override
     public void setWallpaperPosition(IBinder window, float x, float y,
         float xStep, float yStep) {
         // pass for now.
     }
 
+    @Override
     public void wallpaperOffsetsComplete(IBinder window) {
         // pass for now.
     }
 
+    @Override
     public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
             int z, Bundle extras, boolean sync) {
         // pass for now.
         return null;
     }
 
+    @Override
     public void wallpaperCommandComplete(IBinder window, Bundle result) {
         // pass for now.
     }
 
-    public void closeSystemDialogs(String reason) {
-        // pass for now.
-    }
-
+    @Override
     public IBinder asBinder() {
         // pass for now.
         return null;
     }
-
-    public IBinder prepareDrag(IWindow arg0, boolean arg1, int arg2, int arg3, Surface arg4)
-            throws RemoteException {
-        // TODO Auto-generated method stub
-        return null;
-    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
index f8ed4f7..ac8712e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
@@ -95,6 +95,7 @@
 
     // ------- XmlResourceParser implementation
 
+    @Override
     public void setFeature(String name, boolean state)
             throws XmlPullParserException {
         if (FEATURE_PROCESS_NAMESPACES.equals(name) && state) {
@@ -106,6 +107,7 @@
         throw new XmlPullParserException("Unsupported feature: " + name);
     }
 
+    @Override
     public boolean getFeature(String name) {
         if (FEATURE_PROCESS_NAMESPACES.equals(name)) {
             return true;
@@ -116,82 +118,101 @@
         return false;
     }
 
+    @Override
     public void setProperty(String name, Object value) throws XmlPullParserException {
         throw new XmlPullParserException("setProperty() not supported");
     }
 
+    @Override
     public Object getProperty(String name) {
         return null;
     }
 
+    @Override
     public void setInput(Reader in) throws XmlPullParserException {
         mParser.setInput(in);
     }
 
+    @Override
     public void setInput(InputStream inputStream, String inputEncoding)
             throws XmlPullParserException {
         mParser.setInput(inputStream, inputEncoding);
     }
 
+    @Override
     public void defineEntityReplacementText(String entityName,
             String replacementText) throws XmlPullParserException {
         throw new XmlPullParserException(
                 "defineEntityReplacementText() not supported");
     }
 
+    @Override
     public String getNamespacePrefix(int pos) throws XmlPullParserException {
         throw new XmlPullParserException("getNamespacePrefix() not supported");
     }
 
+    @Override
     public String getInputEncoding() {
         return null;
     }
 
+    @Override
     public String getNamespace(String prefix) {
         throw new RuntimeException("getNamespace() not supported");
     }
 
+    @Override
     public int getNamespaceCount(int depth) throws XmlPullParserException {
         throw new XmlPullParserException("getNamespaceCount() not supported");
     }
 
+    @Override
     public String getPositionDescription() {
         return "Binary XML file line #" + getLineNumber();
     }
 
+    @Override
     public String getNamespaceUri(int pos) throws XmlPullParserException {
         throw new XmlPullParserException("getNamespaceUri() not supported");
     }
 
+    @Override
     public int getColumnNumber() {
         return -1;
     }
 
+    @Override
     public int getDepth() {
         return mParser.getDepth();
     }
 
+    @Override
     public String getText() {
         return mParser.getText();
     }
 
+    @Override
     public int getLineNumber() {
         return mParser.getLineNumber();
     }
 
+    @Override
     public int getEventType() {
         return mEventType;
     }
 
+    @Override
     public boolean isWhitespace() throws XmlPullParserException {
         // Original comment: whitespace was stripped by aapt.
         return mParser.isWhitespace();
     }
 
+    @Override
     public String getPrefix() {
         throw new RuntimeException("getPrefix not supported");
     }
 
+    @Override
     public char[] getTextCharacters(int[] holderForStartAndLength) {
         String txt = getText();
         char[] chars = null;
@@ -204,55 +225,68 @@
         return chars;
     }
 
+    @Override
     public String getNamespace() {
         return mParser.getNamespace();
     }
 
+    @Override
     public String getName() {
         return mParser.getName();
     }
 
+    @Override
     public String getAttributeNamespace(int index) {
         return mParser.getAttributeNamespace(index);
     }
 
+    @Override
     public String getAttributeName(int index) {
         return mParser.getAttributeName(index);
     }
 
+    @Override
     public String getAttributePrefix(int index) {
         throw new RuntimeException("getAttributePrefix not supported");
     }
 
+    @Override
     public boolean isEmptyElementTag() {
         // XXX Need to detect this.
         return false;
     }
 
+    @Override
     public int getAttributeCount() {
         return mParser.getAttributeCount();
     }
 
+    @Override
     public String getAttributeValue(int index) {
         return mParser.getAttributeValue(index);
     }
 
+    @Override
     public String getAttributeType(int index) {
         return "CDATA";
     }
 
+    @Override
     public boolean isAttributeDefault(int index) {
         return false;
     }
 
+    @Override
     public int nextToken() throws XmlPullParserException, IOException {
         return next();
     }
 
+    @Override
     public String getAttributeValue(String namespace, String name) {
         return mParser.getAttributeValue(namespace, name);
     }
 
+    @Override
     public int next() throws XmlPullParserException, IOException {
         if (!mStarted) {
             mStarted = true;
@@ -313,6 +347,7 @@
         return "????";
     }
 
+    @Override
     public void require(int type, String namespace, String name)
             throws XmlPullParserException {
         if (type != getEventType()
@@ -322,6 +357,7 @@
                     + getPositionDescription());
     }
 
+    @Override
     public String nextText() throws XmlPullParserException, IOException {
         if (getEventType() != START_TAG) {
             throw new XmlPullParserException(getPositionDescription()
@@ -348,6 +384,7 @@
         }
     }
 
+    @Override
     public int nextTag() throws XmlPullParserException, IOException {
         int eventType = next();
         if (eventType == TEXT && isWhitespace()) { // skip whitespace
@@ -363,76 +400,94 @@
     // AttributeSet implementation
 
 
+    @Override
     public void close() {
         // pass
     }
 
+    @Override
     public boolean getAttributeBooleanValue(int index, boolean defaultValue) {
         return mAttrib.getAttributeBooleanValue(index, defaultValue);
     }
 
+    @Override
     public boolean getAttributeBooleanValue(String namespace, String attribute,
             boolean defaultValue) {
         return mAttrib.getAttributeBooleanValue(namespace, attribute, defaultValue);
     }
 
+    @Override
     public float getAttributeFloatValue(int index, float defaultValue) {
         return mAttrib.getAttributeFloatValue(index, defaultValue);
     }
 
+    @Override
     public float getAttributeFloatValue(String namespace, String attribute, float defaultValue) {
         return mAttrib.getAttributeFloatValue(namespace, attribute, defaultValue);
     }
 
+    @Override
     public int getAttributeIntValue(int index, int defaultValue) {
         return mAttrib.getAttributeIntValue(index, defaultValue);
     }
 
+    @Override
     public int getAttributeIntValue(String namespace, String attribute, int defaultValue) {
         return mAttrib.getAttributeIntValue(namespace, attribute, defaultValue);
     }
 
+    @Override
     public int getAttributeListValue(int index, String[] options, int defaultValue) {
         return mAttrib.getAttributeListValue(index, options, defaultValue);
     }
 
+    @Override
     public int getAttributeListValue(String namespace, String attribute,
             String[] options, int defaultValue) {
         return mAttrib.getAttributeListValue(namespace, attribute, options, defaultValue);
     }
 
+    @Override
     public int getAttributeNameResource(int index) {
         return mAttrib.getAttributeNameResource(index);
     }
 
+    @Override
     public int getAttributeResourceValue(int index, int defaultValue) {
         return mAttrib.getAttributeResourceValue(index, defaultValue);
     }
 
+    @Override
     public int getAttributeResourceValue(String namespace, String attribute, int defaultValue) {
         return mAttrib.getAttributeResourceValue(namespace, attribute, defaultValue);
     }
 
+    @Override
     public int getAttributeUnsignedIntValue(int index, int defaultValue) {
         return mAttrib.getAttributeUnsignedIntValue(index, defaultValue);
     }
 
+    @Override
     public int getAttributeUnsignedIntValue(String namespace, String attribute, int defaultValue) {
         return mAttrib.getAttributeUnsignedIntValue(namespace, attribute, defaultValue);
     }
 
+    @Override
     public String getClassAttribute() {
         return mAttrib.getClassAttribute();
     }
 
+    @Override
     public String getIdAttribute() {
         return mAttrib.getIdAttribute();
     }
 
+    @Override
     public int getIdAttributeResourceValue(int defaultValue) {
         return mAttrib.getIdAttributeResourceValue(defaultValue);
     }
 
+    @Override
     public int getStyleAttribute() {
         return mAttrib.getStyleAttribute();
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index d5400d7..6840f46 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -33,10 +33,10 @@
 import com.android.ide.common.rendering.api.ResourceReference;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.ide.common.rendering.api.Result;
-import com.android.ide.common.rendering.api.SessionParams;
-import com.android.ide.common.rendering.api.ViewInfo;
 import com.android.ide.common.rendering.api.Result.Status;
+import com.android.ide.common.rendering.api.SessionParams;
 import com.android.ide.common.rendering.api.SessionParams.RenderingMode;
+import com.android.ide.common.rendering.api.ViewInfo;
 import com.android.internal.util.XmlUtils;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.android.BridgeContext;
@@ -69,8 +69,8 @@
 import android.view.AttachInfo_Accessor;
 import android.view.BridgeInflater;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewGroup.MarginLayoutParams;
 import android.widget.AbsListView;
@@ -82,8 +82,8 @@
 import android.widget.ListView;
 import android.widget.QuickContactBadge;
 import android.widget.TabHost;
-import android.widget.TabWidget;
 import android.widget.TabHost.TabSpec;
+import android.widget.TabWidget;
 
 import java.awt.AlphaComposite;
 import java.awt.Color;
@@ -835,6 +835,7 @@
                 previousTransition.addTransitionListener(new TransitionListener() {
                     private int mChangeDisappearingCount = 0;
 
+                    @Override
                     public void startTransition(LayoutTransition transition, ViewGroup container,
                             View view, int transitionType) {
                         if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
@@ -842,6 +843,7 @@
                         }
                     }
 
+                    @Override
                     public void endTransition(LayoutTransition transition, ViewGroup container,
                             View view, int transitionType) {
                         if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
@@ -1227,6 +1229,7 @@
             TabSpec spec = tabHost.newTabSpec("tag").setIndicator("Tab Label",
                     tabHost.getResources().getDrawable(android.R.drawable.ic_menu_info_details))
                     .setContent(new TabHost.TabContentFactory() {
+                        @Override
                         public View createTabContent(String tag) {
                             return new LinearLayout(getContext());
                         }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
index c9bb424..22570b9 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
@@ -74,38 +74,46 @@
         }
     }
 
+    @Override
     public boolean isEnabled(int position) {
         return true;
     }
 
+    @Override
     public int getCount() {
         return mItems.size();
     }
 
+    @Override
     public Object getItem(int position) {
         return mItems.get(position);
     }
 
+    @Override
     public long getItemId(int position) {
         return position;
     }
 
+    @Override
     public int getItemViewType(int position) {
         return mItems.get(position).getType();
     }
 
+    @Override
     public View getView(int position, View convertView, ViewGroup parent) {
         // we don't care about recycling here because we never scroll.
         AdapterItem item = mItems.get(position);
         return getView(item, null /*parentGroup*/, convertView, parent);
     }
 
+    @Override
     public int getViewTypeCount() {
         return mTypes.size();
     }
 
     // ---- SpinnerAdapter
 
+    @Override
     public View getDropDownView(int position, View convertView, ViewGroup parent) {
         // pass
         return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
index 2c492e3..199e040 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
@@ -99,23 +99,28 @@
 
     // ---- ExpandableListAdapter
 
+    @Override
     public int getGroupCount() {
         return mItems.size();
     }
 
+    @Override
     public int getChildrenCount(int groupPosition) {
         AdapterItem item = mItems.get(groupPosition);
         return item.getChildren().size();
     }
 
+    @Override
     public Object getGroup(int groupPosition) {
         return mItems.get(groupPosition);
     }
 
+    @Override
     public Object getChild(int groupPosition, int childPosition) {
         return getChildItem(groupPosition, childPosition);
     }
 
+    @Override
     public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
             ViewGroup parent) {
         // we don't care about recycling here because we never scroll.
@@ -123,6 +128,7 @@
         return getView(item, null /*parentItem*/, convertView, parent);
     }
 
+    @Override
     public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
             View convertView, ViewGroup parent) {
         // we don't care about recycling here because we never scroll.
@@ -131,48 +137,59 @@
         return getView(item, parentItem, convertView, parent);
     }
 
+    @Override
     public long getGroupId(int groupPosition) {
         return groupPosition;
     }
 
+    @Override
     public long getChildId(int groupPosition, int childPosition) {
         return childPosition;
     }
 
+    @Override
     public long getCombinedGroupId(long groupId) {
         return groupId << 16 | 0x0000FFFF;
     }
 
+    @Override
     public long getCombinedChildId(long groupId, long childId) {
         return groupId << 16 | childId;
     }
 
+    @Override
     public boolean isChildSelectable(int groupPosition, int childPosition) {
         return true;
     }
 
+    @Override
     public void onGroupCollapsed(int groupPosition) {
         // pass
     }
 
+    @Override
     public void onGroupExpanded(int groupPosition) {
         // pass
     }
 
     // ---- HeterogeneousExpandableList
 
+    @Override
     public int getChildType(int groupPosition, int childPosition) {
         return getChildItem(groupPosition, childPosition).getType();
     }
 
+    @Override
     public int getChildTypeCount() {
         return mChildrenTypes.size();
     }
 
+    @Override
     public int getGroupType(int groupPosition) {
         return mItems.get(groupPosition).getType();
     }
 
+    @Override
     public int getGroupTypeCount() {
         return mGroupTypes.size();
     }
diff --git a/tools/layoutlib/create/.settings/README.txt b/tools/layoutlib/create/.settings/README.txt
new file mode 100644
index 0000000..9120b20
--- /dev/null
+++ b/tools/layoutlib/create/.settings/README.txt
@@ -0,0 +1,2 @@
+Copy this in eclipse project as a .settings folder at the root.
+This ensure proper compilation compliance and warning/error levels.
\ No newline at end of file
diff --git a/tools/layoutlib/create/.settings/org.eclipse.jdt.core.prefs b/tools/layoutlib/create/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..5381a0e
--- /dev/null
+++ b/tools/layoutlib/create/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,93 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.annotation.nonnull=com.android.annotations.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=com.android.annotations.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nonnullisdefault=disabled
+org.eclipse.jdt.core.compiler.annotation.nullable=com.android.annotations.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=enabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=error
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.nullSpecInsufficientInfo=warning
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=error
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 70c8a00..4b33474 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -27,6 +27,7 @@
      * Returns the list of class from layoutlib_create to inject in layoutlib.
      * The list can be empty but must not be null.
      */
+    @Override
     public Class<?>[] getInjectedClasses() {
         return INJECTED_CLASSES;
     }
@@ -35,6 +36,7 @@
      * Returns the list of methods to rewrite as delegates.
      * The list can be empty but must not be null.
      */
+    @Override
     public String[] getDelegateMethods() {
         return DELEGATE_METHODS;
     }
@@ -43,6 +45,7 @@
      * Returns the list of classes on which to delegate all native methods.
      * The list can be empty but must not be null.
      */
+    @Override
     public String[] getDelegateClassNatives() {
         return DELEGATE_CLASS_NATIVES;
     }
@@ -54,6 +57,7 @@
      * <p/>
      * This usage is deprecated. Please use method 'delegates' instead.
      */
+    @Override
     public String[] getOverriddenMethods() {
         return OVERRIDDEN_METHODS;
     }
@@ -63,6 +67,7 @@
      * of class to replace followed by the new FQCN.
      * The list can be empty but must not be null.
      */
+    @Override
     public String[] getRenamedClasses() {
         return RENAMED_CLASSES;
     }
@@ -74,6 +79,7 @@
      * the methods to delete.
      * The list can be empty but must not be null.
      */
+    @Override
     public String[] getDeleteReturns() {
         return DELETE_RETURNS;
     }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodAdapter.java
index 627ea17..7d1e4cf 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodAdapter.java
@@ -28,13 +28,14 @@
      * A stub method is being invoked.
      * <p/>
      * Known limitation: caller arguments are not available.
-     *  
+     *
      * @param signature The signature of the method being invoked, composed of the
      *                  binary class name followed by the method descriptor (aka argument
      *                  types). Example: "com/foo/MyClass/InnerClass/printInt(I)V".
      * @param isNative True if the method was a native method.
      * @param caller The calling object. Null for static methods, "this" for instance methods.
      */
+    @Override
     public void onInvokeV(String signature, boolean isNative, Object caller) {
     }
 
@@ -43,6 +44,7 @@
      * @see #onInvokeV(String, boolean, Object)
      * @return an integer, or a boolean, or a short or a byte.
      */
+    @Override
     public int onInvokeI(String signature, boolean isNative, Object caller) {
         onInvokeV(signature, isNative, caller);
         return 0;
@@ -53,6 +55,7 @@
      * @see #onInvokeV(String, boolean, Object)
      * @return a long.
      */
+    @Override
     public long onInvokeL(String signature, boolean isNative, Object caller) {
         onInvokeV(signature, isNative, caller);
         return 0;
@@ -63,6 +66,7 @@
      * @see #onInvokeV(String, boolean, Object)
      * @return a float.
      */
+    @Override
     public float onInvokeF(String signature, boolean isNative, Object caller) {
         onInvokeV(signature, isNative, caller);
         return 0;
@@ -73,6 +77,7 @@
      * @see #onInvokeV(String, boolean, Object)
      * @return a double.
      */
+    @Override
     public double onInvokeD(String signature, boolean isNative, Object caller) {
         onInvokeV(signature, isNative, caller);
         return 0;
@@ -83,6 +88,7 @@
      * @see #onInvokeV(String, boolean, Object)
      * @return an object.
      */
+    @Override
     public Object onInvokeA(String signature, boolean isNative, Object caller) {
         onInvokeV(signature, isNative, caller);
         return null;
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
index f4ff389..7b76a5b 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
@@ -65,24 +65,29 @@
     public void testClassRenaming() throws IOException, LogAbortException {
 
         ICreateInfo ci = new ICreateInfo() {
+            @Override
             public Class<?>[] getInjectedClasses() {
                 // classes to inject in the final JAR
                 return new Class<?>[0];
             }
 
+            @Override
             public String[] getDelegateMethods() {
                 return new String[0];
             }
 
+            @Override
             public String[] getDelegateClassNatives() {
                 return new String[0];
             }
 
+            @Override
             public String[] getOverriddenMethods() {
                 // methods to force override
                 return new String[0];
             }
 
+            @Override
             public String[] getRenamedClasses() {
                 // classes to rename (so that we can replace them)
                 return new String[] {
@@ -91,6 +96,7 @@
                 };
             }
 
+            @Override
             public String[] getDeleteReturns() {
                  // methods deleted from their return type.
                 return new String[0];