Merge "TTS: SynthesisRequest.error() instead of return value"
diff --git a/api/current.txt b/api/current.txt
index 9d593d8..975444e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2851,6 +2851,7 @@
     method public void onSaveInstanceState(android.os.Bundle);
     method public void onStart();
     method public void onStop();
+    method public void onViewCreated(android.view.View, android.os.Bundle);
     method public void registerForContextMenu(android.view.View);
     method public void setArguments(android.os.Bundle);
     method public void setHasOptionsMenu(boolean);
@@ -2923,8 +2924,10 @@
     method public abstract android.app.FragmentTransaction add(int, android.app.Fragment);
     method public abstract android.app.FragmentTransaction add(int, android.app.Fragment, java.lang.String);
     method public abstract android.app.FragmentTransaction addToBackStack(java.lang.String);
+    method public abstract android.app.FragmentTransaction attach(android.app.Fragment);
     method public abstract int commit();
     method public abstract int commitAllowingStateLoss();
+    method public abstract android.app.FragmentTransaction detach(android.app.Fragment);
     method public abstract android.app.FragmentTransaction disallowAddToBackStack();
     method public abstract android.app.FragmentTransaction hide(android.app.Fragment);
     method public abstract boolean isAddToBackStackAllowed();
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 850f56a..e5a7980 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -173,6 +173,8 @@
     static final int OP_REMOVE = 3;
     static final int OP_HIDE = 4;
     static final int OP_SHOW = 5;
+    static final int OP_DETACH = 6;
+    static final int OP_ATTACH = 7;
 
     static final class Op {
         Op next;
@@ -416,6 +418,32 @@
         return this;
     }
 
+    public FragmentTransaction detach(Fragment fragment) {
+        //if (fragment.mImmediateActivity == null) {
+        //    throw new IllegalStateException("Fragment not added: " + fragment);
+        //}
+
+        Op op = new Op();
+        op.cmd = OP_DETACH;
+        op.fragment = fragment;
+        addOp(op);
+
+        return this;
+    }
+
+    public FragmentTransaction attach(Fragment fragment) {
+        //if (fragment.mImmediateActivity == null) {
+        //    throw new IllegalStateException("Fragment not added: " + fragment);
+        //}
+
+        Op op = new Op();
+        op.cmd = OP_ATTACH;
+        op.fragment = fragment;
+        addOp(op);
+
+        return this;
+    }
+
     public FragmentTransaction setCustomAnimations(int enter, int exit) {
         return setCustomAnimations(enter, exit, 0, 0);
     }
@@ -589,6 +617,16 @@
                     f.mNextAnim = op.enterAnim;
                     mManager.showFragment(f, mTransition, mTransitionStyle);
                 } break;
+                case OP_DETACH: {
+                    Fragment f = op.fragment;
+                    f.mNextAnim = op.exitAnim;
+                    mManager.detachFragment(f, mTransition, mTransitionStyle);
+                } break;
+                case OP_ATTACH: {
+                    Fragment f = op.fragment;
+                    f.mNextAnim = op.enterAnim;
+                    mManager.attachFragment(f, mTransition, mTransitionStyle);
+                } break;
                 default: {
                     throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
                 }
@@ -655,6 +693,16 @@
                     mManager.hideFragment(f,
                             FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
                 } break;
+                case OP_DETACH: {
+                    Fragment f = op.fragment;
+                    mManager.attachFragment(f,
+                            FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
+                } break;
+                case OP_ATTACH: {
+                    Fragment f = op.fragment;
+                    mManager.detachFragment(f,
+                            FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
+                } break;
                 default: {
                     throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
                 }
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 53dc7c8..dd158f9 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -52,6 +52,7 @@
     final int mContainerId;
     final String mTag;
     final boolean mRetainInstance;
+    final boolean mDetached;
     final Bundle mArguments;
     
     Bundle mSavedFragmentState;
@@ -66,6 +67,7 @@
         mContainerId = frag.mContainerId;
         mTag = frag.mTag;
         mRetainInstance = frag.mRetainInstance;
+        mDetached = frag.mDetached;
         mArguments = frag.mArguments;
     }
     
@@ -77,6 +79,7 @@
         mContainerId = in.readInt();
         mTag = in.readString();
         mRetainInstance = in.readInt() != 0;
+        mDetached = in.readInt() != 0;
         mArguments = in.readBundle();
         mSavedFragmentState = in.readBundle();
     }
@@ -103,6 +106,7 @@
         mInstance.mContainerId = mContainerId;
         mInstance.mTag = mTag;
         mInstance.mRetainInstance = mRetainInstance;
+        mInstance.mDetached = mDetached;
         mInstance.mFragmentManager = activity.mFragments;
         
         return mInstance;
@@ -120,6 +124,7 @@
         dest.writeInt(mContainerId);
         dest.writeString(mTag);
         dest.writeInt(mRetainInstance ? 1 : 0);
+        dest.writeInt(mDetached ? 1 : 0);
         dest.writeBundle(mArguments);
         dest.writeBundle(mSavedFragmentState);
     }
@@ -321,8 +326,9 @@
     static final int INITIALIZING = 0;     // Not yet created.
     static final int CREATED = 1;          // Created.
     static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
-    static final int STARTED = 3;          // Created and started, not resumed.
-    static final int RESUMED = 4;          // Created started and resumed.
+    static final int STOPPED = 3;          // Fully created, not started.
+    static final int STARTED = 4;          // Created and started, not resumed.
+    static final int RESUMED = 5;          // Created started and resumed.
     
     int mState = INITIALIZING;
     
@@ -404,6 +410,9 @@
     // from the user.
     boolean mHidden;
     
+    // Set to true when the app has requested that this fragment be detached.
+    boolean mDetached;
+
     // If set this fragment would like its instance retained across
     // configuration changes.
     boolean mRetainInstance;
@@ -511,23 +520,27 @@
         }
     }
     
-    void restoreViewState() {
+    final void restoreViewState() {
         if (mSavedViewState != null) {
             mView.restoreHierarchyState(mSavedViewState);
             mSavedViewState = null;
         }
     }
     
-    void setIndex(int index) {
+    final void setIndex(int index) {
         mIndex = index;
         mWho = "android:fragment:" + mIndex;
    }
     
-    void clearIndex() {
+    final void clearIndex() {
         mIndex = -1;
         mWho = null;
     }
     
+    final boolean isInBackStack() {
+        return mBackStackNesting > 0;
+    }
+
     /**
      * Subclasses can not override equals().
      */
@@ -947,6 +960,19 @@
     }
     
     /**
+     * Called immediately after {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}
+     * has returned, but before any saved state has been restored in to the view.
+     * This gives subclasses a chance to initialize themselves once
+     * they know their view hierarchy has been completely created.  The fragment's
+     * view hierarchy is not however attached to its parent at this point.
+     * @param view The View returned by {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}.
+     * @param savedInstanceState If non-null, this fragment is being re-constructed
+     * from a previous saved state as given here.
+     */
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+    }
+    
+    /**
      * Called to have the fragment instantiate its user interface view.
      * This is optional, and non-graphical fragments can return null (which
      * is the default implementation).  This will be called between
@@ -1280,6 +1306,7 @@
                 writer.print(" mFromLayout="); writer.print(mFromLayout);
                 writer.print(" mInLayout="); writer.println(mInLayout);
         writer.print(prefix); writer.print("mHidden="); writer.print(mHidden);
+                writer.print(" mDetached="); writer.print(mDetached);
                 writer.print(" mRetainInstance="); writer.print(mRetainInstance);
                 writer.print(" mRetaining="); writer.print(mRetaining);
                 writer.print(" mHasMenu="); writer.println(mHasMenu);
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index ab60cf0..0da656f 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -714,13 +714,14 @@
                                 null, f.mSavedFragmentState);
                         if (f.mView != null) {
                             f.mView.setSaveFromParentEnabled(false);
+                            if (f.mHidden) f.mView.setVisibility(View.GONE);
                             f.restoreViewState();
-                            if (f.mHidden) f.mView.setVisibility(View.GONE); 
+                            f.onViewCreated(f.mView, f.mSavedFragmentState);
                         }
                     }
                 case Fragment.CREATED:
                     if (newState > Fragment.CREATED) {
-                        if (DEBUG) Log.v(TAG, "moveto CONTENT: " + f);
+                        if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
                         if (!f.mFromLayout) {
                             ViewGroup container = null;
                             if (f.mContainerId != 0) {
@@ -744,9 +745,10 @@
                                         anim.start();
                                     }
                                     container.addView(f.mView);
-                                    f.restoreViewState();
                                 }
-                                if (f.mHidden) f.mView.setVisibility(View.GONE); 
+                                if (f.mHidden) f.mView.setVisibility(View.GONE);
+                                f.restoreViewState();
+                                f.onViewCreated(f.mView, f.mSavedFragmentState);
                             }
                         }
                         
@@ -756,10 +758,13 @@
                             throw new SuperNotCalledException("Fragment " + f
                                     + " did not call through to super.onActivityCreated()");
                         }
+                        if (f.mView != null) {
+                        }
                         f.mSavedFragmentState = null;
                     }
                 case Fragment.ACTIVITY_CREATED:
-                    if (newState > Fragment.ACTIVITY_CREATED) {
+                case Fragment.STOPPED:
+                    if (newState > Fragment.STOPPED) {
                         if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
                         f.mCalled = false;
                         f.onStart();
@@ -803,9 +808,10 @@
                                     + " did not call through to super.onStop()");
                         }
                     }
+                case Fragment.STOPPED:
                 case Fragment.ACTIVITY_CREATED:
                     if (newState < Fragment.ACTIVITY_CREATED) {
-                        if (DEBUG) Log.v(TAG, "movefrom CONTENT: " + f);
+                        if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
                         if (f.mView != null) {
                             // Need to save the current view state if not
                             // done already.
@@ -971,32 +977,36 @@
         if (mAdded == null) {
             mAdded = new ArrayList<Fragment>();
         }
-        mAdded.add(fragment);
-        makeActive(fragment);
         if (DEBUG) Log.v(TAG, "add: " + fragment);
-        fragment.mAdded = true;
-        fragment.mRemoving = false;
-        if (fragment.mHasMenu) {
-            mNeedMenuInvalidate = true;
-        }
-        if (moveToStateNow) {
-            moveToState(fragment);
+        makeActive(fragment);
+        if (!fragment.mDetached) {
+            mAdded.add(fragment);
+            fragment.mAdded = true;
+            fragment.mRemoving = false;
+            if (fragment.mHasMenu) {
+                mNeedMenuInvalidate = true;
+            }
+            if (moveToStateNow) {
+                moveToState(fragment);
+            }
         }
     }
     
     public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
         if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
-        mAdded.remove(fragment);
-        final boolean inactive = fragment.mBackStackNesting <= 0;
-        if (fragment.mHasMenu) {
-            mNeedMenuInvalidate = true;
-        }
-        fragment.mAdded = false;
-        fragment.mRemoving = true;
-        moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
-                transition, transitionStyle);
-        if (inactive) {
-            makeInactive(fragment);
+        final boolean inactive = !fragment.isInBackStack();
+        if (!fragment.mDetached || inactive) {
+            mAdded.remove(fragment);
+            if (fragment.mHasMenu) {
+                mNeedMenuInvalidate = true;
+            }
+            fragment.mAdded = false;
+            fragment.mRemoving = true;
+            moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
+                    transition, transitionStyle);
+            if (inactive) {
+                makeInactive(fragment);
+            }
         }
     }
     
@@ -1052,6 +1062,39 @@
         }
     }
     
+    public void detachFragment(Fragment fragment, int transition, int transitionStyle) {
+        if (DEBUG) Log.v(TAG, "detach: " + fragment);
+        if (!fragment.mDetached) {
+            fragment.mDetached = true;
+            if (fragment.mAdded) {
+                // We are not already in back stack, so need to remove the fragment.
+                mAdded.remove(fragment);
+                if (fragment.mHasMenu) {
+                    mNeedMenuInvalidate = true;
+                }
+                fragment.mAdded = false;
+                fragment.mRemoving = true;
+                moveToState(fragment, Fragment.CREATED, transition, transitionStyle);
+            }
+        }
+    }
+
+    public void attachFragment(Fragment fragment, int transition, int transitionStyle) {
+        if (DEBUG) Log.v(TAG, "attach: " + fragment);
+        if (fragment.mDetached) {
+            fragment.mDetached = false;
+            if (!fragment.mAdded) {
+                mAdded.add(fragment);
+                fragment.mAdded = true;
+                fragment.mRemoving = false;
+                if (fragment.mHasMenu) {
+                    mNeedMenuInvalidate = true;
+                }
+                moveToState(fragment, mCurState, transition, transitionStyle);
+            }
+        }
+    }
+
     public Fragment findFragmentById(int id) {
         if (mActive != null) {
             // First look through added fragments.
@@ -1594,7 +1637,7 @@
     }
     
     public void dispatchStop() {
-        moveToState(Fragment.ACTIVITY_CREATED, false);
+        moveToState(Fragment.STOPPED, false);
     }
     
     public void dispatchDestroy() {
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 68600b3..c1f3cd6 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -87,6 +87,31 @@
     public abstract FragmentTransaction show(Fragment fragment);
 
     /**
+     * Detach the given fragment from the UI.  This is the same state as
+     * when it is put on the back stack: the fragment is removed from
+     * the UI, however its state is still being actively managed by the
+     * fragment manager.  When going into this state its view hierarchy
+     * is destroyed.
+     *
+     * @param fragment The fragment to be detached.
+     *
+     * @return Returns the same FragmentTransaction instance.
+     */
+    public abstract FragmentTransaction detach(Fragment fragment);
+
+    /**
+     * Re-attach a fragment after it had previously been deatched from
+     * the UI with {@link #detach(Fragment)}.  This
+     * causes its view hierarchy to be re-created, attached to the UI,
+     * and displayed.
+     *
+     * @param fragment The fragment to be attached.
+     *
+     * @return Returns the same FragmentTransaction instance.
+     */
+    public abstract FragmentTransaction attach(Fragment fragment);
+
+    /**
      * @return <code>true</code> if this transaction contains no operations,
      * <code>false</code> otherwise.
      */
diff --git a/core/java/android/app/ListFragment.java b/core/java/android/app/ListFragment.java
index 6e2f4b6..a5ee26c 100644
--- a/core/java/android/app/ListFragment.java
+++ b/core/java/android/app/ListFragment.java
@@ -195,11 +195,11 @@
     }
 
     /**
-     * Attach to list view once Fragment is ready to run.
+     * Attach to list view once the view hierarchy has been created.
      */
     @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
         ensureList();
     }
 
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index f4693c2..56f236d 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -26,8 +26,8 @@
 import android.server.BluetoothService;
 import android.util.Log;
 
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
 
 import java.util.Set;
 
@@ -57,7 +57,7 @@
  * Todo(): Write tests for this class, when the Android Mock support is completed.
  * @hide
  */
-public final class BluetoothDeviceProfileState extends HierarchicalStateMachine {
+public final class BluetoothDeviceProfileState extends StateMachine {
     private static final String TAG = "BluetoothDeviceProfileState";
     private static final boolean DBG = false;
 
@@ -235,16 +235,16 @@
         }
     }
 
-    private class BondedDevice extends HierarchicalState {
+    private class BondedDevice extends State {
         @Override
-        protected void enter() {
+        public void enter() {
             Log.i(TAG, "Entering ACL Connected state with: " + getCurrentMessage().what);
             Message m = new Message();
             m.copyFrom(getCurrentMessage());
             sendMessageAtFrontOfQueue(m);
         }
         @Override
-        protected boolean processMessage(Message message) {
+        public boolean processMessage(Message message) {
             log("ACL Connected State -> Processing Message: " + message.what);
             switch(message.what) {
                 case CONNECT_HFP_OUTGOING:
@@ -353,12 +353,12 @@
         }
     }
 
-    private class OutgoingHandsfree extends HierarchicalState {
+    private class OutgoingHandsfree extends State {
         private boolean mStatus = false;
         private int mCommand;
 
         @Override
-        protected void enter() {
+        public void enter() {
             Log.i(TAG, "Entering OutgoingHandsfree state with: " + getCurrentMessage().what);
             mCommand = getCurrentMessage().what;
             if (mCommand != CONNECT_HFP_OUTGOING &&
@@ -374,7 +374,7 @@
         }
 
         @Override
-        protected boolean processMessage(Message message) {
+        public boolean processMessage(Message message) {
             log("OutgoingHandsfree State -> Processing Message: " + message.what);
             Message deferMsg = new Message();
             int command = message.what;
@@ -466,12 +466,12 @@
         }
     }
 
-    private class IncomingHandsfree extends HierarchicalState {
+    private class IncomingHandsfree extends State {
         private boolean mStatus = false;
         private int mCommand;
 
         @Override
-        protected void enter() {
+        public void enter() {
             Log.i(TAG, "Entering IncomingHandsfree state with: " + getCurrentMessage().what);
             mCommand = getCurrentMessage().what;
             if (mCommand != CONNECT_HFP_INCOMING &&
@@ -487,7 +487,7 @@
         }
 
         @Override
-        protected boolean processMessage(Message message) {
+        public boolean processMessage(Message message) {
             log("IncomingHandsfree State -> Processing Message: " + message.what);
             switch(message.what) {
                 case CONNECT_HFP_OUTGOING:
@@ -546,12 +546,12 @@
         }
     }
 
-    private class OutgoingA2dp extends HierarchicalState {
+    private class OutgoingA2dp extends State {
         private boolean mStatus = false;
         private int mCommand;
 
         @Override
-        protected void enter() {
+        public void enter() {
             Log.i(TAG, "Entering OutgoingA2dp state with: " + getCurrentMessage().what);
             mCommand = getCurrentMessage().what;
             if (mCommand != CONNECT_A2DP_OUTGOING &&
@@ -567,7 +567,7 @@
         }
 
         @Override
-        protected boolean processMessage(Message message) {
+        public boolean processMessage(Message message) {
             log("OutgoingA2dp State->Processing Message: " + message.what);
             Message deferMsg = new Message();
             switch(message.what) {
@@ -656,12 +656,12 @@
         }
     }
 
-    private class IncomingA2dp extends HierarchicalState {
+    private class IncomingA2dp extends State {
         private boolean mStatus = false;
         private int mCommand;
 
         @Override
-        protected void enter() {
+        public void enter() {
             Log.i(TAG, "Entering IncomingA2dp state with: " + getCurrentMessage().what);
             mCommand = getCurrentMessage().what;
             if (mCommand != CONNECT_A2DP_INCOMING &&
@@ -677,7 +677,7 @@
         }
 
         @Override
-        protected boolean processMessage(Message message) {
+        public boolean processMessage(Message message) {
             log("IncomingA2dp State->Processing Message: " + message.what);
             switch(message.what) {
                 case CONNECT_HFP_OUTGOING:
@@ -734,12 +734,12 @@
     }
 
 
-    private class OutgoingHid extends HierarchicalState {
+    private class OutgoingHid extends State {
         private boolean mStatus = false;
         private int mCommand;
 
         @Override
-        protected void enter() {
+        public void enter() {
             log("Entering OutgoingHid state with: " + getCurrentMessage().what);
             mCommand = getCurrentMessage().what;
             if (mCommand != CONNECT_HID_OUTGOING &&
@@ -751,7 +751,7 @@
         }
 
         @Override
-        protected boolean processMessage(Message message) {
+        public boolean processMessage(Message message) {
             log("OutgoingHid State->Processing Message: " + message.what);
             Message deferMsg = new Message();
             switch(message.what) {
@@ -815,12 +815,12 @@
         }
     }
 
-  private class IncomingHid extends HierarchicalState {
+  private class IncomingHid extends State {
       private boolean mStatus = false;
       private int mCommand;
 
       @Override
-      protected void enter() {
+    public void enter() {
           log("Entering IncomingHid state with: " + getCurrentMessage().what);
           mCommand = getCurrentMessage().what;
           if (mCommand != CONNECT_HID_INCOMING &&
@@ -832,7 +832,7 @@
       }
 
       @Override
-      protected boolean processMessage(Message message) {
+    public boolean processMessage(Message message) {
           log("IncomingHid State->Processing Message: " + message.what);
           Message deferMsg = new Message();
           switch(message.what) {
diff --git a/core/java/android/bluetooth/BluetoothProfileState.java b/core/java/android/bluetooth/BluetoothProfileState.java
index 18060a0..98afdb8 100644
--- a/core/java/android/bluetooth/BluetoothProfileState.java
+++ b/core/java/android/bluetooth/BluetoothProfileState.java
@@ -22,8 +22,8 @@
 import android.os.Message;
 import android.util.Log;
 
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
 
 /**
  * This state machine is used to serialize the connections
@@ -39,7 +39,7 @@
  * @hide
  */
 
-public class BluetoothProfileState extends HierarchicalStateMachine {
+public class BluetoothProfileState extends StateMachine {
     private static final boolean DBG = true;
     private static final String TAG = "BluetoothProfileState";
 
@@ -101,15 +101,15 @@
         context.registerReceiver(mBroadcastReceiver, filter);
     }
 
-    private class StableState extends HierarchicalState {
+    private class StableState extends State {
         @Override
-        protected void enter() {
+        public void enter() {
             log("Entering Stable State");
             mPendingDevice = null;
         }
 
         @Override
-        protected boolean processMessage(Message msg) {
+        public boolean processMessage(Message msg) {
             if (msg.what != TRANSITION_TO_STABLE) {
                 transitionTo(mPendingCommandState);
             }
@@ -117,15 +117,15 @@
         }
     }
 
-    private class PendingCommandState extends HierarchicalState {
+    private class PendingCommandState extends State {
         @Override
-        protected void enter() {
+        public void enter() {
             log("Entering PendingCommandState State");
             dispatchMessage(getCurrentMessage());
         }
 
         @Override
-        protected boolean processMessage(Message msg) {
+        public boolean processMessage(Message msg) {
             if (msg.what == TRANSITION_TO_STABLE) {
                 transitionTo(mStableState);
             } else {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a675618..2f4a4bb 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1505,6 +1505,13 @@
         public static final Uri DEFAULT_ALARM_ALERT_URI = getUriFor(ALARM_ALERT);
 
         /**
+         * Persistent store for the system default media button event receiver.
+         *
+         * @hide
+         */
+        public static final String MEDIA_BUTTON_RECEIVER = "media_button_receiver";
+
+        /**
          * Setting to enable Auto Replace (AutoText) in text editors. 1 = On, 0 = Off
          */
         public static final String TEXT_AUTO_REPLACE = "auto_replace";
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 2add7b5..e247df8 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -1066,7 +1066,8 @@
     public List<EngineInfo> getEngines() {
         PackageManager pm = mContext.getPackageManager();
         Intent intent = new Intent(Engine.INTENT_ACTION_TTS_SERVICE);
-        List<ResolveInfo> resolveInfos = pm.queryIntentServices(intent, 0);
+        List<ResolveInfo> resolveInfos =
+                pm.queryIntentServices(intent, PackageManager.MATCH_DEFAULT_ONLY);
         if (resolveInfos == null) return Collections.emptyList();
         List<EngineInfo> engines = new ArrayList<EngineInfo>(resolveInfos.size());
         for (ResolveInfo resolveInfo : resolveInfos) {
diff --git a/core/java/com/android/internal/util/HierarchicalState.java b/core/java/com/android/internal/util/IState.java
similarity index 61%
rename from core/java/com/android/internal/util/HierarchicalState.java
rename to core/java/com/android/internal/util/IState.java
index b37f46c..056f8e9 100644
--- a/core/java/com/android/internal/util/HierarchicalState.java
+++ b/core/java/com/android/internal/util/IState.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2009 The Android Open Source Project
+ * 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.
@@ -21,21 +21,29 @@
 /**
  * {@hide}
  *
- * The class for implementing states in a HierarchicalStateMachine
+ * The interface for implementing states in a {@link StateMachine}
  */
-public class HierarchicalState {
+public interface IState {
 
     /**
-     * Constructor
+     * Returned by processMessage to indicate the the message was processed.
      */
-    protected HierarchicalState() {
-    }
+    static final boolean HANDLED = true;
+
+    /**
+     * Returned by processMessage to indicate the the message was NOT processed.
+     */
+    static final boolean NOT_HANDLED = false;
 
     /**
      * Called when a state is entered.
      */
-    protected void enter() {
-    }
+    void enter();
+
+    /**
+     * Called when a state is exited.
+     */
+    void exit();
 
     /**
      * Called when a message is to be processed by the
@@ -49,28 +57,15 @@
      * be processed until this routine returns.
      *
      * @param msg to process
-     * @return true if processing has completed and false
-     *         if the parent state's processMessage should
-     *         be invoked.
+     * @return HANDLED if processing has completed and NOT_HANDLED
+     *         if the message wasn't processed.
      */
-    protected boolean processMessage(Message msg) {
-        return false;
-    }
+    boolean processMessage(Message msg);
 
     /**
-     * Called when a state is exited.
+     * Name of State for debugging purposes.
+     *
+     * @return name of state.
      */
-    protected void exit() {
-    }
-
-    /**
-     * @return name of state, but default returns the states
-     * class name. An instance name would be better but requiring
-     * it seems unnecessary.
-     */
-    public String getName() {
-        String name = getClass().getName();
-        int lastDollar = name.lastIndexOf('$');
-        return name.substring(lastDollar + 1);
-    }
+    String getName();
 }
diff --git a/core/java/com/android/internal/util/State.java b/core/java/com/android/internal/util/State.java
new file mode 100644
index 0000000..3eadff5
--- /dev/null
+++ b/core/java/com/android/internal/util/State.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import android.os.Message;
+
+/**
+ * {@hide}
+ *
+ * The class for implementing states in a StateMachine
+ */
+public class State implements IState {
+
+    /**
+     * Constructor
+     */
+    protected State() {
+    }
+
+    /* (non-Javadoc)
+     * @see com.android.internal.util.IState#enter()
+     */
+    @Override
+    public void enter() {
+    }
+
+    /* (non-Javadoc)
+     * @see com.android.internal.util.IState#exit()
+     */
+    @Override
+    public void exit() {
+    }
+
+    /* (non-Javadoc)
+     * @see com.android.internal.util.IState#processMessage(android.os.Message)
+     */
+    @Override
+    public boolean processMessage(Message msg) {
+        return false;
+    }
+
+    /**
+     * Name of State for debugging purposes.
+     *
+     * This default implementation returns the class name, returning
+     * the instance name would better in cases where a State class
+     * is used for multiple states. But normally there is one class per
+     * state and the class name is sufficient and easy to get. You may
+     * want to provide a setName or some other mechanism for setting
+     * another name if the class name is not appropriate.
+     *
+     * @see com.android.internal.util.IState#processMessage(android.os.Message)
+     */
+    @Override
+    public String getName() {
+        String name = getClass().getName();
+        int lastDollar = name.lastIndexOf('$');
+        return name.substring(lastDollar + 1);
+    }
+}
diff --git a/core/java/com/android/internal/util/HierarchicalStateMachine.java b/core/java/com/android/internal/util/StateMachine.java
similarity index 85%
rename from core/java/com/android/internal/util/HierarchicalStateMachine.java
rename to core/java/com/android/internal/util/StateMachine.java
index f6aa184..cbe72dd 100644
--- a/core/java/com/android/internal/util/HierarchicalStateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -29,10 +29,10 @@
 /**
  * {@hide}
  *
- * <p>A hierarchical state machine is a state machine which processes messages
+ * <p>The state machine defined here is a hierarchical state machine which processes messages
  * and can have states arranged hierarchically.</p>
  * 
- * <p>A state is a <code>HierarchicalState</code> object and must implement
+ * <p>A state is a <code>State</code> object and must implement
  * <code>processMessage</code> and optionally <code>enter/exit/getName</code>.
  * The enter/exit methods are equivalent to the construction and destruction
  * in Object Oriented programming and are used to perform initialization and
@@ -76,7 +76,7 @@
  * will exit the current state and its parent and then exit from the controlling thread
  * and no further messages will be processed.</p>
  *
- * <p>In addition to <code>processMessage</code> each <code>HierarchicalState</code> has
+ * <p>In addition to <code>processMessage</code> each <code>State</code> has
  * an <code>enter</code> method and <code>exit</exit> method which may be overridden.</p>
  *
  * <p>Since the states are arranged in a hierarchy transitioning to a new state
@@ -122,11 +122,11 @@
  * mS4.enter. The new list of active states is mP0, mP1, mS2 and mS4. So
  * when the next message is received mS4.processMessage will be invoked.</p>
  *
- * <p>Now for some concrete examples, here is the canonical HelloWorld as an HSM.
+ * <p>Now for some concrete examples, here is the canonical HelloWorld as a state machine.
  * It responds with "Hello World" being printed to the log for every message.</p>
 <code>
-class HelloWorld extends HierarchicalStateMachine {
-    Hsm1(String name) {
+class HelloWorld extends StateMachine {
+    HelloWorld(String name) {
         super(name);
         addState(mState1);
         setInitialState(mState1);
@@ -138,7 +138,7 @@
         return hw;
     }
 
-    class State1 extends HierarchicalState {
+    class State1 extends State {
         &#64;Override public boolean processMessage(Message message) {
             Log.d(TAG, "Hello World");
             return HANDLED;
@@ -221,9 +221,9 @@
      }
 }
 </code>
- * <p>The implementation is below and also in HierarchicalStateMachineTest:</p>
+ * <p>The implementation is below and also in StateMachineTest:</p>
 <code>
-class Hsm1 extends HierarchicalStateMachine {
+class Hsm1 extends StateMachine {
     private static final String TAG = "hsm1";
 
     public static final int CMD_1 = 1;
@@ -255,7 +255,7 @@
         Log.d(TAG, "ctor X");
     }
 
-    class P1 extends HierarchicalState {
+    class P1 extends State {
         &#64;Override public void enter() {
             Log.d(TAG, "mP1.enter");
         }
@@ -282,7 +282,7 @@
         }
     }
 
-    class S1 extends HierarchicalState {
+    class S1 extends State {
         &#64;Override public void enter() {
             Log.d(TAG, "mS1.enter");
         }
@@ -302,7 +302,7 @@
         }
     }
 
-    class S2 extends HierarchicalState {
+    class S2 extends State {
         &#64;Override public void enter() {
             Log.d(TAG, "mS2.enter");
         }
@@ -330,7 +330,7 @@
         }
     }
 
-    class P2 extends HierarchicalState {
+    class P2 extends State {
         &#64;Override public void enter() {
             Log.d(TAG, "mP2.enter");
             sendMessage(obtainMessage(CMD_5));
@@ -409,16 +409,16 @@
 D/hsm1    ( 1999): halting
 </code>
  */
-public class HierarchicalStateMachine {
+public class StateMachine {
 
-    private static final String TAG = "HierarchicalStateMachine";
+    private static final String TAG = "StateMachine";
     private String mName;
 
     /** Message.what value when quitting */
-    public static final int HSM_QUIT_CMD = -1;
+    public static final int SM_QUIT_CMD = -1;
 
     /** Message.what value when initializing */
-    public static final int HSM_INIT_CMD = -1;
+    public static final int SM_INIT_CMD = -1;
 
     /**
      * Convenience constant that maybe returned by processMessage
@@ -441,8 +441,8 @@
      */
     public static class ProcessedMessageInfo {
         private int what;
-        private HierarchicalState state;
-        private HierarchicalState orgState;
+        private State state;
+        private State orgState;
 
         /**
          * Constructor
@@ -451,7 +451,7 @@
          * @param orgState is the first state the received the message but
          * did not processes the message.
          */
-        ProcessedMessageInfo(Message message, HierarchicalState state, HierarchicalState orgState) {
+        ProcessedMessageInfo(Message message, State state, State orgState) {
             update(message, state, orgState);
         }
 
@@ -461,7 +461,7 @@
          * @param orgState is the first state the received the message but
          * did not processes the message.
          */
-        public void update(Message message, HierarchicalState state, HierarchicalState orgState) {
+        public void update(Message message, State state, State orgState) {
             this.what = message.what;
             this.state = state;
             this.orgState = orgState;
@@ -477,14 +477,14 @@
         /**
          * @return the state that handled this message
          */
-        public HierarchicalState getState() {
+        public State getState() {
             return state;
         }
 
         /**
          * @return the original state that received the message.
          */
-        public HierarchicalState getOriginalState() {
+        public State getOriginalState() {
             return orgState;
         }
 
@@ -593,7 +593,7 @@
          * @param orgState is the first state the received the message but
          * did not processes the message.
          */
-        void add(Message message, HierarchicalState state, HierarchicalState orgState) {
+        void add(Message message, State state, State orgState) {
             mCount += 1;
             if (mMessages.size() < mMaxSize) {
                 mMessages.add(new ProcessedMessageInfo(message, state, orgState));
@@ -608,7 +608,7 @@
         }
     }
 
-    private static class HsmHandler extends Handler {
+    private static class SmHandler extends Handler {
 
         /** The debug flag */
         private boolean mDbg = false;
@@ -643,8 +643,8 @@
         /** State used when state machine is quitting */
         private QuittingState mQuittingState = new QuittingState();
 
-        /** Reference to the HierarchicalStateMachine */
-        private HierarchicalStateMachine mHsm;
+        /** Reference to the StateMachine */
+        private StateMachine mSm;
 
         /**
          * Information about a state.
@@ -652,7 +652,7 @@
          */
         private class StateInfo {
             /** The state */
-            HierarchicalState state;
+            State state;
 
             /** The parent of this state, null if there is no parent */
             StateInfo parentStateInfo;
@@ -672,14 +672,14 @@
         }
 
         /** The map of all of the states in the state machine */
-        private HashMap<HierarchicalState, StateInfo> mStateInfo =
-            new HashMap<HierarchicalState, StateInfo>();
+        private HashMap<State, StateInfo> mStateInfo =
+            new HashMap<State, StateInfo>();
 
         /** The initial state that will process the first message */
-        private HierarchicalState mInitialState;
+        private State mInitialState;
 
         /** The destination state when transitionTo has been invoked */
-        private HierarchicalState mDestState;
+        private State mDestState;
 
         /** The list of deferred messages */
         private ArrayList<Message> mDeferredMessages = new ArrayList<Message>();
@@ -687,10 +687,10 @@
         /**
          * State entered when transitionToHaltingState is called.
          */
-        private class HaltingState extends HierarchicalState {
+        private class HaltingState extends State {
             @Override
             public boolean processMessage(Message msg) {
-                mHsm.haltedProcessMessage(msg);
+                mSm.haltedProcessMessage(msg);
                 return true;
             }
         }
@@ -698,7 +698,7 @@
         /**
          * State entered when a valid quit message is handled.
          */
-        private class QuittingState extends HierarchicalState {
+        private class QuittingState extends State {
             @Override
             public boolean processMessage(Message msg) {
                 return NOT_HANDLED;
@@ -745,7 +745,7 @@
              * the appropriate states. We loop on this to allow
              * enter and exit methods to use transitionTo.
              */
-            HierarchicalState destState = null;
+            State destState = null;
             while (mDestState != null) {
                 if (mDbg) Log.d(TAG, "handleMessage: new destination call exit");
 
@@ -785,11 +785,11 @@
                     /**
                      * We are quitting so ignore all messages.
                      */
-                    mHsm.quitting();
-                    if (mHsm.mHsmThread != null) {
+                    mSm.quitting();
+                    if (mSm.mSmThread != null) {
                         // If we made the thread then quit looper which stops the thread.
                         getLooper().quit();
-                        mHsm.mHsmThread = null;
+                        mSm.mSmThread = null;
                     }
                 } else if (destState == mHaltingState) {
                     /**
@@ -797,7 +797,7 @@
                      * state. All subsequent messages will be processed in
                      * in the halting state which invokes haltedProcessMessage(msg);
                      */
-                    mHsm.halting();
+                    mSm.halting();
                 }
             }
         }
@@ -833,7 +833,7 @@
              * starting at the first entry.
              */
             mIsConstructionCompleted = true;
-            mMsg = obtainMessage(HSM_INIT_CMD);
+            mMsg = obtainMessage(SM_INIT_CMD);
             invokeEnterMethods(0);
 
             /**
@@ -863,7 +863,7 @@
                     /**
                      * No parents left so it's not handled
                      */
-                    mHsm.unhandledMessage(msg);
+                    mSm.unhandledMessage(msg);
                     if (isQuit(msg)) {
                         transitionTo(mQuittingState);
                     }
@@ -878,7 +878,7 @@
              * Record that we processed the message
              */
             if (curStateInfo != null) {
-                HierarchicalState orgState = mStateStack[mStateStackTopIndex].state;
+                State orgState = mStateStack[mStateStackTopIndex].state;
                 mProcessedMessages.add(msg, curStateInfo.state, orgState);
             } else {
                 mProcessedMessages.add(msg, null, null);
@@ -892,7 +892,7 @@
         private final void invokeExitMethods(StateInfo commonStateInfo) {
             while ((mStateStackTopIndex >= 0) &&
                     (mStateStack[mStateStackTopIndex] != commonStateInfo)) {
-                HierarchicalState curState = mStateStack[mStateStackTopIndex].state;
+                State curState = mStateStack[mStateStackTopIndex].state;
                 if (mDbg) Log.d(TAG, "invokeExitMethods: " + curState.getName());
                 curState.exit();
                 mStateStack[mStateStackTopIndex].active = false;
@@ -934,7 +934,7 @@
          * reversing the order of the items on the temporary stack as
          * they are moved.
          *
-         * @return index into mStateState where entering needs to start
+         * @return index into mStateStack where entering needs to start
          */
         private final int moveTempStateStackToStateStack() {
             int startingIndex = mStateStackTopIndex + 1;
@@ -967,7 +967,7 @@
          * @return StateInfo of the common ancestor for the destState and
          * current state or null if there is no common parent.
          */
-        private final StateInfo setupTempStateStackWithStatesToEnter(HierarchicalState destState) {
+        private final StateInfo setupTempStateStackWithStatesToEnter(State destState) {
             /**
              * Search up the parent list of the destination state for an active
              * state. Use a do while() loop as the destState must always be entered
@@ -1019,7 +1019,7 @@
         /**
          * @return current state
          */
-        private final HierarchicalState getCurrentState() {
+        private final IState getCurrentState() {
             return mStateStack[mStateStackTopIndex].state;
         }
 
@@ -1032,7 +1032,7 @@
          * @param parent the parent of state
          * @return stateInfo for this state
          */
-        private final StateInfo addState(HierarchicalState state, HierarchicalState parent) {
+        private final StateInfo addState(State state, State parent) {
             if (mDbg) {
                 Log.d(TAG, "addStateInternal: E state=" + state.getName()
                         + ",parent=" + ((parent == null) ? "" : parent.getName()));
@@ -1067,29 +1067,29 @@
          * Constructor
          *
          * @param looper for dispatching messages
-         * @param hsm the hierarchical state machine
+         * @param sm the hierarchical state machine
          */
-        private HsmHandler(Looper looper, HierarchicalStateMachine hsm) {
+        private SmHandler(Looper looper, StateMachine sm) {
             super(looper);
-            mHsm = hsm;
+            mSm = sm;
 
             addState(mHaltingState, null);
             addState(mQuittingState, null);
         }
 
-        /** @see HierarchicalStateMachine#setInitialState(HierarchicalState) */
-        private final void setInitialState(HierarchicalState initialState) {
+        /** @see StateMachine#setInitialState(State) */
+        private final void setInitialState(State initialState) {
             if (mDbg) Log.d(TAG, "setInitialState: initialState" + initialState.getName());
             mInitialState = initialState;
         }
 
-        /** @see HierarchicalStateMachine#transitionTo(HierarchicalState) */
-        private final void transitionTo(HierarchicalState destState) {
-            if (mDbg) Log.d(TAG, "StateMachine.transitionTo EX destState" + destState.getName());
-            mDestState = destState;
+        /** @see StateMachine#transitionTo(IState) */
+        private final void transitionTo(IState destState) {
+            mDestState = (State) destState;
+            if (mDbg) Log.d(TAG, "StateMachine.transitionTo EX destState" + mDestState.getName());
         }
 
-        /** @see HierarchicalStateMachine#deferMessage(Message) */
+        /** @see StateMachine#deferMessage(Message) */
         private final void deferMessage(Message msg) {
             if (mDbg) Log.d(TAG, "deferMessage: msg=" + msg.what);
 
@@ -1100,51 +1100,51 @@
             mDeferredMessages.add(newMsg);
         }
 
-        /** @see HierarchicalStateMachine#deferMessage(Message) */
+        /** @see StateMachine#deferMessage(Message) */
         private final void quit() {
             if (mDbg) Log.d(TAG, "quit:");
-            sendMessage(obtainMessage(HSM_QUIT_CMD, mQuitObj));
+            sendMessage(obtainMessage(SM_QUIT_CMD, mQuitObj));
         }
 
-        /** @see HierarchicalStateMachine#isQuit(Message) */
+        /** @see StateMachine#isQuit(Message) */
         private final boolean isQuit(Message msg) {
-            return (msg.what == HSM_QUIT_CMD) && (msg.obj == mQuitObj);
+            return (msg.what == SM_QUIT_CMD) && (msg.obj == mQuitObj);
         }
 
-        /** @see HierarchicalStateMachine#isDbg() */
+        /** @see StateMachine#isDbg() */
         private final boolean isDbg() {
             return mDbg;
         }
 
-        /** @see HierarchicalStateMachine#setDbg(boolean) */
+        /** @see StateMachine#setDbg(boolean) */
         private final void setDbg(boolean dbg) {
             mDbg = dbg;
         }
 
-        /** @see HierarchicalStateMachine#setProcessedMessagesSize(int) */
+        /** @see StateMachine#setProcessedMessagesSize(int) */
         private final void setProcessedMessagesSize(int maxSize) {
             mProcessedMessages.setSize(maxSize);
         }
 
-        /** @see HierarchicalStateMachine#getProcessedMessagesSize() */
+        /** @see StateMachine#getProcessedMessagesSize() */
         private final int getProcessedMessagesSize() {
             return mProcessedMessages.size();
         }
 
-        /** @see HierarchicalStateMachine#getProcessedMessagesCount() */
+        /** @see StateMachine#getProcessedMessagesCount() */
         private final int getProcessedMessagesCount() {
             return mProcessedMessages.count();
         }
 
-        /** @see HierarchicalStateMachine#getProcessedMessageInfo(int) */
+        /** @see StateMachine#getProcessedMessageInfo(int) */
         private final ProcessedMessageInfo getProcessedMessageInfo(int index) {
             return mProcessedMessages.get(index);
         }
 
     }
 
-    private HsmHandler mHsmHandler;
-    private HandlerThread mHsmThread;
+    private SmHandler mSmHandler;
+    private HandlerThread mSmThread;
 
     /**
      * Initialize.
@@ -1154,28 +1154,28 @@
      */
     private void initStateMachine(String name, Looper looper) {
         mName = name;
-        mHsmHandler = new HsmHandler(looper, this);
+        mSmHandler = new SmHandler(looper, this);
     }
 
     /**
-     * Constructor creates an HSM with its own thread.
+     * Constructor creates a StateMachine with its own thread.
      *
      * @param name of the state machine
      */
-    protected HierarchicalStateMachine(String name) {
-        mHsmThread = new HandlerThread(name);
-        mHsmThread.start();
-        Looper looper = mHsmThread.getLooper();
+    protected StateMachine(String name) {
+        mSmThread = new HandlerThread(name);
+        mSmThread.start();
+        Looper looper = mSmThread.getLooper();
 
         initStateMachine(name, looper);
     }
 
     /**
-     * Constructor creates an HSMStateMachine using the looper.
+     * Constructor creates an StateMachine using the looper.
      *
      * @param name of the state machine
      */
-    protected HierarchicalStateMachine(String name, Looper looper) {
+    protected StateMachine(String name, Looper looper) {
         initStateMachine(name, looper);
     }
 
@@ -1184,30 +1184,30 @@
      * @param state the state to add
      * @param parent the parent of state
      */
-    protected final void addState(HierarchicalState state, HierarchicalState parent) {
-        mHsmHandler.addState(state, parent);
+    protected final void addState(State state, State parent) {
+        mSmHandler.addState(state, parent);
     }
 
     /**
      * @return current message
      */
     protected final Message getCurrentMessage() {
-        return mHsmHandler.getCurrentMessage();
+        return mSmHandler.getCurrentMessage();
     }
 
     /**
      * @return current state
      */
-    protected final HierarchicalState getCurrentState() {
-        return mHsmHandler.getCurrentState();
+    protected final IState getCurrentState() {
+        return mSmHandler.getCurrentState();
     }
 
     /**
      * Add a new state to the state machine, parent will be null
      * @param state to add
      */
-    protected final void addState(HierarchicalState state) {
-        mHsmHandler.addState(state, null);
+    protected final void addState(State state) {
+        mSmHandler.addState(state, null);
     }
 
     /**
@@ -1216,8 +1216,8 @@
      *
      * @param initialState is the state which will receive the first message.
      */
-    protected final void setInitialState(HierarchicalState initialState) {
-        mHsmHandler.setInitialState(initialState);
+    protected final void setInitialState(State initialState) {
+        mSmHandler.setInitialState(initialState);
     }
 
     /**
@@ -1228,8 +1228,8 @@
      *
      * @param destState will be the state that receives the next message.
      */
-    protected final void transitionTo(HierarchicalState destState) {
-        mHsmHandler.transitionTo(destState);
+    protected final void transitionTo(IState destState) {
+        mSmHandler.transitionTo(destState);
     }
 
     /**
@@ -1240,7 +1240,7 @@
      * will be called.
      */
     protected final void transitionToHaltingState() {
-        mHsmHandler.transitionTo(mHsmHandler.mHaltingState);
+        mSmHandler.transitionTo(mSmHandler.mHaltingState);
     }
 
     /**
@@ -1253,7 +1253,7 @@
      * @param msg is deferred until the next transition.
      */
     protected final void deferMessage(Message msg) {
-        mHsmHandler.deferMessage(msg);
+        mSmHandler.deferMessage(msg);
     }
 
 
@@ -1263,7 +1263,7 @@
      * @param msg that couldn't be handled.
      */
     protected void unhandledMessage(Message msg) {
-        if (mHsmHandler.mDbg) Log.e(TAG, mName + " - unhandledMessage: msg.what=" + msg.what);
+        if (mSmHandler.mDbg) Log.e(TAG, mName + " - unhandledMessage: msg.what=" + msg.what);
     }
 
     /**
@@ -1276,15 +1276,15 @@
     /**
      * This will be called once after handling a message that called
      * transitionToHalting. All subsequent messages will invoke
-     * {@link HierarchicalStateMachine#haltedProcessMessage(Message)}
+     * {@link StateMachine#haltedProcessMessage(Message)}
      */
     protected void halting() {
     }
 
     /**
      * This will be called once after a quit message that was NOT handled by
-     * the derived HSM. The HSM will stop and any subsequent messages will be
-     * ignored. In addition, if this HSM created the thread, the thread will
+     * the derived StateMachine. The StateMachine will stop and any subsequent messages will be
+     * ignored. In addition, if this StateMachine created the thread, the thread will
      * be stopped after this method returns.
      */
     protected void quitting() {
@@ -1303,35 +1303,35 @@
      * @param maxSize number of messages to maintain at anyone time.
      */
     public final void setProcessedMessagesSize(int maxSize) {
-        mHsmHandler.setProcessedMessagesSize(maxSize);
+        mSmHandler.setProcessedMessagesSize(maxSize);
     }
 
     /**
      * @return number of messages processed
      */
     public final int getProcessedMessagesSize() {
-        return mHsmHandler.getProcessedMessagesSize();
+        return mSmHandler.getProcessedMessagesSize();
     }
 
     /**
      * @return the total number of messages processed
      */
     public final int getProcessedMessagesCount() {
-        return mHsmHandler.getProcessedMessagesCount();
+        return mSmHandler.getProcessedMessagesCount();
     }
 
     /**
      * @return a processed message information
      */
     public final ProcessedMessageInfo getProcessedMessageInfo(int index) {
-        return mHsmHandler.getProcessedMessageInfo(index);
+        return mSmHandler.getProcessedMessageInfo(index);
     }
 
     /**
      * @return Handler
      */
     public final Handler getHandler() {
-        return mHsmHandler;
+        return mSmHandler;
     }
 
     /**
@@ -1341,7 +1341,7 @@
      */
     public final Message obtainMessage()
     {
-        return Message.obtain(mHsmHandler);
+        return Message.obtain(mSmHandler);
     }
 
     /**
@@ -1351,7 +1351,7 @@
      * @return message
      */
     public final Message obtainMessage(int what) {
-        return Message.obtain(mHsmHandler, what);
+        return Message.obtain(mSmHandler, what);
     }
 
     /**
@@ -1364,7 +1364,7 @@
      */
     public final Message obtainMessage(int what, Object obj)
     {
-        return Message.obtain(mHsmHandler, what, obj);
+        return Message.obtain(mSmHandler, what, obj);
     }
 
     /**
@@ -1378,7 +1378,7 @@
      */
     public final Message obtainMessage(int what, int arg1, int arg2)
     {
-        return Message.obtain(mHsmHandler, what, arg1, arg2);
+        return Message.obtain(mSmHandler, what, arg1, arg2);
     }
 
     /**
@@ -1393,107 +1393,107 @@
      */
     public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
     {
-        return Message.obtain(mHsmHandler, what, arg1, arg2, obj);
+        return Message.obtain(mSmHandler, what, arg1, arg2, obj);
     }
 
     /**
      * Enqueue a message to this state machine.
      */
     public final void sendMessage(int what) {
-        mHsmHandler.sendMessage(obtainMessage(what));
+        mSmHandler.sendMessage(obtainMessage(what));
     }
 
     /**
      * Enqueue a message to this state machine.
      */
     public final void sendMessage(int what, Object obj) {
-        mHsmHandler.sendMessage(obtainMessage(what,obj));
+        mSmHandler.sendMessage(obtainMessage(what,obj));
     }
 
     /**
      * Enqueue a message to this state machine.
      */
     public final void sendMessage(Message msg) {
-        mHsmHandler.sendMessage(msg);
+        mSmHandler.sendMessage(msg);
     }
 
     /**
      * Enqueue a message to this state machine after a delay.
      */
     public final void sendMessageDelayed(int what, long delayMillis) {
-        mHsmHandler.sendMessageDelayed(obtainMessage(what), delayMillis);
+        mSmHandler.sendMessageDelayed(obtainMessage(what), delayMillis);
     }
 
     /**
      * Enqueue a message to this state machine after a delay.
      */
     public final void sendMessageDelayed(int what, Object obj, long delayMillis) {
-        mHsmHandler.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
+        mSmHandler.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
     }
 
     /**
      * Enqueue a message to this state machine after a delay.
      */
     public final void sendMessageDelayed(Message msg, long delayMillis) {
-        mHsmHandler.sendMessageDelayed(msg, delayMillis);
+        mSmHandler.sendMessageDelayed(msg, delayMillis);
     }
 
     /**
      * Enqueue a message to the front of the queue for this state machine.
-     * Protected, may only be called by instances of HierarchicalStateMachine.
+     * Protected, may only be called by instances of StateMachine.
      */
     protected final void sendMessageAtFrontOfQueue(int what, Object obj) {
-        mHsmHandler.sendMessageAtFrontOfQueue(obtainMessage(what, obj));
+        mSmHandler.sendMessageAtFrontOfQueue(obtainMessage(what, obj));
     }
 
     /**
      * Enqueue a message to the front of the queue for this state machine.
-     * Protected, may only be called by instances of HierarchicalStateMachine.
+     * Protected, may only be called by instances of StateMachine.
      */
     protected final void sendMessageAtFrontOfQueue(int what) {
-        mHsmHandler.sendMessageAtFrontOfQueue(obtainMessage(what));
+        mSmHandler.sendMessageAtFrontOfQueue(obtainMessage(what));
     }
 
     /**
      * Enqueue a message to the front of the queue for this state machine.
-     * Protected, may only be called by instances of HierarchicalStateMachine.
+     * Protected, may only be called by instances of StateMachine.
      */
     protected final void sendMessageAtFrontOfQueue(Message msg) {
-        mHsmHandler.sendMessageAtFrontOfQueue(msg);
+        mSmHandler.sendMessageAtFrontOfQueue(msg);
     }
 
     /**
      * Removes a message from the message queue.
-     * Protected, may only be called by instances of HierarchicalStateMachine.
+     * Protected, may only be called by instances of StateMachine.
      */
     protected final void removeMessages(int what) {
-        mHsmHandler.removeMessages(what);
+        mSmHandler.removeMessages(what);
     }
 
     /**
      * Conditionally quit the looper and stop execution.
      *
-     * This sends the HSM_QUIT_MSG to the state machine and
+     * This sends the SM_QUIT_MSG to the state machine and
      * if not handled by any state's processMessage then the
      * state machine will be stopped and no further messages
      * will be processed.
      */
     public final void quit() {
-        mHsmHandler.quit();
+        mSmHandler.quit();
     }
 
     /**
      * @return ture if msg is quit
      */
     protected final boolean isQuit(Message msg) {
-        return mHsmHandler.isQuit(msg);
+        return mSmHandler.isQuit(msg);
     }
 
     /**
      * @return if debugging is enabled
      */
     public boolean isDbg() {
-        return mHsmHandler.isDbg();
+        return mSmHandler.isDbg();
     }
 
     /**
@@ -1502,7 +1502,7 @@
      * @param dbg is true to enable debugging.
      */
     public void setDbg(boolean dbg) {
-        mHsmHandler.setDbg(dbg);
+        mSmHandler.setDbg(dbg);
     }
 
     /**
@@ -1510,6 +1510,6 @@
      */
     public void start() {
         /** Send the complete construction message */
-        mHsmHandler.completeConstruction();
+        mSmHandler.completeConstruction();
     }
 }
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index b2caa98..207c72f 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -756,26 +756,36 @@
         env->ReleaseStringChars(text, textArray);
     }
 
+    static void logGlyphs(sp<TextLayoutCacheValue> value) {
+        LOGD("drawTextWithGlyphs -- got glyphs - count=%d", value->getGlyphsCount());
+        for (size_t i = 0; i < value->getGlyphsCount(); i++) {
+            LOGD("                          glyphs[%d]=%d", i, value->getGlyphs()[i]);
+        }
+    }
+
+    static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
+            int start, int end,
+            jfloat x, jfloat y, int flags, SkPaint* paint) {
+
+        jint count = end - start;
+        sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
+                paint, textArray, start, count, count, flags);
+        if (value == NULL) {
+            LOGE("drawTextWithGlyphs -- cannot get Cache value");
+            return ;
+        }
+#if DEBUG_GLYPHS
+        logGlyphs(value);
+#endif
+        doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(),
+                x, y, flags, paint);
+    }
+
     static void drawTextWithGlyphs___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
                                       jcharArray text, int index, int count,
                                       jfloat x, jfloat y, int flags, SkPaint* paint) {
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-#if RTL_USE_HARFBUZZ && USE_TEXT_LAYOUT_CACHE
-        sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
-                paint, textArray + index, 0, count, count, flags);
-        if (value != NULL) {
-#if DEBUG_GLYPHS
-            LOGD("drawTextWithGlyphs -- got glyphs - count=%d", value->getGlyphsCount());
-            for (size_t i = 0; i < value->getGlyphsCount(); i++) {
-                LOGD("                          glyphs[%d]=%d", i, value->getGlyphs()[i]);
-            }
-#endif
-            doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(),
-                    x, y, flags, paint);
-        }
-#else
-        TextLayout::drawText(paint, textArray + index, count, flags, x, y, canvas);
-#endif
+        drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
     }
 
@@ -785,23 +795,7 @@
                                           jfloat x, jfloat y, int flags, SkPaint* paint) {
 
         const jchar* textArray = env->GetStringChars(text, NULL);
-#if RTL_USE_HARFBUZZ && USE_TEXT_LAYOUT_CACHE
-        size_t count = end - start;
-        sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
-                paint, textArray, start, count, count, flags);
-        if (value != NULL) {
-#if DEBUG_GLYPHS
-            LOGD("drawTextWithGlyphs -- got glyphs - count=%d", value->getGlyphsCount());
-            for (size_t i = 0; i < value->getGlyphsCount(); i++) {
-                LOGD("                          glyphs[%d]=%d", i, value->getGlyphs()[i]);
-            }
-#endif
-            doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(),
-                    x, y, flags, paint);
-        }
-#else
-        TextLayout::drawText(paint, textArray + start, end - start, flags, x, y, canvas);
-#endif
+        drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint);
         env->ReleaseStringChars(text, textArray);
     }
 
diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h
index f203b75..9bb1b92 100644
--- a/core/jni/android/graphics/TextLayout.h
+++ b/core/jni/android/graphics/TextLayout.h
@@ -46,27 +46,27 @@
     static TextLayoutCache gTextLayoutCache;
 #endif
 
+enum {
+    kBidi_LTR = 0,
+    kBidi_RTL = 1,
+    kBidi_Default_LTR = 2,
+    kBidi_Default_RTL = 3,
+    kBidi_Force_LTR = 4,
+    kBidi_Force_RTL = 5,
+
+    kBidi_Mask = 0x7
+};
+
+enum {
+    kDirection_LTR = 0,
+    kDirection_RTL = 1,
+
+    kDirection_Mask = 0x1
+};
+
 class TextLayout {
 public:
 
-    enum {
-        kDirection_LTR = 0,
-        kDirection_RTL = 1,
-
-        kDirection_Mask = 0x1
-    };
-
-    enum {
-        kBidi_LTR = 0,
-        kBidi_RTL = 1,
-        kBidi_Default_LTR = 2,
-        kBidi_Default_RTL = 3,
-        kBidi_Force_LTR = 4,
-        kBidi_Force_RTL = 5,
-
-        kBidi_Mask = 0x7
-    };
-
     /*
      * Draws a unidirectional run of text.
      */
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 8db768c..77a731a 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "TextLayoutCache.h"
+#include "TextLayout.h"
 
 namespace android {
 
@@ -381,13 +382,128 @@
     }
 }
 
+struct GlyphRun {
+    inline GlyphRun() {}
+    inline GlyphRun(jchar* glyphs, size_t glyphsCount, bool isRTL) :
+            glyphs(glyphs), glyphsCount(glyphsCount), isRTL(isRTL) { }
+    jchar* glyphs;
+    size_t glyphsCount;
+    int isRTL;
+};
+
 void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar* chars,
         size_t start, size_t count, size_t contextCount, int dirFlags,
         jfloat* outAdvances, jfloat* outTotalAdvance,
         jchar** outGlyphs, size_t* outGlyphsCount) {
+
+        UBiDiLevel bidiReq = 0;
+        bool forceLTR = false;
+        bool forceRTL = false;
+
+        switch (dirFlags) {
+            case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
+            case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
+            case kBidi_Default_LTR: bidiReq = UBIDI_DEFAULT_LTR; break;
+            case kBidi_Default_RTL: bidiReq = UBIDI_DEFAULT_RTL; break;
+            case kBidi_Force_LTR: forceLTR = true; break; // every char is LTR
+            case kBidi_Force_RTL: forceRTL = true; break; // every char is RTL
+        }
+
+        if (forceLTR || forceRTL) {
+#if DEBUG_GLYPHS
+                    LOGD("computeValuesWithHarfbuzz -- forcing run with LTR=%d RTL=%d",
+                            forceLTR, forceRTL);
+#endif
+            computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags,
+                    outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount);
+        } else {
+            UBiDi* bidi = ubidi_open();
+            if (bidi) {
+                UErrorCode status = U_ZERO_ERROR;
+#if DEBUG_GLYPHS
+                LOGD("computeValuesWithHarfbuzz -- bidiReq=%d", bidiReq);
+#endif
+                ubidi_setPara(bidi, chars, contextCount, bidiReq, NULL, &status);
+                if (U_SUCCESS(status)) {
+                    int paraDir = ubidi_getParaLevel(bidi) & kDirection_Mask; // 0 if ltr, 1 if rtl
+                    size_t rc = ubidi_countRuns(bidi, &status);
+#if DEBUG_GLYPHS
+                    LOGD("computeValuesWithHarfbuzz -- dirFlags=%d run-count=%d paraDir=%d", dirFlags, rc, paraDir);
+#endif
+
+                    if (rc == 1 || !U_SUCCESS(status)) {
+                        computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount,
+                                dirFlags, outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount);
+                        ubidi_close(bidi);
+                        return;
+                    }
+
+                    size_t runIndex = 0;
+                    Vector<GlyphRun> glyphRuns;
+                    for (size_t i = 0; i < rc; ++i) {
+                        int32_t startRun;
+                        int32_t lengthRun;
+                        UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &startRun, &lengthRun);
+
+                        int newFlags = (runDir == UBIDI_RTL) ? kDirection_RTL : kDirection_LTR;
+                        jfloat runTotalAdvance = 0;
+                        jchar* runGlyphs;
+                        size_t runGlyphsCount = 0;
+
+#if DEBUG_GLYPHS
+                        LOGD("computeValuesWithHarfbuzz -- run-start=%d run-len=%d newFlags=%d",
+                                startRun, lengthRun, newFlags);
+#endif
+                        computeRunValuesWithHarfbuzz(paint, chars, startRun,
+                                lengthRun, contextCount, newFlags,
+                                outAdvances + runIndex, &runTotalAdvance,
+                                &runGlyphs, &runGlyphsCount);
+
+                        runIndex += lengthRun;
+
+                        *outTotalAdvance += runTotalAdvance;
+                        *outGlyphsCount += runGlyphsCount;
+
+#if DEBUG_GLYPHS
+                        LOGD("computeValuesWithHarfbuzz -- run=%d run-glyphs-count=%d",
+                                i, runGlyphsCount);
+                        for (size_t j = 0; j < runGlyphsCount; j++) {
+                            LOGD("                          -- glyphs[%d]=%d", j, runGlyphs[j]);
+                        }
+#endif
+                        glyphRuns.push(GlyphRun(runGlyphs, runGlyphsCount, newFlags));
+                    }
+
+#if DEBUG_GLYPHS
+                    LOGD("computeValuesWithHarfbuzz -- total-glyphs-count=%d", *outGlyphsCount);
+#endif
+                    *outGlyphs = new jchar[*outGlyphsCount];
+                    jchar* glyphs = *outGlyphs;
+                    for (size_t i = 0; i < glyphRuns.size(); i++) {
+                        const GlyphRun& glyphRun = glyphRuns.itemAt(i);
+                        if (glyphRun.isRTL) {
+                            for (size_t n = 0; n < glyphRun.glyphsCount; n++) {
+                                glyphs[glyphRun.glyphsCount - n - 1] = glyphRun.glyphs[n];
+                            }
+                        } else {
+                            memcpy(glyphs, glyphRun.glyphs, glyphRun.glyphsCount * sizeof(jchar));
+                        }
+                        glyphs += glyphRun.glyphsCount;
+                        delete[] glyphRun.glyphs;
+                    }
+                }
+                ubidi_close(bidi);
+            }
+        }
+}
+
+void TextLayoutCacheValue::computeRunValuesWithHarfbuzz(SkPaint* paint, const UChar* chars,
+        size_t start, size_t count, size_t contextCount, int dirFlags,
+        jfloat* outAdvances, jfloat* outTotalAdvance,
+        jchar** outGlyphs, size_t* outGlyphsCount) {
+
     bool isRTL = dirFlags & 0x1;
 
-    // TODO: need to run BiDi algo here to breakdown the text in several runs
     HB_ShaperItem shaperItem;
     HB_FontRec font;
     FontData fontData;
@@ -397,21 +513,30 @@
 #if DEBUG_GLYPHS
     LOGD("HARFBUZZ -- num_glypth=%d - kerning_applied=%d", shaperItem.num_glyphs,
             shaperItem.kerning_applied);
-    LOGD("         -- string= '%s'", String8(chars, contextCount).string());
+    LOGD("         -- string= '%s'", String8(chars + start, count).string());
     LOGD("         -- isDevKernText=%d", paint->isDevKernText());
 #endif
 
     // Get Advances and their total
-    jfloat totalAdvance = 0;
-    for (size_t i = 0; i < count; i++) {
-        totalAdvance += outAdvances[i] = HBFixedToFloat(shaperItem.advances[i]);
-#if DEBUG_ADVANCES
-        LOGD("hb-adv = %d - rebased = %f - total = %f", shaperItem.advances[i], outAdvances[i],
-                totalAdvance);
-#endif
+    jfloat totalAdvance = outAdvances[0] = HBFixedToFloat(shaperItem.advances[shaperItem.log_clusters[0]]);
+    for (size_t i = 1; i < count; i++) {
+        size_t clusterPrevious = shaperItem.log_clusters[i - 1];
+        size_t cluster = shaperItem.log_clusters[i];
+        if (cluster == clusterPrevious) {
+            outAdvances[i] = 0;
+        } else {
+            totalAdvance += outAdvances[i] = HBFixedToFloat(shaperItem.advances[shaperItem.log_clusters[i]]);
+        }
     }
     *outTotalAdvance = totalAdvance;
 
+#if DEBUG_ADVANCES
+    for (size_t i = 0; i < count; i++) {
+        LOGD("hb-adv[%d] = %f - log_clusters = %d - total = %f", i,
+                outAdvances[i], shaperItem.log_clusters[i], totalAdvance);
+    }
+#endif
+
     // Get Glyphs
     if (outGlyphs) {
         *outGlyphsCount = shaperItem.num_glyphs;
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index e6ce68d..62813df 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -178,6 +178,10 @@
     static void createGlyphArrays(HB_ShaperItem* shaperItem, int size);
     static void resetGlyphArrays(HB_ShaperItem* shaperItem);
 
+    static void computeRunValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start,
+            size_t count, size_t contextCount, int dirFlags,
+            jfloat* outAdvances, jfloat* outTotalAdvance,
+            jchar** outGlyphs, size_t* outGlyphsCount);
 }; // TextLayoutCacheValue
 
 /**
diff --git a/core/tests/coretests/src/com/android/internal/util/HierarchicalStateMachineTest.java b/core/tests/coretests/src/com/android/internal/util/StateMachineTest.java
similarity index 87%
rename from core/tests/coretests/src/com/android/internal/util/HierarchicalStateMachineTest.java
rename to core/tests/coretests/src/com/android/internal/util/StateMachineTest.java
index b6f8be5..ab6b2b6 100644
--- a/core/tests/coretests/src/com/android/internal/util/HierarchicalStateMachineTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/StateMachineTest.java
@@ -22,9 +22,9 @@
 import android.os.Message;
 import android.os.SystemClock;
 
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
-import com.android.internal.util.HierarchicalStateMachine.ProcessedMessageInfo;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+import com.android.internal.util.StateMachine.ProcessedMessageInfo;
 
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -33,9 +33,9 @@
 import junit.framework.TestCase;
 
 /**
- * Test for HierarchicalStateMachine.
+ * Test for StateMachine.
  */
-public class HierarchicalStateMachineTest extends TestCase {
+public class StateMachineTest extends TestCase {
     private static final int TEST_CMD_1 = 1;
     private static final int TEST_CMD_2 = 2;
     private static final int TEST_CMD_3 = 3;
@@ -45,12 +45,12 @@
 
     private static final boolean DBG = true;
     private static final boolean WAIT_FOR_DEBUGGER = false;
-    private static final String TAG = "HierarchicalStateMachineTest";
+    private static final String TAG = "StateMachineTest";
 
     /**
      * Tests that we can quit the state machine.
      */
-    class StateMachineQuitTest extends HierarchicalStateMachine {
+    class StateMachineQuitTest extends StateMachine {
         private int mQuitCount = 0;
 
         StateMachineQuitTest(String name) {
@@ -65,8 +65,9 @@
             setInitialState(mS1);
         }
 
-        class S1 extends HierarchicalState {
-            @Override protected boolean processMessage(Message message) {
+        class S1 extends State {
+            @Override
+            public boolean processMessage(Message message) {
                 if (isQuit(message)) {
                     mQuitCount += 1;
                     if (mQuitCount > 2) {
@@ -129,18 +130,18 @@
 
         // The first two message didn't quit and were handled by mS1
         pmi = smQuitTest.getProcessedMessageInfo(6);
-        assertEquals(HierarchicalStateMachine.HSM_QUIT_CMD, pmi.getWhat());
+        assertEquals(StateMachine.SM_QUIT_CMD, pmi.getWhat());
         assertEquals(smQuitTest.mS1, pmi.getState());
         assertEquals(smQuitTest.mS1, pmi.getOriginalState());
 
         pmi = smQuitTest.getProcessedMessageInfo(7);
-        assertEquals(HierarchicalStateMachine.HSM_QUIT_CMD, pmi.getWhat());
+        assertEquals(StateMachine.SM_QUIT_CMD, pmi.getWhat());
         assertEquals(smQuitTest.mS1, pmi.getState());
         assertEquals(smQuitTest.mS1, pmi.getOriginalState());
 
         // The last message was never handled so the states are null
         pmi = smQuitTest.getProcessedMessageInfo(8);
-        assertEquals(HierarchicalStateMachine.HSM_QUIT_CMD, pmi.getWhat());
+        assertEquals(StateMachine.SM_QUIT_CMD, pmi.getWhat());
         assertEquals(null, pmi.getState());
         assertEquals(null, pmi.getOriginalState());
 
@@ -150,7 +151,7 @@
     /**
      * Test enter/exit can use transitionTo
      */
-    class StateMachineEnterExitTransitionToTest extends HierarchicalStateMachine {
+    class StateMachineEnterExitTransitionToTest extends StateMachine {
         StateMachineEnterExitTransitionToTest(String name) {
             super(name);
             mThisSm = this;
@@ -166,34 +167,38 @@
             setInitialState(mS1);
         }
 
-        class S1 extends HierarchicalState {
-            @Override protected void enter() {
+        class S1 extends State {
+            @Override
+            public void enter() {
                 // Test that message is HSM_INIT_CMD
-                assertEquals(HSM_INIT_CMD, getCurrentMessage().what);
+                assertEquals(SM_INIT_CMD, getCurrentMessage().what);
 
                 // Test that a transition in enter and the initial state works
                 mS1EnterCount += 1;
                 transitionTo(mS2);
                 Log.d(TAG, "S1.enter");
             }
-            @Override protected void exit() {
+            @Override
+            public void exit() {
                 // Test that message is HSM_INIT_CMD
-                assertEquals(HSM_INIT_CMD, getCurrentMessage().what);
+                assertEquals(SM_INIT_CMD, getCurrentMessage().what);
 
                 mS1ExitCount += 1;
                 Log.d(TAG, "S1.exit");
             }
         }
 
-        class S2 extends HierarchicalState {
-            @Override protected void enter() {
+        class S2 extends State {
+            @Override
+            public void enter() {
                 // Test that message is HSM_INIT_CMD
-                assertEquals(HSM_INIT_CMD, getCurrentMessage().what);
+                assertEquals(SM_INIT_CMD, getCurrentMessage().what);
 
                 mS2EnterCount += 1;
                 Log.d(TAG, "S2.enter");
             }
-            @Override protected void exit() {
+            @Override
+            public void exit() {
                 // Test that message is TEST_CMD_1
                 assertEquals(TEST_CMD_1, getCurrentMessage().what);
 
@@ -202,7 +207,8 @@
                 transitionTo(mS4);
                 Log.d(TAG, "S2.exit");
             }
-            @Override protected boolean processMessage(Message message) {
+            @Override
+            public boolean processMessage(Message message) {
                 // Start a transition to S3 but it will be
                 // changed to a transition to S4 in exit
                 transitionTo(mS3);
@@ -211,28 +217,32 @@
             }
         }
 
-        class S3 extends HierarchicalState {
-            @Override protected void enter() {
+        class S3 extends State {
+            @Override
+            public void enter() {
                 // Test that we can do halting in an enter/exit
                 transitionToHaltingState();
                 mS3EnterCount += 1;
                 Log.d(TAG, "S3.enter");
             }
-            @Override protected void exit() {
+            @Override
+            public void exit() {
                 mS3ExitCount += 1;
                 Log.d(TAG, "S3.exit");
             }
         }
 
 
-        class S4 extends HierarchicalState {
-            @Override protected void enter() {
+        class S4 extends State {
+            @Override
+            public void enter() {
                 // Test that we can do halting in an enter/exit
                 transitionToHaltingState();
                 mS4EnterCount += 1;
                 Log.d(TAG, "S4.enter");
             }
-            @Override protected void exit() {
+            @Override
+            public void exit() {
                 mS4ExitCount += 1;
                 Log.d(TAG, "S4.exit");
             }
@@ -310,7 +320,7 @@
     /**
      * Tests that ProcessedMessage works as a circular buffer.
      */
-    class StateMachine0 extends HierarchicalStateMachine {
+    class StateMachine0 extends StateMachine {
         StateMachine0(String name) {
             super(name);
             mThisSm = this;
@@ -324,8 +334,9 @@
             setInitialState(mS1);
         }
 
-        class S1 extends HierarchicalState {
-            @Override protected boolean processMessage(Message message) {
+        class S1 extends State {
+            @Override
+            public boolean processMessage(Message message) {
                 if (message.what == TEST_CMD_6) {
                     transitionToHaltingState();
                 }
@@ -394,7 +405,7 @@
      * in state mS1. With the first message it transitions to
      * itself which causes it to be exited and reentered.
      */
-    class StateMachine1 extends HierarchicalStateMachine {
+    class StateMachine1 extends StateMachine {
         StateMachine1(String name) {
             super(name);
             mThisSm = this;
@@ -408,12 +419,17 @@
             if (DBG) Log.d(TAG, "StateMachine1: ctor X");
         }
 
-        class S1 extends HierarchicalState {
-            @Override protected void enter() {
+        class S1 extends State {
+            @Override
+            public void enter() {
                 mEnterCount++;
             }
-
-            @Override protected boolean processMessage(Message message) {
+            @Override
+            public void exit() {
+                mExitCount++;
+            }
+            @Override
+            public boolean processMessage(Message message) {
                 if (message.what == TEST_CMD_1) {
                     assertEquals(1, mEnterCount);
                     assertEquals(0, mExitCount);
@@ -425,10 +441,6 @@
                 }
                 return HANDLED;
             }
-
-            @Override protected void exit() {
-                mExitCount++;
-            }
         }
 
         @Override
@@ -493,7 +505,7 @@
      * mS2 then receives both of the deferred messages first TEST_CMD_1 and
      * then TEST_CMD_2.
      */
-    class StateMachine2 extends HierarchicalStateMachine {
+    class StateMachine2 extends StateMachine {
         StateMachine2(String name) {
             super(name);
             mThisSm = this;
@@ -508,26 +520,28 @@
             if (DBG) Log.d(TAG, "StateMachine2: ctor X");
         }
 
-        class S1 extends HierarchicalState {
-            @Override protected void enter() {
+        class S1 extends State {
+            @Override
+            public void enter() {
                 mDidEnter = true;
             }
-
-            @Override protected boolean processMessage(Message message) {
+            @Override
+            public void exit() {
+                mDidExit = true;
+            }
+            @Override
+            public boolean processMessage(Message message) {
                 deferMessage(message);
                 if (message.what == TEST_CMD_2) {
                     transitionTo(mS2);
                 }
                 return HANDLED;
             }
-
-            @Override protected void exit() {
-                mDidExit = true;
-            }
         }
 
-        class S2 extends HierarchicalState {
-            @Override protected boolean processMessage(Message message) {
+        class S2 extends State {
+            @Override
+            public boolean processMessage(Message message) {
                 if (message.what == TEST_CMD_2) {
                     transitionToHaltingState();
                 }
@@ -598,7 +612,7 @@
      * Test that unhandled messages in a child are handled by the parent.
      * When TEST_CMD_2 is received.
      */
-    class StateMachine3 extends HierarchicalStateMachine {
+    class StateMachine3 extends StateMachine {
         StateMachine3(String name) {
             super(name);
             mThisSm = this;
@@ -615,8 +629,9 @@
             if (DBG) Log.d(TAG, "StateMachine3: ctor X");
         }
 
-        class ParentState extends HierarchicalState {
-            @Override protected boolean processMessage(Message message) {
+        class ParentState extends State {
+            @Override
+            public boolean processMessage(Message message) {
                 if (message.what == TEST_CMD_2) {
                     transitionToHaltingState();
                 }
@@ -624,8 +639,9 @@
             }
         }
 
-        class ChildState extends HierarchicalState {
-            @Override protected boolean processMessage(Message message) {
+        class ChildState extends State {
+            @Override
+            public boolean processMessage(Message message) {
                 return NOT_HANDLED;
             }
         }
@@ -682,7 +698,7 @@
      * with transition from child 1 to child 2 and child 2
      * lets the parent handle the messages.
      */
-    class StateMachine4 extends HierarchicalStateMachine {
+    class StateMachine4 extends StateMachine {
         StateMachine4(String name) {
             super(name);
             mThisSm = this;
@@ -700,8 +716,9 @@
             if (DBG) Log.d(TAG, "StateMachine4: ctor X");
         }
 
-        class ParentState extends HierarchicalState {
-            @Override protected boolean processMessage(Message message) {
+        class ParentState extends State {
+            @Override
+            public boolean processMessage(Message message) {
                 if (message.what == TEST_CMD_2) {
                     transitionToHaltingState();
                 }
@@ -709,15 +726,17 @@
             }
         }
 
-        class ChildState1 extends HierarchicalState {
-            @Override protected boolean processMessage(Message message) {
+        class ChildState1 extends State {
+            @Override
+            public boolean processMessage(Message message) {
                 transitionTo(mChildState2);
                 return HANDLED;
             }
         }
 
-        class ChildState2 extends HierarchicalState {
-            @Override protected boolean processMessage(Message message) {
+        class ChildState2 extends State {
+            @Override
+            public boolean processMessage(Message message) {
                 return NOT_HANDLED;
             }
         }
@@ -775,7 +794,7 @@
      * Test transition from one child to another of a "complex"
      * hierarchy with two parents and multiple children.
      */
-    class StateMachine5 extends HierarchicalStateMachine {
+    class StateMachine5 extends StateMachine {
         StateMachine5(String name) {
             super(name);
             mThisSm = this;
@@ -797,23 +816,32 @@
             if (DBG) Log.d(TAG, "StateMachine5: ctor X");
         }
 
-        class ParentState1 extends HierarchicalState {
-            @Override protected void enter() {
+        class ParentState1 extends State {
+            @Override
+            public void enter() {
                 mParentState1EnterCount += 1;
             }
-            @Override protected boolean processMessage(Message message) {
-                return HANDLED;
-            }
-            @Override protected void exit() {
+            @Override
+            public void exit() {
                 mParentState1ExitCount += 1;
             }
+            @Override
+            public boolean processMessage(Message message) {
+                return HANDLED;
+            }
         }
 
-        class ChildState1 extends HierarchicalState {
-            @Override protected void enter() {
+        class ChildState1 extends State {
+            @Override
+            public void enter() {
                 mChildState1EnterCount += 1;
             }
-            @Override protected boolean processMessage(Message message) {
+            @Override
+            public void exit() {
+                mChildState1ExitCount += 1;
+            }
+            @Override
+            public boolean processMessage(Message message) {
                 assertEquals(1, mParentState1EnterCount);
                 assertEquals(0, mParentState1ExitCount);
                 assertEquals(1, mChildState1EnterCount);
@@ -832,16 +860,19 @@
                 transitionTo(mChildState2);
                 return HANDLED;
             }
-            @Override protected void exit() {
-                mChildState1ExitCount += 1;
-            }
         }
 
-        class ChildState2 extends HierarchicalState {
-            @Override protected void enter() {
+        class ChildState2 extends State {
+            @Override
+            public void enter() {
                 mChildState2EnterCount += 1;
             }
-            @Override protected boolean processMessage(Message message) {
+            @Override
+            public void exit() {
+                mChildState2ExitCount += 1;
+            }
+            @Override
+            public boolean processMessage(Message message) {
                 assertEquals(1, mParentState1EnterCount);
                 assertEquals(0, mParentState1ExitCount);
                 assertEquals(1, mChildState1EnterCount);
@@ -860,16 +891,19 @@
                 transitionTo(mChildState5);
                 return HANDLED;
             }
-            @Override protected void exit() {
-                mChildState2ExitCount += 1;
-            }
         }
 
-        class ParentState2 extends HierarchicalState {
-            @Override protected void enter() {
+        class ParentState2 extends State {
+            @Override
+            public void enter() {
                 mParentState2EnterCount += 1;
             }
-            @Override protected boolean processMessage(Message message) {
+            @Override
+            public void exit() {
+                mParentState2ExitCount += 1;
+            }
+            @Override
+            public boolean processMessage(Message message) {
                 assertEquals(1, mParentState1EnterCount);
                 assertEquals(1, mParentState1ExitCount);
                 assertEquals(1, mChildState1EnterCount);
@@ -888,16 +922,19 @@
                 transitionToHaltingState();
                 return HANDLED;
             }
-            @Override protected void exit() {
-                mParentState2ExitCount += 1;
-            }
         }
 
-        class ChildState3 extends HierarchicalState {
-            @Override protected void enter() {
+        class ChildState3 extends State {
+            @Override
+            public void enter() {
                 mChildState3EnterCount += 1;
             }
-            @Override protected boolean processMessage(Message message) {
+            @Override
+            public void exit() {
+                mChildState3ExitCount += 1;
+            }
+            @Override
+            public boolean processMessage(Message message) {
                 assertEquals(1, mParentState1EnterCount);
                 assertEquals(1, mParentState1ExitCount);
                 assertEquals(1, mChildState1EnterCount);
@@ -916,16 +953,19 @@
                 transitionTo(mChildState4);
                 return HANDLED;
             }
-            @Override protected void exit() {
-                mChildState3ExitCount += 1;
-            }
         }
 
-        class ChildState4 extends HierarchicalState {
-            @Override protected void enter() {
+        class ChildState4 extends State {
+            @Override
+            public void enter() {
                 mChildState4EnterCount += 1;
             }
-            @Override protected boolean processMessage(Message message) {
+            @Override
+            public void exit() {
+                mChildState4ExitCount += 1;
+            }
+            @Override
+            public boolean processMessage(Message message) {
                 assertEquals(1, mParentState1EnterCount);
                 assertEquals(1, mParentState1ExitCount);
                 assertEquals(1, mChildState1EnterCount);
@@ -944,16 +984,19 @@
                 transitionTo(mParentState2);
                 return HANDLED;
             }
-            @Override protected void exit() {
-                mChildState4ExitCount += 1;
-            }
         }
 
-        class ChildState5 extends HierarchicalState {
-            @Override protected void enter() {
+        class ChildState5 extends State {
+            @Override
+            public void enter() {
                 mChildState5EnterCount += 1;
             }
-            @Override protected boolean processMessage(Message message) {
+            @Override
+            public void exit() {
+                mChildState5ExitCount += 1;
+            }
+            @Override
+            public boolean processMessage(Message message) {
                 assertEquals(1, mParentState1EnterCount);
                 assertEquals(1, mParentState1ExitCount);
                 assertEquals(1, mChildState1EnterCount);
@@ -972,9 +1015,6 @@
                 transitionTo(mChildState3);
                 return HANDLED;
             }
-            @Override protected void exit() {
-                mChildState5ExitCount += 1;
-            }
         }
 
         @Override
@@ -1089,7 +1129,7 @@
      * after construction and before any other messages arrive and that
      * sendMessageDelayed works.
      */
-    class StateMachine6 extends HierarchicalStateMachine {
+    class StateMachine6 extends StateMachine {
         StateMachine6(String name) {
             super(name);
             mThisSm = this;
@@ -1103,13 +1143,13 @@
             if (DBG) Log.d(TAG, "StateMachine6: ctor X");
         }
 
-        class S1 extends HierarchicalState {
-
-            @Override protected void enter() {
+        class S1 extends State {
+            @Override
+            public void enter() {
                 sendMessage(TEST_CMD_1);
             }
-
-            @Override protected boolean processMessage(Message message) {
+            @Override
+            public boolean processMessage(Message message) {
                 if (message.what == TEST_CMD_1) {
                     mArrivalTimeMsg1 = SystemClock.elapsedRealtime();
                 } else if (message.what == TEST_CMD_2) {
@@ -1118,9 +1158,6 @@
                 }
                 return HANDLED;
             }
-
-            @Override protected void exit() {
-            }
         }
 
         @Override
@@ -1178,7 +1215,7 @@
      * Test that enter is invoked immediately after exit. This validates
      * that enter can be used to send a watch dog message for its state.
      */
-    class StateMachine7 extends HierarchicalStateMachine {
+    class StateMachine7 extends StateMachine {
         private final int SM7_DELAY_TIME = 250;
 
         StateMachine7(String name) {
@@ -1195,24 +1232,26 @@
             if (DBG) Log.d(TAG, "StateMachine7: ctor X");
         }
 
-        class S1 extends HierarchicalState {
-            @Override protected boolean processMessage(Message message) {
+        class S1 extends State {
+            @Override
+            public void exit() {
+                sendMessage(TEST_CMD_2);
+            }
+            @Override
+            public boolean processMessage(Message message) {
                 transitionTo(mS2);
                 return HANDLED;
             }
-            @Override protected void exit() {
-                sendMessage(TEST_CMD_2);
-            }
         }
 
-        class S2 extends HierarchicalState {
-
-            @Override protected void enter() {
+        class S2 extends State {
+            @Override
+            public void enter() {
                 // Send a delayed message as a watch dog
                 sendMessageDelayed(TEST_CMD_3, SM7_DELAY_TIME);
             }
-
-            @Override protected boolean processMessage(Message message) {
+            @Override
+            public boolean processMessage(Message message) {
                 if (message.what == TEST_CMD_2) {
                     mMsgCount += 1;
                     mArrivalTimeMsg2 = SystemClock.elapsedRealtime();
@@ -1226,9 +1265,6 @@
                 }
                 return HANDLED;
             }
-
-            @Override protected void exit() {
-            }
         }
 
         @Override
@@ -1286,7 +1322,7 @@
     /**
      * Test unhandledMessage.
      */
-    class StateMachineUnhandledMessage extends HierarchicalStateMachine {
+    class StateMachineUnhandledMessage extends StateMachine {
         StateMachineUnhandledMessage(String name) {
             super(name);
             mThisSm = this;
@@ -1298,13 +1334,14 @@
             // Set the initial state
             setInitialState(mS1);
         }
-
-        @Override protected void unhandledMessage(Message message) {
+        @Override
+        public void unhandledMessage(Message message) {
             mUnhandledMessageCount += 1;
         }
 
-        class S1 extends HierarchicalState {
-            @Override protected boolean processMessage(Message message) {
+        class S1 extends State {
+            @Override
+            public boolean processMessage(Message message) {
                 if (message.what == TEST_CMD_2) {
                     transitionToHaltingState();
                 }
@@ -1359,7 +1396,7 @@
      * will be used to notify testStateMachineSharedThread that the test is
      * complete.
      */
-    class StateMachineSharedThread extends HierarchicalStateMachine {
+    class StateMachineSharedThread extends StateMachine {
         StateMachineSharedThread(String name, Looper looper, int maxCount) {
             super(name, looper);
             mMaxCount = maxCount;
@@ -1372,8 +1409,9 @@
             setInitialState(mS1);
         }
 
-        class S1 extends HierarchicalState {
-            @Override protected boolean processMessage(Message message) {
+        class S1 extends State {
+            @Override
+            public boolean processMessage(Message message) {
                 if (message.what == TEST_CMD_4) {
                     transitionToHaltingState();
                 }
@@ -1503,7 +1541,7 @@
     }
 }
 
-class Hsm1 extends HierarchicalStateMachine {
+class Hsm1 extends StateMachine {
     private static final String TAG = "hsm1";
 
     public static final int CMD_1 = 1;
@@ -1535,11 +1573,17 @@
         Log.d(TAG, "ctor X");
     }
 
-    class P1 extends HierarchicalState {
-        @Override protected void enter() {
+    class P1 extends State {
+        @Override
+        public void enter() {
             Log.d(TAG, "P1.enter");
         }
-        @Override protected boolean processMessage(Message message) {
+        @Override
+        public void exit() {
+            Log.d(TAG, "P1.exit");
+        }
+        @Override
+        public boolean processMessage(Message message) {
             boolean retVal;
             Log.d(TAG, "P1.processMessage what=" + message.what);
             switch(message.what) {
@@ -1557,16 +1601,19 @@
             }
             return retVal;
         }
-        @Override protected void exit() {
-            Log.d(TAG, "P1.exit");
-        }
     }
 
-    class S1 extends HierarchicalState {
-        @Override protected void enter() {
+    class S1 extends State {
+        @Override
+        public void enter() {
             Log.d(TAG, "S1.enter");
         }
-        @Override protected boolean processMessage(Message message) {
+        @Override
+        public void exit() {
+            Log.d(TAG, "S1.exit");
+        }
+        @Override
+        public boolean processMessage(Message message) {
             Log.d(TAG, "S1.processMessage what=" + message.what);
             if (message.what == CMD_1) {
                 // Transition to ourself to show that enter/exit is called
@@ -1577,16 +1624,19 @@
                 return NOT_HANDLED;
             }
         }
-        @Override protected void exit() {
-            Log.d(TAG, "S1.exit");
-        }
     }
 
-    class S2 extends HierarchicalState {
-        @Override protected void enter() {
+    class S2 extends State {
+        @Override
+        public void enter() {
             Log.d(TAG, "S2.enter");
         }
-        @Override protected boolean processMessage(Message message) {
+        @Override
+        public void exit() {
+            Log.d(TAG, "S2.exit");
+        }
+        @Override
+        public boolean processMessage(Message message) {
             boolean retVal;
             Log.d(TAG, "S2.processMessage what=" + message.what);
             switch(message.what) {
@@ -1605,17 +1655,20 @@
             }
             return retVal;
         }
-        @Override protected void exit() {
-            Log.d(TAG, "S2.exit");
-        }
     }
 
-    class P2 extends HierarchicalState {
-        @Override protected void enter() {
+    class P2 extends State {
+        @Override
+        public void enter() {
             Log.d(TAG, "P2.enter");
             sendMessage(CMD_5);
         }
-        @Override protected boolean processMessage(Message message) {
+        @Override
+        public void exit() {
+            Log.d(TAG, "P2.exit");
+        }
+        @Override
+        public boolean processMessage(Message message) {
             Log.d(TAG, "P2.processMessage what=" + message.what);
             switch(message.what) {
             case(CMD_3):
@@ -1628,9 +1681,6 @@
             }
             return HANDLED;
         }
-        @Override protected void exit() {
-            Log.d(TAG, "P2.exit");
-        }
     }
 
     @Override
diff --git a/docs/html/guide/webapps/targeting.jd b/docs/html/guide/webapps/targeting.jd
index bdc2d5e..46f769c 100644
--- a/docs/html/guide/webapps/targeting.jd
+++ b/docs/html/guide/webapps/targeting.jd
@@ -368,14 +368,14 @@
 }
 
 &#64;media screen and (-webkit-device-pixel-ratio: 1.5) {
-    // CSS for high-density screens
+    /* CSS for high-density screens */
     #header {
         background:url(high-density-image.png);
     }
 }
 
 &#64;media screen and (-webkit-device-pixel-ratio: 0.75) {
-    // CSS for low-density screens
+    /* CSS for low-density screens */
     #header {
         background:url(low-density-image.png);
     }
@@ -426,7 +426,7 @@
 <pre>
 if (window.devicePixelRatio == 1.5) {
   alert("This is a high-density screen");
-} else if (window.devicePixelRation == 0.75) {
+} else if (window.devicePixelRatio == 0.75) {
   alert("This is a low-density screen");
 }
 </pre>
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index 32c9a1d5..bfe13f0 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -53,7 +53,8 @@
     
     status_t            setData(const uint8_t* buffer, size_t len);
 
-    status_t            appendFrom(Parcel *parcel, size_t start, size_t len);
+    status_t            appendFrom(const Parcel *parcel,
+                                   size_t start, size_t len);
 
     bool                hasFileDescriptors() const;
 
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 340daaf..96828c6 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -127,11 +127,28 @@
     // be called from the client.
     status_t setDefaultBufferSize(uint32_t w, uint32_t h);
 
-private:
+    // getCurrentBuffer returns the buffer associated with the current image.
+    sp<GraphicBuffer> getCurrentBuffer() const;
+
+    // getCurrentTextureTarget returns the texture target of the current
+    // texture as returned by updateTexImage().
+    GLenum getCurrentTextureTarget() const;
+
+    // getCurrentCrop returns the cropping rectangle of the current buffer
+    Rect getCurrentCrop() const;
+
+    // getCurrentTransform returns the transform of the current buffer
+    uint32_t getCurrentTransform() const;
+
+protected:
 
     // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
     // all slots.
     void freeAllBuffers();
+    static bool isExternalFormat(uint32_t format);
+    static GLenum getTextureTarget(uint32_t format);
+
+private:
 
     // createImage creates a new EGLImage from a GraphicBuffer.
     EGLImageKHR createImage(EGLDisplay dpy,
@@ -194,6 +211,10 @@
     // reset mCurrentTexture to INVALID_BUFFER_SLOT.
     int mCurrentTexture;
 
+    // mCurrentTextureTarget is the GLES texture target to be used with the
+    // current texture.
+    GLenum mCurrentTextureTarget;
+
     // mCurrentTextureBuf is the graphic buffer of the current texture. It's
     // possible that this buffer is not associated with any buffer slot, so we
     // must track it separately in order to properly use
@@ -256,7 +277,7 @@
     // mMutex is the mutex used to prevent concurrent access to the member
     // variables of SurfaceTexture objects. It must be locked whenever the
     // member variables are accessed.
-    Mutex mMutex;
+    mutable Mutex mMutex;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index df82bf2..fe9b049 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -27,6 +27,8 @@
 
 namespace android {
 
+class Surface;
+
 class SurfaceTextureClient
     : public EGLNativeBase<ANativeWindow, SurfaceTextureClient, RefBase>
 {
@@ -36,6 +38,7 @@
     sp<ISurfaceTexture> getISurfaceTexture() const;
 
 private:
+    friend class Surface;
 
     // can't be copied
     SurfaceTextureClient& operator = (const SurfaceTextureClient& rhs);
@@ -78,6 +81,8 @@
 
     void freeAllBuffers();
 
+    int getConnectedApi() const;
+
     enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS };
     enum { MIN_BUFFER_SLOTS = SurfaceTexture::MIN_BUFFER_SLOTS };
     enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
@@ -121,10 +126,25 @@
     // a timestamp is auto-generated when queueBuffer is called.
     int64_t mTimestamp;
 
+    // mConnectedApi holds the currently connected API to this surface
+    int mConnectedApi;
+
+    // mQueryWidth is the width returned by query(). It is set to width
+    // of the last dequeued buffer or to mReqWidth if no buffer was dequeued.
+    uint32_t mQueryWidth;
+
+    // mQueryHeight is the height returned by query(). It is set to height
+    // of the last dequeued buffer or to mReqHeight if no buffer was dequeued.
+    uint32_t mQueryHeight;
+
+    // mQueryFormat is the format returned by query(). It is set to the last
+    // dequeued format or to mReqFormat if no buffer was dequeued.
+    uint32_t mQueryFormat;
+
     // mMutex is the mutex used to prevent concurrent access to the member
     // variables of SurfaceTexture objects. It must be locked whenever the
     // member variables are accessed.
-    Mutex mMutex;
+    mutable Mutex mMutex;
 };
 
 }; // namespace android
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 6ed85d7..a0fc4d0 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -353,12 +353,12 @@
     return err;
 }
 
-status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len)
+status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len)
 {
     const sp<ProcessState> proc(ProcessState::self());
     status_t err;
-    uint8_t *data = parcel->mData;
-    size_t *objects = parcel->mObjects;
+    const uint8_t *data = parcel->mData;
+    const size_t *objects = parcel->mObjects;
     size_t size = parcel->mObjectsSize;
     int startPos = mDataPos;
     int firstIndex = -1, lastIndex = -2;
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index e2346f0..39418f0 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -27,6 +27,8 @@
 
 #include <gui/SurfaceTexture.h>
 
+#include <hardware/hardware.h>
+
 #include <surfaceflinger/ISurfaceComposer.h>
 #include <surfaceflinger/SurfaceComposerClient.h>
 #include <surfaceflinger/IGraphicBufferAlloc.h>
@@ -82,6 +84,7 @@
     mUseDefaultSize(true),
     mBufferCount(MIN_BUFFER_SLOTS),
     mCurrentTexture(INVALID_BUFFER_SLOT),
+    mCurrentTextureTarget(GL_TEXTURE_EXTERNAL_OES),
     mCurrentTransform(0),
     mCurrentTimestamp(0),
     mLastQueued(INVALID_BUFFER_SLOT),
@@ -197,6 +200,7 @@
     if (buffer == NULL) {
         return ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
     }
+
     if ((mUseDefaultSize) &&
         ((uint32_t(buffer->width) != mDefaultWidth) ||
          (uint32_t(buffer->height) != mDefaultHeight))) {
@@ -263,9 +267,6 @@
     LOGV("SurfaceTexture::updateTexImage");
     Mutex::Autolock lock(mMutex);
 
-    // We always bind the texture even if we don't update its contents.
-    glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
-
     // Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT,
     // so this check will fail until a buffer gets queued.
     if (mCurrentTexture != mLastQueued) {
@@ -283,7 +284,15 @@
         while ((error = glGetError()) != GL_NO_ERROR) {
             LOGE("GL error cleared before updating SurfaceTexture: %#04x", error);
         }
-        glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
+
+        GLenum target = getTextureTarget(
+                mSlots[mLastQueued].mGraphicBuffer->format);
+        if (target != mCurrentTextureTarget) {
+            glDeleteTextures(1, &mTexName);
+        }
+        glBindTexture(target, mTexName);
+        glEGLImageTargetTexture2DOES(target, (GLeglImageOES)image);
+
         bool failed = false;
         while ((error = glGetError()) != GL_NO_ERROR) {
             LOGE("error binding external texture image %p (slot %d): %#04x",
@@ -296,14 +305,53 @@
 
         // Update the SurfaceTexture state.
         mCurrentTexture = mLastQueued;
+        mCurrentTextureTarget = target;
         mCurrentTextureBuf = mSlots[mCurrentTexture].mGraphicBuffer;
         mCurrentCrop = mLastQueuedCrop;
         mCurrentTransform = mLastQueuedTransform;
         mCurrentTimestamp = mLastQueuedTimestamp;
+    } else {
+        // We always bind the texture even if we don't update its contents.
+        glBindTexture(mCurrentTextureTarget, mTexName);
     }
     return OK;
 }
 
+bool SurfaceTexture::isExternalFormat(uint32_t format)
+{
+    switch (format) {
+    // supported YUV formats
+    case HAL_PIXEL_FORMAT_YV12:
+    // Legacy/deprecated YUV formats
+    case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+    case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+    case HAL_PIXEL_FORMAT_YCbCr_422_I:
+        return true;
+    }
+
+    // Any OEM format needs to be considered
+    if (format>=0x100 && format<=0x1FF)
+        return true;
+
+    return false;
+}
+
+GLenum SurfaceTexture::getTextureTarget(uint32_t format)
+{
+    GLenum target = GL_TEXTURE_2D;
+#if defined(GL_OES_EGL_image_external)
+    if (isExternalFormat(format)) {
+        target = GL_TEXTURE_EXTERNAL_OES;
+    }
+#endif
+    return target;
+}
+
+GLenum SurfaceTexture::getCurrentTextureTarget() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentTextureTarget;
+}
+
 void SurfaceTexture::getTransformMatrix(float mtx[16]) {
     LOGV("SurfaceTexture::getTransformMatrix");
     Mutex::Autolock lock(mMutex);
@@ -445,6 +493,22 @@
     return image;
 }
 
+sp<GraphicBuffer> SurfaceTexture::getCurrentBuffer() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentTextureBuf;
+}
+
+Rect SurfaceTexture::getCurrentCrop() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentCrop;
+}
+
+uint32_t SurfaceTexture::getCurrentTransform() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentTransform;
+}
+
+
 static void mtxMul(float out[16], const float a[16], const float b[16]) {
     out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3];
     out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3];
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 29fc4d3..f4b2416 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -26,8 +26,10 @@
 SurfaceTextureClient::SurfaceTextureClient(
         const sp<ISurfaceTexture>& surfaceTexture):
         mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0),
-        mReqHeight(0), mReqFormat(DEFAULT_FORMAT), mReqUsage(0),
-        mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mMutex() {
+        mReqHeight(0), mReqFormat(0), mReqUsage(0),
+        mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mConnectedApi(0),
+        mQueryWidth(0), mQueryHeight(0), mQueryFormat(0),
+        mMutex() {
     // Initialize the ANativeWindow function pointers.
     ANativeWindow::setSwapInterval  = setSwapInterval;
     ANativeWindow::dequeueBuffer    = dequeueBuffer;
@@ -101,9 +103,10 @@
     }
     sp<GraphicBuffer>& gbuf(mSlots[buf]);
     if (err == ISurfaceTexture::BUFFER_NEEDS_REALLOCATION ||
-        gbuf == 0 || gbuf->getWidth() != mReqWidth ||
-        gbuf->getHeight() != mReqHeight ||
-        uint32_t(gbuf->getPixelFormat()) != mReqFormat ||
+        gbuf == 0 ||
+        (mReqWidth && gbuf->getWidth() != mReqWidth) ||
+        (mReqHeight && gbuf->getHeight() != mReqHeight) ||
+        (mReqFormat && uint32_t(gbuf->getPixelFormat()) != mReqFormat) ||
         (gbuf->getUsage() & mReqUsage) != mReqUsage) {
         gbuf = mSurfaceTexture->requestBuffer(buf, mReqWidth, mReqHeight,
                 mReqFormat, mReqUsage);
@@ -111,6 +114,9 @@
             LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed");
             return NO_MEMORY;
         }
+        mQueryWidth  = gbuf->width;
+        mQueryHeight = gbuf->height;
+        mQueryFormat = gbuf->format;
     }
     *buffer = gbuf.get();
     return OK;
@@ -159,13 +165,13 @@
     Mutex::Autolock lock(mMutex);
     switch (what) {
     case NATIVE_WINDOW_WIDTH:
+        *value = mQueryWidth ? mQueryWidth : mReqWidth;
+        return NO_ERROR;
     case NATIVE_WINDOW_HEIGHT:
-        // XXX: How should SurfaceTexture behave if setBuffersGeometry didn't
-        // override the size?
-        *value = 0;
+        *value = mQueryHeight ? mQueryHeight : mReqHeight;
         return NO_ERROR;
     case NATIVE_WINDOW_FORMAT:
-        *value = DEFAULT_FORMAT;
+        *value = mQueryFormat ? mQueryFormat : mReqFormat;
         return NO_ERROR;
     case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
         *value = MIN_UNDEQUEUED_BUFFERS;
@@ -260,16 +266,49 @@
 
 int SurfaceTextureClient::connect(int api) {
     LOGV("SurfaceTextureClient::connect");
-    // XXX: Implement this!
-    return INVALID_OPERATION;
+    Mutex::Autolock lock(mMutex);
+    int err = NO_ERROR;
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+            if (mConnectedApi) {
+                err = -EINVAL;
+            } else {
+                mConnectedApi = api;
+            }
+            break;
+        default:
+            err = -EINVAL;
+            break;
+    }
+    return err;
 }
 
 int SurfaceTextureClient::disconnect(int api) {
     LOGV("SurfaceTextureClient::disconnect");
-    // XXX: Implement this!
-    return INVALID_OPERATION;
+    Mutex::Autolock lock(mMutex);
+    int err = NO_ERROR;
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+            if (mConnectedApi == api) {
+                mConnectedApi = 0;
+            } else {
+                err = -EINVAL;
+            }
+            break;
+        default:
+            err = -EINVAL;
+            break;
+    }
+    return err;
 }
 
+int SurfaceTextureClient::getConnectedApi() const
+{
+    Mutex::Autolock lock(mMutex);
+    return mConnectedApi;
+}
+
+
 int SurfaceTextureClient::setUsage(uint32_t reqUsage)
 {
     LOGV("SurfaceTextureClient::setUsage");
diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp
index 6c5a55b..20aef49 100644
--- a/libs/rs/driver/rsdBcc.cpp
+++ b/libs/rs/driver/rsdBcc.cpp
@@ -381,7 +381,7 @@
     mtls.zEnd = rsMax((uint32_t)1, mtls.zEnd);
     mtls.arrayEnd = rsMax((uint32_t)1, mtls.arrayEnd);
 
-    rsAssert(ain->getType()->getDimZ() == 0);
+    rsAssert(!ain || (ain->getType()->getDimZ() == 0));
 
     Context *mrsc = (Context *)rsc;
     Script * oldTLS = setTLS(s);
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 9d0cba3..504cfde 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -111,6 +111,7 @@
     private static final int MSG_BTA2DP_DOCK_TIMEOUT = 8;
     private static final int MSG_LOAD_SOUND_EFFECTS = 9;
     private static final int MSG_SET_FORCE_USE = 10;
+    private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 11;
 
 
     private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
@@ -355,6 +356,12 @@
         intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
         context.registerReceiver(mReceiver, intentFilter);
 
+        // Register for package removal intent broadcasts for media button receiver persistence
+        IntentFilter pkgFilter = new IntentFilter();
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        pkgFilter.addDataScheme("package");
+        context.registerReceiver(mReceiver, pkgFilter);
+
         // Register for media button intent broadcasts.
         intentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
         intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
@@ -444,6 +451,9 @@
         // Broadcast vibrate settings
         broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
         broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
+
+        // Restore the default media button receiver from the system settings
+        restoreMediaButtonReceiver();
     }
 
     private void setStreamVolumeIndex(int stream, int index) {
@@ -1912,6 +1922,11 @@
             }
         }
 
+        private void persistMediaButtonReceiver(ComponentName receiver) {
+            Settings.System.putString(mContentResolver, Settings.System.MEDIA_BUTTON_RECEIVER,
+                    receiver == null ? "" : receiver.flattenToString());
+        }
+
         private void cleanupPlayer(MediaPlayer mp) {
             if (mp != null) {
                 try {
@@ -2022,6 +2037,10 @@
                 case MSG_SET_FORCE_USE:
                     setForceUse(msg.arg1, msg.arg2);
                     break;
+
+                case MSG_PERSIST_MEDIABUTTONRECEIVER:
+                    persistMediaButtonReceiver( (ComponentName) msg.obj );
+                    break;
             }
         }
     }
@@ -2354,6 +2373,14 @@
                 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
                         AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
                 mContext.sendStickyBroadcast(newIntent);
+            } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
+                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                    // a package is being removed, not replaced
+                    String packageName = intent.getData().getSchemeSpecificPart();
+                    if (packageName != null) {
+                        removeMediaButtonReceiverForPackage(packageName);
+                    }
+                }
             }
         }
     }
@@ -2469,7 +2496,7 @@
                 if(fse.mClientId.equals(clientToRemove)) {
                     Log.i(TAG, " AudioFocus  abandonAudioFocus(): removing entry for "
                             + fse.mClientId);
-                    mFocusStack.remove(fse);
+                    stackIterator.remove();
                 }
             }
         }
@@ -2489,7 +2516,7 @@
             if(fse.mSourceRef.equals(cb)) {
                 Log.i(TAG, " AudioFocus  abandonAudioFocus(): removing entry for "
                         + fse.mClientId);
-                mFocusStack.remove(fse);
+                stackIterator.remove();
             }
         }
         if (isTopOfStackForClientToRemove) {
@@ -2701,6 +2728,56 @@
 
     /**
      * Helper function:
+     * Remove any entry in the remote control stack that has the same package name as packageName
+     * Pre-condition: packageName != null
+     */
+    private void removeMediaButtonReceiverForPackage(String packageName) {
+        synchronized(mRCStack) {
+            if (mRCStack.empty()) {
+                return;
+            } else {
+                RemoteControlStackEntry oldTop = mRCStack.peek();
+                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+                // iterate over the stack entries
+                while(stackIterator.hasNext()) {
+                    RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
+                    if (packageName.equalsIgnoreCase(rcse.mReceiverComponent.getPackageName())) {
+                        // a stack entry is from the package being removed, remove it from the stack
+                        stackIterator.remove();
+                    }
+                }
+                if (mRCStack.empty()) {
+                    // no saved media button receiver
+                    mAudioHandler.sendMessage(
+                            mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
+                                    null));
+                    return;
+                } else if (oldTop != mRCStack.peek()) {
+                    // the top of the stack has changed, save it in the system settings
+                    // by posting a message to persist it
+                    mAudioHandler.sendMessage(
+                            mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
+                                    mRCStack.peek().mReceiverComponent));
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper function:
+     * Restore remote control receiver from the system settings
+     */
+    private void restoreMediaButtonReceiver() {
+        String receiverName = Settings.System.getString(mContentResolver,
+                Settings.System.MEDIA_BUTTON_RECEIVER);
+        if ((null != receiverName) && !receiverName.isEmpty()) {
+            ComponentName receiverComponentName = ComponentName.unflattenFromString(receiverName);
+            registerMediaButtonEventReceiver(receiverComponentName);
+        }
+    }
+
+    /**
+     * Helper function:
      * Set the new remote control receiver at the top of the RC focus stack
      */
     private void pushMediaButtonReceiver(ComponentName newReceiver) {
@@ -2712,11 +2789,15 @@
         while(stackIterator.hasNext()) {
             RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
             if(rcse.mReceiverComponent.equals(newReceiver)) {
-                mRCStack.remove(rcse);
+                stackIterator.remove();
                 break;
             }
         }
         mRCStack.push(new RemoteControlStackEntry(newReceiver));
+
+        // post message to persist the default media button receiver
+        mAudioHandler.sendMessage( mAudioHandler.obtainMessage(
+                MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, newReceiver/*obj*/) );
     }
 
     /**
@@ -2728,7 +2809,7 @@
         while(stackIterator.hasNext()) {
             RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
             if(rcse.mReceiverComponent.equals(newReceiver)) {
-                mRCStack.remove(rcse);
+                stackIterator.remove();
                 break;
             }
         }
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 7d72729..0747efb 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -13,8 +13,8 @@
 	EGL/hooks.cpp 	       \
 	EGL/Loader.cpp 	       \
 #
-LOCAL_STATIC_LIBRARIES += libGLESv2_dbg libprotobuf-cpp-2.3.0-lite liblzf
-LOCAL_SHARED_LIBRARIES += libcutils libutils libstlport
+
+LOCAL_SHARED_LIBRARIES += libcutils libutils libGLESv2_dbg
 LOCAL_LDLIBS := -lpthread -ldl
 LOCAL_MODULE:= libEGL
 LOCAL_LDFLAGS += -Wl,--exclude-libs=ALL
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 6474c87..9cf7223 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -46,6 +46,7 @@
 #include "egl_impl.h"
 #include "Loader.h"
 #include "glesv2dbg.h"
+#include "egl_tls.h"
 
 #define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
 
@@ -58,7 +59,7 @@
 static char const * const gVendorString     = "Android";
 static char const * const gVersionString    = "1.4 Android META-EGL";
 static char const * const gClientApiString  = "OpenGL ES";
-static char const * const gExtensionString  = 
+static char const * const gExtensionString  =
         "EGL_KHR_image "
         "EGL_KHR_image_base "
         "EGL_KHR_image_pixmap "
@@ -221,18 +222,15 @@
 struct egl_context_t : public egl_object_t
 {
     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(dpy), dpy(dpy), context(context), config(config), read(0), draw(0), 
-      impl(impl), cnx(cnx), version(version), dbg(NULL)
+            int impl, egl_connection_t const* cnx, int version)
+    : egl_object_t(dpy), dpy(dpy), context(context), config(config), read(0), draw(0),
+      impl(impl), cnx(cnx), version(version)
     {
     }
     ~egl_context_t()
     {
-        if (dbg)
-            DestroyDbgContext(dbg);
-        dbg = NULL;
     }
     EGLDisplay                  dpy;
     EGLContext                  context;
@@ -242,7 +240,6 @@
     int                         impl;
     egl_connection_t const*     cnx;
     int                         version;
-    DbgContext *                dbg;
 };
 
 struct egl_image_t : public egl_object_t
@@ -277,15 +274,6 @@
 typedef egl_image_t::Ref    ImageRef;
 typedef egl_sync_t::Ref     SyncRef;
 
-struct tls_t
-{
-    tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { }
-    EGLint      error;
-    EGLContext  ctx;
-    EGLBoolean  logCallWithNoContext;
-};
-
-
 // ----------------------------------------------------------------------------
 
 static egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
@@ -323,7 +311,7 @@
     int propertyLevel = atoi(value);
     int applicationLevel = gEGLApplicationTraceLevel;
     gEGLTraceLevel = propertyLevel > applicationLevel ? propertyLevel : applicationLevel;
-    
+
     property_get("debug.egl.debug_proc", value, "");
     long pid = getpid();
     char procPath[128] = {};
@@ -336,14 +324,20 @@
         {
             if (!strcmp(value, cmdline))
                 gEGLDebugLevel = 1;
-        }    
+        }
         fclose(file);
     }
-    
+
     if (gEGLDebugLevel > 0)
     {
         property_get("debug.egl.debug_port", value, "5039");
-        StartDebugServer(atoi(value));
+        const unsigned short port = (unsigned short)atoi(value);
+        property_get("debug.egl.debug_forceUseFile", value, "0");
+        const bool forceUseFile = (bool)atoi(value);
+        property_get("debug.egl.debug_maxFileSize", value, "8");
+        const unsigned int maxFileSize = atoi(value) << 20;
+        property_get("debug.egl.debug_filePath", value, "/data/local/tmp/dump.gles2dbg");
+        StartDebugServer(port, forceUseFile, maxFileSize, value);
     }
 }
 
@@ -586,7 +580,7 @@
 }
 
 static inline
-egl_surface_t* get_surface(EGLSurface surface) {   
+egl_surface_t* get_surface(EGLSurface surface) {
     return egl_to_native_cast<egl_surface_t>(surface);
 }
 
@@ -595,11 +589,6 @@
     return egl_to_native_cast<egl_context_t>(context);
 }
 
-DbgContext * getDbgContextThreadSpecific()
-{
-    return get_context(getContext())->dbg;
-}
-
 static inline
 egl_image_t* get_image(EGLImageKHR image) {
     return egl_to_native_cast<egl_image_t>(image);
@@ -1442,10 +1431,12 @@
         loseCurrent(cur_c);
 
         if (ctx != EGL_NO_CONTEXT) {
-            if (!c->dbg && gEGLDebugLevel > 0)
-                c->dbg = CreateDbgContext(c->version, c->cnx->hooks[c->version]);
             setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
             setContext(ctx);
+            tls_t * const tls = getTLS();
+            if (!tls->dbg && gEGLDebugLevel > 0)
+                tls->dbg = CreateDbgContext(gEGLThreadLocalStorageKey, c->version,
+                                            c->cnx->hooks[c->version]);
             _c.acquire();
             _r.acquire();
             _d.acquire();
diff --git a/opengl/libs/GLES2_dbg/Android.mk b/opengl/libs/GLES2_dbg/Android.mk
index fc40799..853cce6 100644
--- a/opengl/libs/GLES2_dbg/Android.mk
+++ b/opengl/libs/GLES2_dbg/Android.mk
@@ -11,7 +11,7 @@
     src/server.cpp \
     src/vertex.cpp
 
-LOCAL_C_INCLUDES :=	\
+LOCAL_C_INCLUDES := \
     $(LOCAL_PATH) \
     $(LOCAL_PATH)/../ \
     external/stlport/stlport \
@@ -21,7 +21,8 @@
 
 #LOCAL_CFLAGS += -O0 -g -DDEBUG -UNDEBUG
 LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI
-
+LOCAL_STATIC_LIBRARIES := libprotobuf-cpp-2.3.0-lite liblzf
+LOCAL_SHARED_LIBRARIES := libcutils libutils libstlport
 ifeq ($(TARGET_ARCH),arm)
 	LOCAL_CFLAGS += -fstrict-aliasing
 endif
@@ -43,4 +44,4 @@
 LOCAL_MODULE:= libGLESv2_dbg
 LOCAL_MODULE_TAGS := optional
 
-include $(BUILD_STATIC_LIBRARY)
+include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libs/GLES2_dbg/generate_api_cpp.py b/opengl/libs/GLES2_dbg/generate_api_cpp.py
index 66c110f..aeba213 100755
--- a/opengl/libs/GLES2_dbg/generate_api_cpp.py
+++ b/opengl/libs/GLES2_dbg/generate_api_cpp.py
@@ -26,36 +26,36 @@
         return line.replace(annotation, "*")
     else:
         return line
-    
+
 def generate_api(lines):
     externs = []
     i = 0
     # these have been hand written
-    skipFunctions = ["glReadPixels", "glDrawArrays", "glDrawElements"]
-    
+    skipFunctions = ["glDrawArrays", "glDrawElements"]
+
     # these have an EXTEND_Debug_* macro for getting data
-    extendFunctions = ["glCopyTexImage2D", "glCopyTexSubImage2D", "glShaderSource",
-"glTexImage2D", "glTexSubImage2D"]
-    
+    extendFunctions = ["glCopyTexImage2D", "glCopyTexSubImage2D", "glReadPixels",
+"glShaderSource", "glTexImage2D", "glTexSubImage2D"]
+
     # these also needs to be forwarded to DbgContext
     contextFunctions = ["glUseProgram", "glEnableVertexAttribArray", "glDisableVertexAttribArray", 
 "glVertexAttribPointer", "glBindBuffer", "glBufferData", "glBufferSubData", "glDeleteBuffers",]
-    
+
     for line in lines:
         if line.find("API_ENTRY(") >= 0: # a function prototype
             returnType = line[0: line.find(" API_ENTRY(")]
             functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name
             parameterList = line[line.find(")(") + 2: line.find(") {")]
-            
+
             #if line.find("*") >= 0:
             #    extern = "%s Debug_%s(%s);" % (returnType, functionName, parameterList)
             #    externs.append(extern)
             #    continue
-            
+
             if functionName in skipFunctions:
                 sys.stderr.write("!\n! skipping function '%s'\n!\n" % (functionName))
                 continue
-                
+
             parameters = parameterList.split(',')
             paramIndex = 0
             if line.find("*") >= 0 and (line.find("*") < line.find(":") or line.find("*") > line.rfind(":")): # unannotated pointer
@@ -65,21 +65,21 @@
                     sys.stderr.write("%s should be hand written\n" % (extern))
                     print "// FIXME: this function has pointers, it should be hand written"
                     externs.append(extern)
-                
+
             print "%s Debug_%s(%s)\n{" % (returnType, functionName, RemoveAnnotation(parameterList))
             print "    glesv2debugger::Message msg;"
-    
+
             if parameterList == "void":
                 parameters = []
             arguments = ""
             paramNames = []
             inout = ""
             getData = ""
-            
+
             callerMembers = ""
             setCallerMembers = ""
             setMsgParameters = ""
-            
+
             for parameter in parameters:
                 const = parameter.find("const")
                 parameter = parameter.replace("const", "")
@@ -107,7 +107,7 @@
                         annotation = "strlen(%s)" % (paramName)
                     else:
                         count = int(annotation)
-            
+
                     setMsgParameters += "    msg.set_arg%d(ToInt(%s));\n" % (paramIndex, paramName)
                     if paramType.find("void") >= 0:
                         getData += "    msg.mutable_data()->assign(reinterpret_cast<const char *>(%s), %s * sizeof(char));" % (paramName, annotation)
@@ -127,7 +127,7 @@
                 paramIndex += 1
                 callerMembers += "        %s %s;\n" % (paramType, paramName)
                 setCallerMembers += "    caller.%s = %s;\n" % (paramName, paramName)
-            
+
             print "    struct : public FunctionCall {"
             print callerMembers
             print "        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {"
@@ -141,6 +141,11 @@
             if inout in ["out", "inout"]:
                 print "            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);"
                 print "        " + getData
+            if functionName in extendFunctions:
+                print "\
+#ifdef EXTEND_AFTER_CALL_Debug_%s\n\
+            EXTEND_AFTER_CALL_Debug_%s;\n\
+#endif" % (functionName, functionName)
             if functionName in contextFunctions:
                 print "            getDbgContextThreadSpecific()->%s(%s);" % (functionName, arguments)
             if returnType == "void":
@@ -157,7 +162,10 @@
             if inout in ["in", "inout"]:
                 print getData
             if functionName in extendFunctions:
-                print "    EXTEND_Debug_%s;" % (functionName) 
+                print "\
+#ifdef EXTEND_Debug_%s\n\
+    EXTEND_Debug_%s;\n\
+#endif" % (functionName, functionName)
             print "    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_%s);"\
                 % (functionName)
             if returnType != "void":
@@ -166,8 +174,8 @@
                 else:
                     print "    return reinterpret_cast<%s>(ret);" % (returnType)
             print "}\n"
-                        
-            
+
+
     print "// FIXME: the following functions should be written by hand"
     for extern in externs:
         print extern
@@ -189,18 +197,23 @@
  ** See the License for the specific language governing permissions and
  ** limitations under the License.
  */
- 
+
 // auto generated by generate_api_cpp.py
 
+#include <utils/Debug.h>
+
 #include "src/header.h"
 #include "src/api.h"
 
-template<typename T> static int ToInt(const T & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (int &)t; }
-template<typename T> static T FromInt(const int & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (T &)t; }
-"""    
+template<typename T> static int ToInt(const T & t)
+{
+    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(sizeof(T) == sizeof(int));
+    return (int &)t;
+}
+"""
     lines = open("gl2_api_annotated.in").readlines()
     generate_api(lines)
     #lines = open("gl2ext_api.in").readlines()
     #generate_api(lines)
-            
+
 
diff --git a/opengl/libs/GLES2_dbg/generate_caller_cpp.py b/opengl/libs/GLES2_dbg/generate_caller_cpp.py
index eac2292..ee4208d 100755
--- a/opengl/libs/GLES2_dbg/generate_caller_cpp.py
+++ b/opengl/libs/GLES2_dbg/generate_caller_cpp.py
@@ -177,7 +177,6 @@
 {
     LOGD("GenerateCall function=%u", cmd.function());
     const int * ret = prevRet; // only some functions have return value
-    gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;
     nsecs_t c0 = systemTime(timeMode);
     switch (cmd.function()) {""")
     
diff --git a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
index 466c447..914ea24 100755
--- a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
+++ b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
@@ -70,41 +70,43 @@
 """)
 
     i = 0;
-    
+
     lines = open("gl2_api_annotated.in").readlines()
     i = generate_gl_entries(output, lines, i)
     output.write("        // end of GL functions\n")
-    
+
     #lines = open("gl2ext_api.in").readlines()
     #i = generate_gl_entries(output, lines, i)
     #output.write("        // end of GL EXT functions\n")
-    
+
     lines = open("../EGL/egl_entries.in").readlines()
     i = generate_egl_entries(output, lines, i)
     output.write("        // end of GL EXT functions\n")
-    
+
     output.write("        ACK = %d;\n" % (i))
     i += 1
-    
+
     output.write("        NEG = %d;\n" % (i))
     i += 1
-    
+
     output.write("        CONTINUE = %d;\n" % (i))
     i += 1
-    
+
     output.write("        SKIP = %d;\n" % (i))
     i += 1
-    
+
     output.write("        SETPROP = %d;\n" % (i))
     i += 1
-    
+
     output.write("""    }
     required Function function = 2 [default = NEG]; // type/function of message
     enum Type
     {
         BeforeCall = 0;
         AfterCall = 1;
-        Response = 2; // currently used for misc messages
+        AfterGeneratedCall = 2;
+        Response = 3; // currently used for misc messages
+        CompleteCall = 4; // BeforeCall and AfterCall merged
     }
     required Type type = 3;
     required bool expect_response = 4;
@@ -125,16 +127,21 @@
         ReferencedImage = 0; // for image sourced from ReadPixels
         NonreferencedImage = 1; // for image sourced from ReadPixels
     };
-    optional DataType data_type = 23; // most data types can be inferred from function
-    optional int32 pixel_format = 24; // used for image data if format and type 
-    optional int32 pixel_type = 25;   //     cannot be determined from arg 
-    
+    // most data types can be inferred from function
+    optional DataType data_type = 23;
+    // these are used for image data when they cannot be determined from args
+    optional int32 pixel_format = 24;
+    optional int32 pixel_type = 25;
+    optional int32 image_width = 26;
+    optional int32 image_height = 27;
+
     optional float time = 11; // duration of previous GL call (ms)
     enum Prop
     {
-        Capture = 0; // arg0 = true | false
+        CaptureDraw = 0; // arg0 = number of glDrawArrays/Elements to glReadPixels
         TimeMode = 1; // arg0 = SYSTEM_TIME_* in utils/Timers.h
         ExpectResponse = 2; // arg0 = enum Function, arg1 = true/false
+        CaptureSwap = 3; // arg0 = number of eglSwapBuffers to glReadPixels
     };
     optional Prop prop = 21; // used with SETPROP, value in arg0
     optional float clock = 22; // wall clock in seconds
@@ -142,6 +149,6 @@
 """)
 
     output.close()
-    
+
     os.system("aprotoc --cpp_out=src --java_out=../../../../../development/tools/glesv2debugger/src debugger_message.proto")
     os.system('mv -f "src/debugger_message.pb.cc" "src/debugger_message.pb.cpp"')
diff --git a/opengl/libs/GLES2_dbg/src/api.cpp b/opengl/libs/GLES2_dbg/src/api.cpp
index 130ca7e..c483547 100644
--- a/opengl/libs/GLES2_dbg/src/api.cpp
+++ b/opengl/libs/GLES2_dbg/src/api.cpp
@@ -16,11 +16,16 @@
  
 // auto generated by generate_api_cpp.py
 
+#include <utils/Debug.h>
+
 #include "src/header.h"
 #include "src/api.h"
 
-template<typename T> static int ToInt(const T & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (int &)t; }
-template<typename T> static T FromInt(const int & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (T &)t; }
+template<typename T> static int ToInt(const T & t)
+{
+    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(sizeof(T) == sizeof(int));
+    return (int &)t;
+}
 
 void Debug_glActiveTexture(GLenum texture)
 {
@@ -592,6 +597,9 @@
 
         const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
             _c->glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
+#ifdef EXTEND_AFTER_CALL_Debug_glCopyTexImage2D
+            EXTEND_AFTER_CALL_Debug_glCopyTexImage2D;
+#endif
             return 0;
         }
     } caller;
@@ -613,7 +621,9 @@
     msg.set_arg6(height);
     msg.set_arg7(border);
 
+#ifdef EXTEND_Debug_glCopyTexImage2D
     EXTEND_Debug_glCopyTexImage2D;
+#endif
     int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCopyTexImage2D);
 }
 
@@ -632,6 +642,9 @@
 
         const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
             _c->glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+#ifdef EXTEND_AFTER_CALL_Debug_glCopyTexSubImage2D
+            EXTEND_AFTER_CALL_Debug_glCopyTexSubImage2D;
+#endif
             return 0;
         }
     } caller;
@@ -653,7 +666,9 @@
     msg.set_arg6(width);
     msg.set_arg7(height);
 
+#ifdef EXTEND_Debug_glCopyTexSubImage2D
     EXTEND_Debug_glCopyTexSubImage2D;
+#endif
     int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCopyTexSubImage2D);
 }
 
@@ -2164,6 +2179,49 @@
     int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glPolygonOffset);
 }
 
+void Debug_glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
+{
+    glesv2debugger::Message msg;
+    struct : public FunctionCall {
+        GLint x;
+        GLint y;
+        GLsizei width;
+        GLsizei height;
+        GLenum format;
+        GLenum type;
+        GLvoid* pixels;
+
+        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+            _c->glReadPixels(x, y, width, height, format, type, pixels);
+#ifdef EXTEND_AFTER_CALL_Debug_glReadPixels
+            EXTEND_AFTER_CALL_Debug_glReadPixels;
+#endif
+            return 0;
+        }
+    } caller;
+    caller.x = x;
+    caller.y = y;
+    caller.width = width;
+    caller.height = height;
+    caller.format = format;
+    caller.type = type;
+    caller.pixels = pixels;
+
+    msg.set_arg0(x);
+    msg.set_arg1(y);
+    msg.set_arg2(width);
+    msg.set_arg3(height);
+    msg.set_arg4(format);
+    msg.set_arg5(type);
+    msg.set_arg6(ToInt(pixels));
+
+    // FIXME: check for pointer usage
+#ifdef EXTEND_Debug_glReadPixels
+    EXTEND_Debug_glReadPixels;
+#endif
+    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glReadPixels);
+}
+
 void Debug_glReleaseShaderCompiler(void)
 {
     glesv2debugger::Message msg;
@@ -2297,6 +2355,9 @@
 
         const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
             _c->glShaderSource(shader, count, string, length);
+#ifdef EXTEND_AFTER_CALL_Debug_glShaderSource
+            EXTEND_AFTER_CALL_Debug_glShaderSource;
+#endif
             return 0;
         }
     } caller;
@@ -2311,7 +2372,9 @@
     msg.set_arg3(ToInt(length));
 
     // FIXME: check for pointer usage
+#ifdef EXTEND_Debug_glShaderSource
     EXTEND_Debug_glShaderSource;
+#endif
     int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glShaderSource);
 }
 
@@ -2472,6 +2535,9 @@
 
         const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
             _c->glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
+#ifdef EXTEND_AFTER_CALL_Debug_glTexImage2D
+            EXTEND_AFTER_CALL_Debug_glTexImage2D;
+#endif
             return 0;
         }
     } caller;
@@ -2496,7 +2562,9 @@
     msg.set_arg8(ToInt(pixels));
 
     // FIXME: check for pointer usage
+#ifdef EXTEND_Debug_glTexImage2D
     EXTEND_Debug_glTexImage2D;
+#endif
     int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexImage2D);
 }
 
@@ -2616,6 +2684,9 @@
 
         const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
             _c->glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
+#ifdef EXTEND_AFTER_CALL_Debug_glTexSubImage2D
+            EXTEND_AFTER_CALL_Debug_glTexSubImage2D;
+#endif
             return 0;
         }
     } caller;
@@ -2640,7 +2711,9 @@
     msg.set_arg8(ToInt(pixels));
 
     // FIXME: check for pointer usage
+#ifdef EXTEND_Debug_glTexSubImage2D
     EXTEND_Debug_glTexSubImage2D;
+#endif
     int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexSubImage2D);
 }
 
diff --git a/opengl/libs/GLES2_dbg/src/api.h b/opengl/libs/GLES2_dbg/src/api.h
index b9fc341..0b227bc 100644
--- a/opengl/libs/GLES2_dbg/src/api.h
+++ b/opengl/libs/GLES2_dbg/src/api.h
@@ -16,19 +16,29 @@
 
 #define EXTEND_Debug_glCopyTexImage2D \
     DbgContext * const dbg = getDbgContextThreadSpecific(); \
-    GLint readFormat, readType; \
-    dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat); \
-    dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType); \
-    unsigned readSize = GetBytesPerPixel(readFormat, readType) * width * height; \
-    void * readData = dbg->GetReadPixelsBuffer(readSize); \
-    dbg->hooks->gl.glReadPixels(x, y, width, height, readFormat, readType, readData); \
+    void * readData = dbg->GetReadPixelsBuffer(4 * width * height); \
+    /* pick easy format for client to convert */ \
+    dbg->hooks->gl.glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, readData); \
     dbg->CompressReadPixelBuffer(msg.mutable_data()); \
     msg.set_data_type(msg.ReferencedImage); \
-    msg.set_pixel_format(readFormat); \
-    msg.set_pixel_type(readType);
+    msg.set_pixel_format(GL_RGBA); \
+    msg.set_pixel_type(GL_UNSIGNED_BYTE);
 
 #define EXTEND_Debug_glCopyTexSubImage2D EXTEND_Debug_glCopyTexImage2D
 
+#define EXTEND_AFTER_CALL_Debug_glReadPixels \
+    { \
+        DbgContext * const dbg = getDbgContextThreadSpecific(); \
+        if (dbg->IsReadPixelBuffer(pixels)) { \
+            dbg->CompressReadPixelBuffer(msg.mutable_data()); \
+            msg.set_data_type(msg.ReferencedImage); \
+        } else { \
+            const unsigned int size = width * height * GetBytesPerPixel(format, type); \
+            dbg->Compress(pixels, size, msg.mutable_data()); \
+            msg.set_data_type(msg.NonreferencedImage); \
+        } \
+    }
+
 #define EXTEND_Debug_glShaderSource \
     std::string * const data = msg.mutable_data(); \
     for (unsigned i = 0; i < count; i++) \
diff --git a/opengl/libs/GLES2_dbg/src/caller.cpp b/opengl/libs/GLES2_dbg/src/caller.cpp
index 9992f05..6b72751 100644
--- a/opengl/libs/GLES2_dbg/src/caller.cpp
+++ b/opengl/libs/GLES2_dbg/src/caller.cpp
@@ -105,7 +105,6 @@
 {
     LOGD("GenerateCall function=%u", cmd.function());
     const int * ret = prevRet; // only some functions have return value
-    gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;
     nsecs_t c0 = systemTime(timeMode);
     switch (cmd.function()) {    case glesv2debugger::Message_Function_glActiveTexture:
         dbg->hooks->gl.glActiveTexture(
@@ -772,7 +771,7 @@
     msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
     msg.set_context_id(reinterpret_cast<int>(dbg));
     msg.set_function(cmd.function());
-    msg.set_type(glesv2debugger::Message_Type_AfterCall);
+    msg.set_type(glesv2debugger::Message_Type_AfterGeneratedCall);
     return ret;
 }
 
diff --git a/opengl/libs/GLES2_dbg/src/caller.h b/opengl/libs/GLES2_dbg/src/caller.h
index 5447757..e8111b3 100644
--- a/opengl/libs/GLES2_dbg/src/caller.h
+++ b/opengl/libs/GLES2_dbg/src/caller.h
@@ -138,7 +138,9 @@
         const glesv2debugger::Message & cmd,
         glesv2debugger::Message & msg, const int * const prevRet)
 {
-    assert(0);
+    GLint params = -1;
+    dbg->hooks->gl.glGetProgramiv(cmd.arg0(), cmd.arg1(), &params);
+    msg.mutable_data()->append(reinterpret_cast<char *>(&params), sizeof(params));
     return prevRet;
 }
 
@@ -146,7 +148,10 @@
         const glesv2debugger::Message & cmd,
         glesv2debugger::Message & msg, const int * const prevRet)
 {
-    assert(0);
+    const GLsizei bufSize = static_cast<GLsizei>(dbg->GetBufferSize());
+    GLsizei length = -1;
+    dbg->hooks->gl.glGetProgramInfoLog(cmd.arg0(), bufSize, &length, dbg->GetBuffer());
+    msg.mutable_data()->append(dbg->GetBuffer(), length);
     return prevRet;
 }
 
@@ -162,7 +167,9 @@
                                         const glesv2debugger::Message & cmd,
                                         glesv2debugger::Message & msg, const int * const prevRet)
 {
-    assert(0);
+    GLint params = -1;
+    dbg->hooks->gl.glGetShaderiv(cmd.arg0(), cmd.arg1(), &params);
+    msg.mutable_data()->append(reinterpret_cast<char *>(&params), sizeof(params));
     return prevRet;
 }
 
@@ -170,7 +177,10 @@
         const glesv2debugger::Message & cmd,
         glesv2debugger::Message & msg, const int * const prevRet)
 {
-    assert(0);
+    const GLsizei bufSize = static_cast<GLsizei>(dbg->GetBufferSize());
+    GLsizei length = -1;
+    dbg->hooks->gl.glGetShaderInfoLog(cmd.arg0(), bufSize, &length, dbg->GetBuffer());
+    msg.mutable_data()->append(dbg->GetBuffer(), length);
     return prevRet;
 }
 
diff --git a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
index cc7336c..fe93874 100644
--- a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
+++ b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "header.h"
+#include "egl_tls.h"
 
 extern "C"
 {
@@ -24,11 +25,23 @@
 namespace android
 {
 
+static pthread_key_t sEGLThreadLocalStorageKey = -1;
+
+DbgContext * getDbgContextThreadSpecific()
+{
+    tls_t* tls = (tls_t*)pthread_getspecific(sEGLThreadLocalStorageKey);
+    return tls->dbg;
+}
+
 DbgContext::DbgContext(const unsigned version, const gl_hooks_t * const hooks,
-                       const unsigned MAX_VERTEX_ATTRIBS)
+                       const unsigned MAX_VERTEX_ATTRIBS, const GLenum readFormat,
+                       const GLenum readType)
         : lzf_buf(NULL), lzf_readIndex(0), lzf_refSize(0), lzf_refBufSize(0)
         , version(version), hooks(hooks)
         , MAX_VERTEX_ATTRIBS(MAX_VERTEX_ATTRIBS)
+        , readFormat(readFormat), readType(readType)
+        , readBytesPerPixel(GetBytesPerPixel(readFormat, readType))
+        , captureSwap(0), captureDraw(0)
         , vertexAttribs(new VertexAttrib[MAX_VERTEX_ATTRIBS])
         , hasNonVBOAttribs(false), indexBuffers(NULL), indexBuffer(NULL)
         , program(0), maxAttrib(0)
@@ -47,13 +60,18 @@
     free(lzf_ref[1]);
 }
 
-DbgContext * CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks)
+DbgContext * CreateDbgContext(const pthread_key_t EGLThreadLocalStorageKey,
+                              const unsigned version, const gl_hooks_t * const hooks)
 {
+    sEGLThreadLocalStorageKey = EGLThreadLocalStorageKey;
     assert(version < 2);
     assert(GL_NO_ERROR == hooks->gl.glGetError());
     GLint MAX_VERTEX_ATTRIBS = 0;
     hooks->gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &MAX_VERTEX_ATTRIBS);
-    return new DbgContext(version, hooks, MAX_VERTEX_ATTRIBS);
+    GLint readFormat, readType;
+    hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat);
+    hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType);
+    return new DbgContext(version, hooks, MAX_VERTEX_ATTRIBS, readFormat, readType);
 }
 
 void DestroyDbgContext(DbgContext * const dbg)
@@ -113,6 +131,7 @@
 {
     if (!lzf_buf)
         lzf_buf = (char *)malloc(LZF_CHUNK_SIZE);
+    assert(lzf_buf);
     const uint32_t totalDecompSize = in_len;
     outStr->append((const char *)&totalDecompSize, sizeof(totalDecompSize));
     for (unsigned int i = 0; i < in_len; i += LZF_CHUNK_SIZE) {
@@ -135,8 +154,10 @@
     if (lzf_refBufSize < size + 8) {
         lzf_refBufSize = size + 8;
         lzf_ref[0] = (unsigned *)realloc(lzf_ref[0], lzf_refBufSize);
+        assert(lzf_ref[0]);
         memset(lzf_ref[0], 0, lzf_refBufSize);
         lzf_ref[1] = (unsigned *)realloc(lzf_ref[1], lzf_refBufSize);
+        assert(lzf_ref[1]);
         memset(lzf_ref[1], 0, lzf_refBufSize);
     }
     if (lzf_refSize != size) // need to clear unused ref to maintain consistency
@@ -151,6 +172,7 @@
 
 void DbgContext::CompressReadPixelBuffer(std::string * const outStr)
 {
+    assert(lzf_ref[0] && lzf_ref[1]);
     unsigned * const ref = lzf_ref[lzf_readIndex ^ 1];
     unsigned * const src = lzf_ref[lzf_readIndex];
     for (unsigned i = 0; i < lzf_refSize / sizeof(*ref) + 1; i++)
@@ -158,13 +180,34 @@
     Compress(ref, lzf_refSize, outStr);
 }
 
+char * DbgContext::GetBuffer()
+{
+    if (!lzf_buf)
+        lzf_buf = (char *)malloc(LZF_CHUNK_SIZE);
+    assert(lzf_buf);
+    return lzf_buf;
+}
+
+unsigned int DbgContext::GetBufferSize()
+{
+    if (!lzf_buf)
+        lzf_buf = (char *)malloc(LZF_CHUNK_SIZE);
+    assert(lzf_buf);
+    if (lzf_buf)
+        return LZF_CHUNK_SIZE;
+    else
+        return 0;
+}
+
 void DbgContext::glUseProgram(GLuint program)
 {
     while (GLenum error = hooks->gl.glGetError())
-        LOGD("DbgContext::glUseProgram: before glGetError() = 0x%.4X", error);
-
+        LOGD("DbgContext::glUseProgram(%u): before glGetError() = 0x%.4X",
+             program, error);
     this->program = program;
-
+    maxAttrib = 0;
+    if (program == 0)
+        return;
     GLint activeAttributes = 0;
     hooks->gl.glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &activeAttributes);
     maxAttrib = 0;
@@ -202,9 +245,9 @@
             maxAttrib = slot;
     }
     delete name;
-
     while (GLenum error = hooks->gl.glGetError())
-        LOGD("DbgContext::glUseProgram: after glGetError() = 0x%.4X", error);
+        LOGD("DbgContext::glUseProgram(%u): after glGetError() = 0x%.4X",
+             program, error);
 }
 
 static bool HasNonVBOAttribs(const DbgContext * const ctx)
@@ -254,14 +297,16 @@
 
 void DbgContext::glEnableVertexAttribArray(GLuint index)
 {
-    assert(index < MAX_VERTEX_ATTRIBS);
+    if (index >= MAX_VERTEX_ATTRIBS)
+        return;
     vertexAttribs[index].enabled = true;
     hasNonVBOAttribs = HasNonVBOAttribs(this);
 }
 
 void DbgContext::glDisableVertexAttribArray(GLuint index)
 {
-    assert(index < MAX_VERTEX_ATTRIBS);
+    if (index >= MAX_VERTEX_ATTRIBS)
+        return;
     vertexAttribs[index].enabled = false;
     hasNonVBOAttribs = HasNonVBOAttribs(this);
 }
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
index 046c954..40478c3 100644
--- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
+++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
@@ -436,6 +436,8 @@
     case 0:
     case 1:
     case 2:
+    case 3:
+    case 4:
       return true;
     default:
       return false;
@@ -445,7 +447,9 @@
 #ifndef _MSC_VER
 const Message_Type Message::BeforeCall;
 const Message_Type Message::AfterCall;
+const Message_Type Message::AfterGeneratedCall;
 const Message_Type Message::Response;
+const Message_Type Message::CompleteCall;
 const Message_Type Message::Type_MIN;
 const Message_Type Message::Type_MAX;
 const int Message::Type_ARRAYSIZE;
@@ -472,6 +476,7 @@
     case 0:
     case 1:
     case 2:
+    case 3:
       return true;
     default:
       return false;
@@ -479,9 +484,10 @@
 }
 
 #ifndef _MSC_VER
-const Message_Prop Message::Capture;
+const Message_Prop Message::CaptureDraw;
 const Message_Prop Message::TimeMode;
 const Message_Prop Message::ExpectResponse;
+const Message_Prop Message::CaptureSwap;
 const Message_Prop Message::Prop_MIN;
 const Message_Prop Message::Prop_MAX;
 const int Message::Prop_ARRAYSIZE;
@@ -506,6 +512,8 @@
 const int Message::kDataTypeFieldNumber;
 const int Message::kPixelFormatFieldNumber;
 const int Message::kPixelTypeFieldNumber;
+const int Message::kImageWidthFieldNumber;
+const int Message::kImageHeightFieldNumber;
 const int Message::kTimeFieldNumber;
 const int Message::kPropFieldNumber;
 const int Message::kClockFieldNumber;
@@ -545,6 +553,8 @@
   data_type_ = 0;
   pixel_format_ = 0;
   pixel_type_ = 0;
+  image_width_ = 0;
+  image_height_ = 0;
   time_ = 0;
   prop_ = 0;
   clock_ = 0;
@@ -606,6 +616,8 @@
   if (_has_bits_[16 / 32] & (0xffu << (16 % 32))) {
     pixel_format_ = 0;
     pixel_type_ = 0;
+    image_width_ = 0;
+    image_height_ = 0;
     time_ = 0;
     prop_ = 0;
     clock_ = 0;
@@ -790,7 +802,7 @@
           DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
                    float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
                  input, &time_)));
-          _set_bit(18);
+          _set_bit(20);
         } else {
           goto handle_uninterpreted;
         }
@@ -905,7 +917,7 @@
           DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
                    float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
                  input, &clock_)));
-          _set_bit(20);
+          _set_bit(22);
         } else {
           goto handle_uninterpreted;
         }
@@ -960,6 +972,38 @@
         } else {
           goto handle_uninterpreted;
         }
+        if (input->ExpectTag(208)) goto parse_image_width;
+        break;
+      }
+
+      // optional int32 image_width = 26;
+      case 26: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_image_width:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &image_width_)));
+          _set_bit(18);
+        } else {
+          goto handle_uninterpreted;
+        }
+        if (input->ExpectTag(216)) goto parse_image_height;
+        break;
+      }
+
+      // optional int32 image_height = 27;
+      case 27: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_image_height:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &image_height_)));
+          _set_bit(19);
+        } else {
+          goto handle_uninterpreted;
+        }
         if (input->ExpectAtEnd()) return true;
         break;
       }
@@ -1035,7 +1079,7 @@
   }
   
   // optional float time = 11;
-  if (_has_bit(18)) {
+  if (_has_bit(20)) {
     ::google::protobuf::internal::WireFormatLite::WriteFloat(11, this->time(), output);
   }
   
@@ -1065,13 +1109,13 @@
   }
   
   // optional .com.android.glesv2debugger.Message.Prop prop = 21;
-  if (_has_bit(19)) {
+  if (_has_bit(21)) {
     ::google::protobuf::internal::WireFormatLite::WriteEnum(
       21, this->prop(), output);
   }
   
   // optional float clock = 22;
-  if (_has_bit(20)) {
+  if (_has_bit(22)) {
     ::google::protobuf::internal::WireFormatLite::WriteFloat(22, this->clock(), output);
   }
   
@@ -1091,6 +1135,16 @@
     ::google::protobuf::internal::WireFormatLite::WriteInt32(25, this->pixel_type(), output);
   }
   
+  // optional int32 image_width = 26;
+  if (_has_bit(18)) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(26, this->image_width(), output);
+  }
+
+  // optional int32 image_height = 27;
+  if (_has_bit(19)) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(27, this->image_height(), output);
+  }
+
 }
 
 int Message::ByteSize() const {
@@ -1222,6 +1276,20 @@
           this->pixel_type());
     }
     
+    // optional int32 image_width = 26;
+    if (has_image_width()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->image_width());
+    }
+
+    // optional int32 image_height = 27;
+    if (has_image_height()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->image_height());
+    }
+
     // optional float time = 11;
     if (has_time()) {
       total_size += 1 + 4;
@@ -1312,12 +1380,18 @@
       set_pixel_type(from.pixel_type());
     }
     if (from._has_bit(18)) {
-      set_time(from.time());
+      set_image_width(from.image_width());
     }
     if (from._has_bit(19)) {
-      set_prop(from.prop());
+      set_image_height(from.image_height());
     }
     if (from._has_bit(20)) {
+      set_time(from.time());
+    }
+    if (from._has_bit(21)) {
+      set_prop(from.prop());
+    }
+    if (from._has_bit(22)) {
       set_clock(from.clock());
     }
   }
@@ -1355,6 +1429,8 @@
     std::swap(data_type_, other->data_type_);
     std::swap(pixel_format_, other->pixel_format_);
     std::swap(pixel_type_, other->pixel_type_);
+    std::swap(image_width_, other->image_width_);
+    std::swap(image_height_, other->image_height_);
     std::swap(time_, other->time_);
     std::swap(prop_, other->prop_);
     std::swap(clock_, other->clock_);
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
index b2ec5a0..4ccfebb 100644
--- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
+++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
@@ -236,11 +236,13 @@
 enum Message_Type {
   Message_Type_BeforeCall = 0,
   Message_Type_AfterCall = 1,
-  Message_Type_Response = 2
+  Message_Type_AfterGeneratedCall = 2,
+  Message_Type_Response = 3,
+  Message_Type_CompleteCall = 4
 };
 bool Message_Type_IsValid(int value);
 const Message_Type Message_Type_Type_MIN = Message_Type_BeforeCall;
-const Message_Type Message_Type_Type_MAX = Message_Type_Response;
+const Message_Type Message_Type_Type_MAX = Message_Type_CompleteCall;
 const int Message_Type_Type_ARRAYSIZE = Message_Type_Type_MAX + 1;
 
 enum Message_DataType {
@@ -253,13 +255,14 @@
 const int Message_DataType_DataType_ARRAYSIZE = Message_DataType_DataType_MAX + 1;
 
 enum Message_Prop {
-  Message_Prop_Capture = 0,
+  Message_Prop_CaptureDraw = 0,
   Message_Prop_TimeMode = 1,
-  Message_Prop_ExpectResponse = 2
+  Message_Prop_ExpectResponse = 2,
+  Message_Prop_CaptureSwap = 3
 };
 bool Message_Prop_IsValid(int value);
-const Message_Prop Message_Prop_Prop_MIN = Message_Prop_Capture;
-const Message_Prop Message_Prop_Prop_MAX = Message_Prop_ExpectResponse;
+const Message_Prop Message_Prop_Prop_MIN = Message_Prop_CaptureDraw;
+const Message_Prop Message_Prop_Prop_MAX = Message_Prop_CaptureSwap;
 const int Message_Prop_Prop_ARRAYSIZE = Message_Prop_Prop_MAX + 1;
 
 // ===================================================================
@@ -510,7 +513,9 @@
   typedef Message_Type Type;
   static const Type BeforeCall = Message_Type_BeforeCall;
   static const Type AfterCall = Message_Type_AfterCall;
+  static const Type AfterGeneratedCall = Message_Type_AfterGeneratedCall;
   static const Type Response = Message_Type_Response;
+  static const Type CompleteCall = Message_Type_CompleteCall;
   static inline bool Type_IsValid(int value) {
     return Message_Type_IsValid(value);
   }
@@ -535,9 +540,10 @@
     Message_DataType_DataType_ARRAYSIZE;
   
   typedef Message_Prop Prop;
-  static const Prop Capture = Message_Prop_Capture;
+  static const Prop CaptureDraw = Message_Prop_CaptureDraw;
   static const Prop TimeMode = Message_Prop_TimeMode;
   static const Prop ExpectResponse = Message_Prop_ExpectResponse;
+  static const Prop CaptureSwap = Message_Prop_CaptureSwap;
   static inline bool Prop_IsValid(int value) {
     return Message_Prop_IsValid(value);
   }
@@ -679,6 +685,20 @@
   inline ::google::protobuf::int32 pixel_type() const;
   inline void set_pixel_type(::google::protobuf::int32 value);
   
+  // optional int32 image_width = 26;
+  inline bool has_image_width() const;
+  inline void clear_image_width();
+  static const int kImageWidthFieldNumber = 26;
+  inline ::google::protobuf::int32 image_width() const;
+  inline void set_image_width(::google::protobuf::int32 value);
+
+  // optional int32 image_height = 27;
+  inline bool has_image_height() const;
+  inline void clear_image_height();
+  static const int kImageHeightFieldNumber = 27;
+  inline ::google::protobuf::int32 image_height() const;
+  inline void set_image_height(::google::protobuf::int32 value);
+
   // optional float time = 11;
   inline bool has_time() const;
   inline void clear_time();
@@ -723,6 +743,8 @@
   int data_type_;
   ::google::protobuf::int32 pixel_format_;
   ::google::protobuf::int32 pixel_type_;
+  ::google::protobuf::int32 image_width_;
+  ::google::protobuf::int32 image_height_;
   float time_;
   int prop_;
   float clock_;
@@ -730,7 +752,7 @@
   friend void protobuf_AssignDesc_debugger_5fmessage_2eproto();
   friend void protobuf_ShutdownFile_debugger_5fmessage_2eproto();
   
-  ::google::protobuf::uint32 _has_bits_[(21 + 31) / 32];
+  ::google::protobuf::uint32 _has_bits_[(23 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
   inline bool _has_bit(int index) const {
@@ -1070,52 +1092,84 @@
   pixel_type_ = value;
 }
 
+// optional int32 image_width = 26;
+inline bool Message::has_image_width() const {
+  return _has_bit(18);
+}
+inline void Message::clear_image_width() {
+  image_width_ = 0;
+  _clear_bit(18);
+}
+inline ::google::protobuf::int32 Message::image_width() const {
+  return image_width_;
+}
+inline void Message::set_image_width(::google::protobuf::int32 value) {
+  _set_bit(18);
+  image_width_ = value;
+}
+
+// optional int32 image_height = 27;
+inline bool Message::has_image_height() const {
+  return _has_bit(19);
+}
+inline void Message::clear_image_height() {
+  image_height_ = 0;
+  _clear_bit(19);
+}
+inline ::google::protobuf::int32 Message::image_height() const {
+  return image_height_;
+}
+inline void Message::set_image_height(::google::protobuf::int32 value) {
+  _set_bit(19);
+  image_height_ = value;
+}
+
 // optional float time = 11;
 inline bool Message::has_time() const {
-  return _has_bit(18);
+  return _has_bit(20);
 }
 inline void Message::clear_time() {
   time_ = 0;
-  _clear_bit(18);
+  _clear_bit(20);
 }
 inline float Message::time() const {
   return time_;
 }
 inline void Message::set_time(float value) {
-  _set_bit(18);
+  _set_bit(20);
   time_ = value;
 }
 
 // optional .com.android.glesv2debugger.Message.Prop prop = 21;
 inline bool Message::has_prop() const {
-  return _has_bit(19);
+  return _has_bit(21);
 }
 inline void Message::clear_prop() {
   prop_ = 0;
-  _clear_bit(19);
+  _clear_bit(21);
 }
 inline ::com::android::glesv2debugger::Message_Prop Message::prop() const {
   return static_cast< ::com::android::glesv2debugger::Message_Prop >(prop_);
 }
 inline void Message::set_prop(::com::android::glesv2debugger::Message_Prop value) {
   GOOGLE_DCHECK(::com::android::glesv2debugger::Message_Prop_IsValid(value));
-  _set_bit(19);
+  _set_bit(21);
   prop_ = value;
 }
 
 // optional float clock = 22;
 inline bool Message::has_clock() const {
-  return _has_bit(20);
+  return _has_bit(22);
 }
 inline void Message::clear_clock() {
   clock_ = 0;
-  _clear_bit(20);
+  _clear_bit(22);
 }
 inline float Message::clock() const {
   return clock_;
 }
 inline void Message::set_clock(float value) {
-  _set_bit(20);
+  _set_bit(22);
   clock_ = value;
 }
 
diff --git a/opengl/libs/GLES2_dbg/src/egl.cpp b/opengl/libs/GLES2_dbg/src/egl.cpp
index 3a20e21..eb28d06 100644
--- a/opengl/libs/GLES2_dbg/src/egl.cpp
+++ b/opengl/libs/GLES2_dbg/src/egl.cpp
@@ -18,6 +18,7 @@
 
 EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
 {
+    DbgContext * const dbg = getDbgContextThreadSpecific();
     glesv2debugger::Message msg;
     struct : public FunctionCall {
         EGLDisplay dpy;
@@ -33,7 +34,21 @@
 
     msg.set_arg0(reinterpret_cast<int>(dpy));
     msg.set_arg1(reinterpret_cast<int>(draw));
-
+    if (dbg->captureSwap > 0) {
+        dbg->captureSwap--;
+        int viewport[4] = {};
+        dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
+        void * pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
+                        dbg->readBytesPerPixel);
+        dbg->hooks->gl.glReadPixels(viewport[0], viewport[1], viewport[2],
+                                    viewport[3], dbg->readFormat, dbg->readType, pixels);
+        dbg->CompressReadPixelBuffer(msg.mutable_data());
+        msg.set_data_type(msg.ReferencedImage);
+        msg.set_pixel_format(dbg->readFormat);
+        msg.set_pixel_type(dbg->readType);
+        msg.set_image_width(viewport[2]);
+        msg.set_image_height(viewport[3]);
+    }
     int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_eglSwapBuffers);
     return static_cast<EGLBoolean>(reinterpret_cast<int>(ret));
 }
diff --git a/opengl/libs/GLES2_dbg/src/header.h b/opengl/libs/GLES2_dbg/src/header.h
index 9218da5..c9e6c41 100644
--- a/opengl/libs/GLES2_dbg/src/header.h
+++ b/opengl/libs/GLES2_dbg/src/header.h
@@ -14,6 +14,9 @@
  ** limitations under the License.
  */
 
+#ifndef ANDROID_GLES2_DBG_HEADER_H
+#define ANDROID_GLES2_DBG_HEADER_H
+
 #include <stdlib.h>
 #include <ctype.h>
 #include <string.h>
@@ -24,9 +27,7 @@
 
 #include <cutils/log.h>
 #include <utils/Timers.h>
-#include <../../../libcore/include/StaticAssert.h>
 
-#define EGL_TRACE 1
 #include "hooks.h"
 
 #include "glesv2dbg.h"
@@ -39,8 +40,6 @@
 using namespace android;
 using namespace com::android;
 
-#define API_ENTRY(_api) Debug_##_api
-
 #ifndef __location__
 #define __HIERALLOC_STRING_0__(s)   #s
 #define __HIERALLOC_STRING_1__(s)   __HIERALLOC_STRING_0__(s)
@@ -76,7 +75,7 @@
 struct DbgContext {
 private:
     static const unsigned int LZF_CHUNK_SIZE = 256 * 1024;
-    char * lzf_buf; // malloc / free; for lzf chunk compression
+    char * lzf_buf; // malloc / free; for lzf chunk compression and other uses
 
     // used as buffer and reference frame for ReadPixels; malloc/free
     unsigned * lzf_ref [2];
@@ -84,9 +83,14 @@
     unsigned lzf_refSize, lzf_refBufSize; // bytes
 
 public:
-    const unsigned version; // 0 is GLES1, 1 is GLES2
+    const unsigned int version; // 0 is GLES1, 1 is GLES2
     const gl_hooks_t * const hooks;
-    const unsigned MAX_VERTEX_ATTRIBS;
+    const unsigned int MAX_VERTEX_ATTRIBS;
+    const GLenum readFormat, readType; // implementation supported glReadPixels
+    const unsigned int readBytesPerPixel;
+
+    unsigned int captureSwap; // number of eglSwapBuffers to glReadPixels
+    unsigned int captureDraw; // number of glDrawArrays/Elements to glReadPixels
 
     GLFunctionBitfield expectResponse;
 
@@ -119,7 +123,8 @@
     unsigned maxAttrib; // number of slots used by program
 
     DbgContext(const unsigned version, const gl_hooks_t * const hooks,
-               const unsigned MAX_VERTEX_ATTRIBS);
+               const unsigned MAX_VERTEX_ATTRIBS, const GLenum readFormat,
+               const GLenum readType);
     ~DbgContext();
 
     void Fetch(const unsigned index, std::string * const data) const;
@@ -129,6 +134,8 @@
         return ptr == lzf_ref[lzf_readIndex];
     }
     void CompressReadPixelBuffer(std::string * const outStr);
+    char * GetBuffer(); // allocates lzf_buf if NULL
+    unsigned int GetBufferSize(); // allocates lzf_buf if NULL
 
     void glUseProgram(GLuint program);
     void glEnableVertexAttribArray(GLuint index);
@@ -141,9 +148,7 @@
     void glDeleteBuffers(GLsizei n, const GLuint *buffers);
 };
 
-
 DbgContext * getDbgContextThreadSpecific();
-#define DBGCONTEXT(ctx) DbgContext * const ctx = getDbgContextThreadSpecific();
 
 struct FunctionCall {
     virtual const int * operator()(gl_hooks_t::gl_t const * const _c,
@@ -152,7 +157,6 @@
 };
 
 // move these into DbgContext as static
-extern bool capture;
 extern int timeMode; // SYSTEM_TIME_
 
 extern int clientSock, serverSock;
@@ -169,3 +173,5 @@
 const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message & cmd,
                          glesv2debugger::Message & msg, const int * const prevRet);
 }; // namespace android {
+
+#endif // #ifndef ANDROID_GLES2_DBG_HEADER_H
diff --git a/opengl/libs/GLES2_dbg/src/server.cpp b/opengl/libs/GLES2_dbg/src/server.cpp
index 7039c84..f13d6cc 100644
--- a/opengl/libs/GLES2_dbg/src/server.cpp
+++ b/opengl/libs/GLES2_dbg/src/server.cpp
@@ -28,7 +28,8 @@
 {
 
 int serverSock = -1, clientSock = -1;
-
+FILE * file = NULL;
+unsigned int MAX_FILE_SIZE = 0;
 int timeMode = SYSTEM_TIME_THREAD;
 
 static void Die(const char * msg)
@@ -38,18 +39,25 @@
     exit(1);
 }
 
-void StartDebugServer(unsigned short port)
+void StartDebugServer(const unsigned short port, const bool forceUseFile,
+                      const unsigned int maxFileSize, const char * const filePath)
 {
+    MAX_FILE_SIZE = maxFileSize;
+
     LOGD("GLESv2_dbg: StartDebugServer");
-    if (serverSock >= 0)
+    if (serverSock >= 0 || file)
         return;
 
     LOGD("GLESv2_dbg: StartDebugServer create socket");
     struct sockaddr_in server = {}, client = {};
 
     /* Create the TCP socket */
-    if ((serverSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
-        Die("Failed to create socket");
+    if (forceUseFile || (serverSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+        file = fopen(filePath, "wb");
+        if (!file)
+            Die("Failed to create socket and file");
+        else
+            return;
     }
     /* Construct the server sockaddr_in structure */
     server.sin_family = AF_INET;                  /* Internet/IP */
@@ -92,13 +100,17 @@
         close(serverSock);
         serverSock = -1;
     }
-
+    if (file) {
+        fclose(file);
+        file = NULL;
+    }
 }
 
 void Receive(glesv2debugger::Message & cmd)
 {
+    if (clientSock < 0)
+        return;
     unsigned len = 0;
-
     int received = recv(clientSock, &len, 4, MSG_WAITALL);
     if (received < 0)
         Die("Failed to receive response length");
@@ -106,7 +118,6 @@
         LOGD("received %dB: %.8X", received, len);
         Die("Received length mismatch, expected 4");
     }
-    len = ntohl(len);
     static void * buffer = NULL;
     static unsigned bufferSize = 0;
     if (bufferSize < len) {
@@ -125,6 +136,8 @@
 
 bool TryReceive(glesv2debugger::Message & cmd)
 {
+    if (clientSock < 0)
+        return false;
     fd_set readSet;
     FD_ZERO(&readSet);
     FD_SET(clientSock, &readSet);
@@ -153,7 +166,19 @@
         assert(msg.has_context_id() && msg.context_id() != 0);
     static std::string str;
     msg.SerializeToString(&str);
-    uint32_t len = htonl(str.length());
+    const uint32_t len = str.length();
+    if (clientSock < 0) {
+        if (file) {
+            fwrite(&len, sizeof(len), 1, file);
+            fwrite(str.data(), len, 1, file);
+            if (ftell(file) >= MAX_FILE_SIZE) {
+                fclose(file);
+                Die("MAX_FILE_SIZE reached");
+            }
+        }
+        pthread_mutex_unlock(&mutex);
+        return 0;
+    }
     int sent = -1;
     sent = send(clientSock, &len, sizeof(len), 0);
     if (sent != sizeof(len)) {
@@ -169,14 +194,13 @@
     }
 
     // try to receive commands even though not expecting response,
-    // since client can send SETPROP commands anytime
+    //  since client can send SETPROP and other commands anytime
     if (!msg.expect_response()) {
         if (TryReceive(cmd)) {
-            LOGD("Send: TryReceived");
             if (glesv2debugger::Message_Function_SETPROP == cmd.function())
-                LOGD("Send: received SETPROP");
+                LOGD("Send: TryReceived SETPROP");
             else
-                LOGD("Send: received something else");
+                LOGD("Send: TryReceived %u", cmd.function());
         }
     } else
         Receive(cmd);
@@ -188,9 +212,9 @@
 void SetProp(DbgContext * const dbg, const glesv2debugger::Message & cmd)
 {
     switch (cmd.prop()) {
-    case glesv2debugger::Message_Prop_Capture:
-        LOGD("SetProp Message_Prop_Capture %d", cmd.arg0());
-        capture = cmd.arg0();
+    case glesv2debugger::Message_Prop_CaptureDraw:
+        LOGD("SetProp Message_Prop_CaptureDraw %d", cmd.arg0());
+        dbg->captureDraw = cmd.arg0();
         break;
     case glesv2debugger::Message_Prop_TimeMode:
         LOGD("SetProp Message_Prop_TimeMode %d", cmd.arg0());
@@ -200,6 +224,10 @@
         LOGD("SetProp Message_Prop_ExpectResponse %d=%d", cmd.arg0(), cmd.arg1());
         dbg->expectResponse.Bit((glesv2debugger::Message_Function)cmd.arg0(), cmd.arg1());
         break;
+    case glesv2debugger::Message_Prop_CaptureSwap:
+        LOGD("SetProp CaptureSwap %d", cmd.arg0());
+        dbg->captureSwap = cmd.arg0();
+        break;
     default:
         assert(0);
     }
@@ -213,12 +241,16 @@
     glesv2debugger::Message cmd;
     msg.set_context_id(reinterpret_cast<int>(dbg));
     msg.set_type(glesv2debugger::Message_Type_BeforeCall);
-    const bool expectResponse = dbg->expectResponse.Bit(function);
+    bool expectResponse = dbg->expectResponse.Bit(function);
     msg.set_expect_response(expectResponse);
     msg.set_function(function);
-    if (!expectResponse)
-        cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+
+    // when not exectResponse, set cmd to CONTINUE then SKIP
+    cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+    cmd.set_expect_response(false);
+    glesv2debugger::Message_Function oldCmd = cmd.function();
     Send(msg, cmd);
+    expectResponse = cmd.expect_response();
     while (true) {
         msg.Clear();
         nsecs_t c0 = systemTime(timeMode);
@@ -233,22 +265,34 @@
             msg.set_function(function);
             msg.set_type(glesv2debugger::Message_Type_AfterCall);
             msg.set_expect_response(expectResponse);
-            if (!expectResponse)
+            if (!expectResponse) {
                 cmd.set_function(glesv2debugger::Message_Function_SKIP);
+                cmd.set_expect_response(false);
+            }
+            oldCmd = cmd.function();
             Send(msg, cmd);
+            expectResponse = cmd.expect_response();
             break;
         case glesv2debugger::Message_Function_SKIP:
             return const_cast<int *>(ret);
         case glesv2debugger::Message_Function_SETPROP:
             SetProp(dbg, cmd);
-            Receive(cmd);
+            expectResponse = cmd.expect_response();
+            if (!expectResponse) // SETPROP is "out of band"
+                cmd.set_function(oldCmd);
+            else
+                Receive(cmd);
             break;
         default:
             ret = GenerateCall(dbg, cmd, msg, ret);
             msg.set_expect_response(expectResponse);
-            if (!expectResponse)
+            if (!expectResponse) {
                 cmd.set_function(cmd.SKIP);
+                cmd.set_expect_response(expectResponse);
+            }
+            oldCmd = cmd.function();
             Send(msg, cmd);
+            expectResponse = cmd.expect_response();
             break;
         }
     }
diff --git a/opengl/libs/GLES2_dbg/src/vertex.cpp b/opengl/libs/GLES2_dbg/src/vertex.cpp
index 471e5ad..7edc050 100644
--- a/opengl/libs/GLES2_dbg/src/vertex.cpp
+++ b/opengl/libs/GLES2_dbg/src/vertex.cpp
@@ -21,74 +21,13 @@
 bool capture; // capture after each glDraw*
 }
 
-void Debug_glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
-{
-    DbgContext * const dbg = getDbgContextThreadSpecific();
-    glesv2debugger::Message msg, cmd;
-    msg.set_context_id(reinterpret_cast<int>(dbg));
-    msg.set_type(glesv2debugger::Message_Type_BeforeCall);
-    const bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glReadPixels);
-    msg.set_expect_response(expectResponse);
-    msg.set_function(glesv2debugger::Message_Function_glReadPixels);
-    msg.set_arg0(x);
-    msg.set_arg1(y);
-    msg.set_arg2(width);
-    msg.set_arg3(height);
-    msg.set_arg4(format);
-    msg.set_arg5(type);
-    msg.set_arg6(reinterpret_cast<int>(pixels));
-
-    const unsigned size = width * height * GetBytesPerPixel(format, type);
-    if (!expectResponse)
-        cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
-    Send(msg, cmd);
-    float t = 0;
-    while (true) {
-        msg.Clear();
-        nsecs_t c0 = systemTime(timeMode);
-        switch (cmd.function()) {
-        case glesv2debugger::Message_Function_CONTINUE:
-            dbg->hooks->gl.glReadPixels(x, y, width, height, format, type, pixels);
-            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
-            msg.set_context_id(reinterpret_cast<int>(dbg));
-            msg.set_function(glesv2debugger::Message_Function_glReadPixels);
-            msg.set_type(glesv2debugger::Message_Type_AfterCall);
-            msg.set_expect_response(expectResponse);
-            if (dbg->IsReadPixelBuffer(pixels)) {
-                dbg->CompressReadPixelBuffer(msg.mutable_data());
-                msg.set_data_type(msg.ReferencedImage);
-            } else {
-                dbg->Compress(pixels, size, msg.mutable_data());
-                msg.set_data_type(msg.NonreferencedImage);
-            }
-            if (!expectResponse)
-                cmd.set_function(glesv2debugger::Message_Function_SKIP);
-            Send(msg, cmd);
-            break;
-        case glesv2debugger::Message_Function_SKIP:
-            return;
-        case glesv2debugger::Message_Function_SETPROP:
-            SetProp(dbg, cmd);
-            Receive(cmd);
-            break;
-        default:
-            GenerateCall(dbg, cmd, msg, NULL);
-            msg.set_expect_response(expectResponse);
-            if (!expectResponse)
-                cmd.set_function(cmd.SKIP);
-            Send(msg, cmd);
-            break;
-        }
-    }
-}
-
 void Debug_glDrawArrays(GLenum mode, GLint first, GLsizei count)
 {
     DbgContext * const dbg = getDbgContextThreadSpecific();
     glesv2debugger::Message msg, cmd;
     msg.set_context_id(reinterpret_cast<int>(dbg));
     msg.set_type(glesv2debugger::Message_Type_BeforeCall);
-    const bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawArrays);
+    bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawArrays);
     msg.set_expect_response(expectResponse);
     msg.set_function(glesv2debugger::Message_Function_glDrawArrays);
     msg.set_arg0(mode);
@@ -103,11 +42,14 @@
     }
 
     void * pixels = NULL;
-    GLint readFormat = 0, readType = 0;
     int viewport[4] = {};
-    if (!expectResponse)
+    if (!expectResponse) {
         cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+        cmd.set_expect_response(false);
+    }
+    glesv2debugger::Message_Function oldCmd = cmd.function();
     Send(msg, cmd);
+    expectResponse = cmd.expect_response();
     while (true) {
         msg.Clear();
         nsecs_t c0 = systemTime(timeMode);
@@ -121,31 +63,47 @@
             msg.set_expect_response(expectResponse);
             if (!expectResponse)
                 cmd.set_function(glesv2debugger::Message_Function_SKIP);
+            if (!expectResponse) {
+                cmd.set_function(glesv2debugger::Message_Function_SKIP);
+                cmd.set_expect_response(false);
+            }
+            oldCmd = cmd.function();
             Send(msg, cmd);
-            if (capture) {
+            expectResponse = cmd.expect_response();
+            // TODO: pack glReadPixels data with vertex data instead of
+            //  relying on sperate call for transport, this would allow
+            //  auto generated message loop using EXTEND_Debug macro
+            if (dbg->captureDraw > 0) {
+                dbg->captureDraw--;
                 dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
-                dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat);
-                dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType);
 //                LOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X",
 //                     viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType);
                 pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
-                                                  GetBytesPerPixel(readFormat, readType));
+                                                  dbg->readBytesPerPixel);
                 Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
-                                   readFormat, readType, pixels);
+                                   dbg->readFormat, dbg->readType, pixels);
             }
             break;
         case glesv2debugger::Message_Function_SKIP:
             return;
         case glesv2debugger::Message_Function_SETPROP:
             SetProp(dbg, cmd);
-            Receive(cmd);
+            expectResponse = cmd.expect_response();
+            if (!expectResponse) // SETPROP is "out of band"
+                cmd.set_function(oldCmd);
+            else
+                Receive(cmd);
             break;
         default:
             GenerateCall(dbg, cmd, msg, NULL);
             msg.set_expect_response(expectResponse);
-            if (!expectResponse)
+            if (!expectResponse) {
                 cmd.set_function(cmd.SKIP);
+                cmd.set_expect_response(expectResponse);
+            }
+            oldCmd = cmd.function();
             Send(msg, cmd);
+            expectResponse = cmd.expect_response();
             break;
         }
     }
@@ -169,7 +127,7 @@
     glesv2debugger::Message msg, cmd;
     msg.set_context_id(reinterpret_cast<int>(dbg));
     msg.set_type(glesv2debugger::Message_Type_BeforeCall);
-    const bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawElements);
+    bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawElements);
     msg.set_expect_response(expectResponse);
     msg.set_function(glesv2debugger::Message_Function_glDrawElements);
     msg.set_arg0(mode);
@@ -195,11 +153,14 @@
         assert(0);
 
     void * pixels = NULL;
-    GLint readFormat = 0, readType = 0;
     int viewport[4] = {};
-    if (!expectResponse)
+    if (!expectResponse) {
         cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+        cmd.set_expect_response(false);
+    }
+    glesv2debugger::Message_Function oldCmd = cmd.function();
     Send(msg, cmd);
+    expectResponse = cmd.expect_response();
     while (true) {
         msg.Clear();
         nsecs_t c0 = systemTime(timeMode);
@@ -213,31 +174,45 @@
             msg.set_expect_response(expectResponse);
             if (!expectResponse)
                 cmd.set_function(glesv2debugger::Message_Function_SKIP);
+            if (!expectResponse) {
+                cmd.set_function(glesv2debugger::Message_Function_SKIP);
+                cmd.set_expect_response(false);
+            }
+            oldCmd = cmd.function();
             Send(msg, cmd);
-            if (capture) {
+            expectResponse = cmd.expect_response();
+            // TODO: pack glReadPixels data with vertex data instead of
+            //  relying on sperate call for transport, this would allow
+            //  auto generated message loop using EXTEND_Debug macro
+            if (dbg->captureDraw > 0) {
+                dbg->captureDraw--;
                 dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
-                dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat);
-                dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType);
-//                LOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X",
-//                     viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType);
                 pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
-                                                  GetBytesPerPixel(readFormat, readType));
+                                                  dbg->readBytesPerPixel);
                 Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
-                                   readFormat, readType, pixels);
+                                   dbg->readFormat, dbg->readType, pixels);
             }
             break;
         case glesv2debugger::Message_Function_SKIP:
             return;
         case glesv2debugger::Message_Function_SETPROP:
             SetProp(dbg, cmd);
-            Receive(cmd);
+            expectResponse = cmd.expect_response();
+            if (!expectResponse) // SETPROP is "out of band"
+                cmd.set_function(oldCmd);
+            else
+                Receive(cmd);
             break;
         default:
             GenerateCall(dbg, cmd, msg, NULL);
             msg.set_expect_response(expectResponse);
-            if (!expectResponse)
+            if (!expectResponse) {
                 cmd.set_function(cmd.SKIP);
+                cmd.set_expect_response(expectResponse);
+            }
+            oldCmd = cmd.function();
             Send(msg, cmd);
+            expectResponse = cmd.expect_response();
             break;
         }
     }
diff --git a/opengl/libs/egl_tls.h b/opengl/libs/egl_tls.h
new file mode 100644
index 0000000..087989a
--- /dev/null
+++ b/opengl/libs/egl_tls.h
@@ -0,0 +1,40 @@
+/*
+ ** Copyright 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 ANDROID_EGL_TLS_H
+#define ANDROID_EGL_TLS_H
+
+#include <EGL/egl.h>
+
+#include "glesv2dbg.h"
+
+namespace android
+{
+struct tls_t {
+    tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE), dbg(0) { }
+    ~tls_t() {
+        if (dbg)
+            DestroyDbgContext(dbg);
+    }
+
+    EGLint      error;
+    EGLContext  ctx;
+    EGLBoolean  logCallWithNoContext;
+    DbgContext* dbg;
+};
+}
+
+#endif
diff --git a/opengl/libs/glesv2dbg.h b/opengl/libs/glesv2dbg.h
index 8029dce..ee2c011 100644
--- a/opengl/libs/glesv2dbg.h
+++ b/opengl/libs/glesv2dbg.h
@@ -13,20 +13,27 @@
  ** See the License for the specific language governing permissions and
  ** limitations under the License.
  */
- 
+
 #ifndef _GLESV2_DBG_H_
 #define _GLESV2_DBG_H_
 
+#include <pthread.h>
+
 namespace android
 {
-    struct DbgContext;
-    
-    DbgContext * CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks);
-    void DestroyDbgContext(DbgContext * const dbg);
-    
-    void StartDebugServer(unsigned short port); // create and bind socket if haven't already
-    void StopDebugServer(); // close socket if open
-    
+struct DbgContext;
+
+DbgContext * CreateDbgContext(const pthread_key_t EGLThreadLocalStorageKey,
+                              const unsigned version, const gl_hooks_t * const hooks);
+
+void DestroyDbgContext(DbgContext * const dbg);
+
+// create and bind socket if haven't already, if failed to create socket or
+//  forceUseFile, then open /data/local/tmp/dump.gles2dbg, exit when size reached
+void StartDebugServer(const unsigned short port, const bool forceUseFile,
+                      const unsigned int maxFileSize, const char * const filePath);
+void StopDebugServer(); // close socket if open
+
 }; // namespace android
 
 #endif // #ifndef _GLESV2_DBG_H_
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 5853696..9ff5233 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -49,8 +49,9 @@
 import android.util.Log;
 
 import com.android.internal.telephony.Phone;
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
+import com.android.internal.util.IState;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -122,7 +123,7 @@
     // resampled each time we turn on tethering - used as cache for settings/config-val
     private boolean mDunRequired;  // configuration info - must use DUN apn on 3g
 
-    private HierarchicalStateMachine mTetherMasterSM;
+    private StateMachine mTetherMasterSM;
 
     private Notification mTetheredNotification;
 
@@ -668,7 +669,7 @@
     }
 
 
-    class TetherInterfaceSM extends HierarchicalStateMachine {
+    class TetherInterfaceSM extends StateMachine {
         // notification from the master SM that it's not in tether mode
         static final int CMD_TETHER_MODE_DEAD            =  1;
         // request from the user that it wants to tether
@@ -694,13 +695,13 @@
         // the upstream connection has changed
         static final int CMD_TETHER_CONNECTION_CHANGED   = 12;
 
-        private HierarchicalState mDefaultState;
+        private State mDefaultState;
 
-        private HierarchicalState mInitialState;
-        private HierarchicalState mStartingState;
-        private HierarchicalState mTetheredState;
+        private State mInitialState;
+        private State mStartingState;
+        private State mTetheredState;
 
-        private HierarchicalState mUnavailableState;
+        private State mUnavailableState;
 
         private boolean mAvailable;
         private boolean mTethered;
@@ -732,7 +733,7 @@
         public String toString() {
             String res = new String();
             res += mIfaceName + " - ";
-            HierarchicalState current = getCurrentState();
+            IState current = getCurrentState();
             if (current == mInitialState) res += "InitialState";
             if (current == mStartingState) res += "StartingState";
             if (current == mTetheredState) res += "TetheredState";
@@ -782,7 +783,7 @@
             return (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR);
         }
 
-        class InitialState extends HierarchicalState {
+        class InitialState extends State {
             @Override
             public void enter() {
                 setAvailable(true);
@@ -812,7 +813,7 @@
             }
         }
 
-        class StartingState extends HierarchicalState {
+        class StartingState extends State {
             @Override
             public void enter() {
                 setAvailable(false);
@@ -870,7 +871,7 @@
             }
         }
 
-        class TetheredState extends HierarchicalState {
+        class TetheredState extends State {
             @Override
             public void enter() {
                 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
@@ -1034,7 +1035,7 @@
             }
         }
 
-        class UnavailableState extends HierarchicalState {
+        class UnavailableState extends State {
             @Override
             public void enter() {
                 setAvailable(false);
@@ -1064,7 +1065,7 @@
 
     }
 
-    class TetherMasterSM extends HierarchicalStateMachine {
+    class TetherMasterSM extends StateMachine {
         // an interface SM has requested Tethering
         static final int CMD_TETHER_MODE_REQUESTED   = 1;
         // an interface SM has unrequested Tethering
@@ -1082,14 +1083,14 @@
         // We do not flush the old ones.
         private int mSequenceNumber;
 
-        private HierarchicalState mInitialState;
-        private HierarchicalState mTetherModeAliveState;
+        private State mInitialState;
+        private State mTetherModeAliveState;
 
-        private HierarchicalState mSetIpForwardingEnabledErrorState;
-        private HierarchicalState mSetIpForwardingDisabledErrorState;
-        private HierarchicalState mStartTetheringErrorState;
-        private HierarchicalState mStopTetheringErrorState;
-        private HierarchicalState mSetDnsForwardersErrorState;
+        private State mSetIpForwardingEnabledErrorState;
+        private State mSetIpForwardingDisabledErrorState;
+        private State mStartTetheringErrorState;
+        private State mStopTetheringErrorState;
+        private State mSetDnsForwardersErrorState;
 
         private ArrayList mNotifyList;
 
@@ -1125,7 +1126,7 @@
             setInitialState(mInitialState);
         }
 
-        class TetherMasterUtilState extends HierarchicalState {
+        class TetherMasterUtilState extends State {
             protected final static boolean TRY_TO_SETUP_MOBILE_CONNECTION = true;
             protected final static boolean WAIT_FOR_NETWORK_TO_SETTLE     = false;
 
@@ -1440,7 +1441,7 @@
             }
         }
 
-        class ErrorState extends HierarchicalState {
+        class ErrorState extends State {
             int mErrorNotification;
             @Override
             public boolean processMessage(Message message) {
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 64cff96..a774841 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -93,7 +93,11 @@
 int DisplayHardware::getHeight() const          { return mHeight; }
 PixelFormat DisplayHardware::getFormat() const  { return mFormat; }
 uint32_t DisplayHardware::getMaxTextureSize() const { return mMaxTextureSize; }
-uint32_t DisplayHardware::getMaxViewportDims() const { return mMaxViewportDims; }
+
+uint32_t DisplayHardware::getMaxViewportDims() const {
+    return mMaxViewportDims[0] < mMaxViewportDims[1] ?
+            mMaxViewportDims[0] : mMaxViewportDims[1];
+}
 
 void DisplayHardware::init(uint32_t dpy)
 {
@@ -228,7 +232,7 @@
             eglQueryString(display, EGL_EXTENSIONS));
 
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
-    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &mMaxViewportDims);
+    glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
 
 
 #ifdef EGL_ANDROID_swap_rectangle
@@ -260,7 +264,7 @@
     LOGI("version   : %s", extensions.getVersion());
     LOGI("extensions: %s", extensions.getExtension());
     LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
-    LOGI("GL_MAX_VIEWPORT_DIMS = %d", mMaxViewportDims);
+    LOGI("GL_MAX_VIEWPORT_DIMS = %d x %d", mMaxViewportDims[0], mMaxViewportDims[1]);
     LOGI("flags = %08x", mFlags);
 
     // Unbind the context from this thread
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index ee7a2af..cdf89fd 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -108,7 +108,7 @@
     PixelFormat     mFormat;
     uint32_t        mFlags;
     mutable uint32_t mPageFlipCount;
-    GLint           mMaxViewportDims;
+    GLint           mMaxViewportDims[2];
     GLint           mMaxTextureSize;
     
     HWComposer*     mHwc;
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 0c47e86..791fbfd 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -17,8 +17,8 @@
 package com.android.internal.telephony;
 
 
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
 
 import android.net.LinkAddress;
 import android.net.LinkCapabilities;
@@ -37,7 +37,7 @@
 /**
  * {@hide}
  *
- * DataConnection HierarchicalStateMachine.
+ * DataConnection StateMachine.
  *
  * This is an abstract base class for representing a single data connection.
  * Instances of this class such as <code>CdmaDataConnection</code> and
@@ -55,7 +55,7 @@
  *
  * The other public methods are provided for debugging.
  */
-public abstract class DataConnection extends HierarchicalStateMachine {
+public abstract class DataConnection extends StateMachine {
     protected static final boolean DBG = true;
 
     protected static Object mCountLock = new Object();
@@ -484,17 +484,17 @@
     /**
      * The parent state for all other states.
      */
-    private class DcDefaultState extends HierarchicalState {
+    private class DcDefaultState extends State {
         @Override
-        protected void enter() {
+        public void enter() {
             phone.mCM.registerForRilConnected(getHandler(), EVENT_RIL_CONNECTED, null);
         }
         @Override
-        protected void exit() {
+        public void exit() {
             phone.mCM.unregisterForRilConnected(getHandler());
         }
         @Override
-        protected boolean processMessage(Message msg) {
+        public boolean processMessage(Message msg) {
             AsyncResult ar;
 
             switch (msg.what) {
@@ -547,7 +547,7 @@
     /**
      * The state machine is inactive and expects a EVENT_CONNECT.
      */
-    private class DcInactiveState extends HierarchicalState {
+    private class DcInactiveState extends State {
         private ConnectionParams mConnectionParams = null;
         private FailCause mFailCause = null;
         private DisconnectParams mDisconnectParams = null;
@@ -563,7 +563,8 @@
             mDisconnectParams = dp;
         }
 
-        @Override protected void enter() {
+        @Override
+        public void enter() {
             mTag += 1;
 
             /**
@@ -583,14 +584,16 @@
             }
         }
 
-        @Override protected void exit() {
+        @Override
+        public void exit() {
             // clear notifications
             mConnectionParams = null;
             mFailCause = null;
             mDisconnectParams = null;
         }
 
-        @Override protected boolean processMessage(Message msg) {
+        @Override
+        public boolean processMessage(Message msg) {
             boolean retVal;
 
             switch (msg.what) {
@@ -626,8 +629,9 @@
     /**
      * The state machine is activating a connection.
      */
-    private class DcActivatingState extends HierarchicalState {
-        @Override protected boolean processMessage(Message msg) {
+    private class DcActivatingState extends State {
+        @Override
+        public boolean processMessage(Message msg) {
             boolean retVal;
             AsyncResult ar;
             ConnectionParams cp;
@@ -722,7 +726,7 @@
     /**
      * The state machine is connected, expecting an EVENT_DISCONNECT.
      */
-    private class DcActiveState extends HierarchicalState {
+    private class DcActiveState extends State {
         private ConnectionParams mConnectionParams = null;
         private FailCause mFailCause = null;
 
@@ -746,13 +750,15 @@
             }
         }
 
-        @Override protected void exit() {
+        @Override
+        public void exit() {
             // clear notifications
             mConnectionParams = null;
             mFailCause = null;
         }
 
-        @Override protected boolean processMessage(Message msg) {
+        @Override
+        public boolean processMessage(Message msg) {
             boolean retVal;
 
             switch (msg.what) {
@@ -778,8 +784,9 @@
     /**
      * The state machine is disconnecting.
      */
-    private class DcDisconnectingState extends HierarchicalState {
-        @Override protected boolean processMessage(Message msg) {
+    private class DcDisconnectingState extends State {
+        @Override
+        public boolean processMessage(Message msg) {
             boolean retVal;
 
             switch (msg.what) {
@@ -812,8 +819,9 @@
     /**
      * The state machine is disconnecting after an creating a connection.
      */
-    private class DcDisconnectionErrorCreatingConnection extends HierarchicalState {
-        @Override protected boolean processMessage(Message msg) {
+    private class DcDisconnectionErrorCreatingConnection extends State {
+        @Override
+        public boolean processMessage(Message msg) {
             boolean retVal;
 
             switch (msg.what) {
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 488794f..56be570 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -159,8 +159,8 @@
     static final String REASON_ROAMING_OFF = "roamingOff";
     static final String REASON_DATA_DISABLED = "dataDisabled";
     static final String REASON_DATA_ENABLED = "dataEnabled";
-    static final String REASON_GPRS_ATTACHED = "gprsAttached";
-    static final String REASON_GPRS_DETACHED = "gprsDetached";
+    static final String REASON_DATA_ATTACHED = "dataAttached";
+    static final String REASON_DATA_DETACHED = "dataDetached";
     static final String REASON_CDMA_DATA_ATTACHED = "cdmaDataAttached";
     static final String REASON_CDMA_DATA_DETACHED = "cdmaDataDetached";
     static final String REASON_APN_CHANGED = "apnChanged";
diff --git a/telephony/java/com/android/internal/telephony/cat/RilMessageDecoder.java b/telephony/java/com/android/internal/telephony/cat/RilMessageDecoder.java
index a197c9a..2a1f508 100644
--- a/telephony/java/com/android/internal/telephony/cat/RilMessageDecoder.java
+++ b/telephony/java/com/android/internal/telephony/cat/RilMessageDecoder.java
@@ -20,15 +20,15 @@
 import com.android.internal.telephony.IccUtils;
 
 import android.os.Handler;
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
 import android.os.Message;
 
 /**
  * Class used for queuing raw ril messages, decoding them into CommanParams
  * objects and sending the result back to the CAT Service.
  */
-class RilMessageDecoder extends HierarchicalStateMachine {
+class RilMessageDecoder extends StateMachine {
 
     // constants
     private static final int CMD_START = 1;
@@ -101,8 +101,9 @@
         mCmdParamsFactory = CommandParamsFactory.getInstance(this, fh);
     }
 
-    private class StateStart extends HierarchicalState {
-        @Override protected boolean processMessage(Message msg) {
+    private class StateStart extends State {
+        @Override
+        public boolean processMessage(Message msg) {
             if (msg.what == CMD_START) {
                 if (decodeMessageParams((RilMessage)msg.obj)) {
                     transitionTo(mStateCmdParamsReady);
@@ -115,8 +116,9 @@
         }
     }
 
-    private class StateCmdParamsReady extends HierarchicalState {
-        @Override protected boolean processMessage(Message msg) {
+    private class StateCmdParamsReady extends State {
+        @Override
+        public boolean processMessage(Message msg) {
             if (msg.what == CMD_PARAMS_READY) {
                 mCurrentRilMessage.mResCode = ResultCode.fromInt(msg.arg1);
                 mCurrentRilMessage.mData = msg.obj;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 9a91ee4..fc1d536 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -505,9 +505,8 @@
         ApnContext apnContext = mApnContexts.get(type);
 
         if (apnContext != null) {
-            apnContext.setPendingAction(ApnContext.PENDING_ACTION_APN_DISABLE);
-
             if (apnContext.getState() != State.IDLE && apnContext.getState() != State.FAILED) {
+                apnContext.setPendingAction(ApnContext.PENDING_ACTION_APN_DISABLE);
                 Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
                 msg.arg1 = 1; // tearDown is true;
                 // TODO - don't set things on apnContext from public functions.
@@ -519,6 +518,7 @@
                 return Phone.APN_REQUEST_STARTED;
             } else {
                 if (DBG) log("return APN_ALREADY_INACTIVE");
+                apnContext.setEnabled(false);
                 return Phone.APN_ALREADY_INACTIVE;
             }
 
@@ -582,26 +582,16 @@
          * when GPRS detaches, but we should stop the network polling.
          */
         stopNetStatPoll();
-        notifyDataConnection(Phone.REASON_GPRS_DETACHED);
+        notifyDataConnection(Phone.REASON_DATA_DETACHED);
     }
 
     private void onDataConnectionAttached() {
         if (getOverallState() == State.CONNECTED) {
             startNetStatPoll();
-            notifyDataConnection(Phone.REASON_GPRS_ATTACHED);
-        } else {
-            // Only check for default APN state
-            ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
-            if (defaultApnContext != null) {
-                if (defaultApnContext.getState() == State.FAILED) {
-                    cleanUpConnection(false, defaultApnContext);
-                    if (defaultApnContext.getDataConnection() != null) {
-                        defaultApnContext.getDataConnection().resetRetryCount();
-                    }
-                }
-                trySetupData(Phone.REASON_GPRS_ATTACHED, Phone.APN_TYPE_DEFAULT);
-            }
+            notifyDataConnection(Phone.REASON_DATA_ATTACHED);
         }
+
+        setupDataOnReadyApns(Phone.REASON_DATA_ATTACHED);
     }
 
     @Override
@@ -610,7 +600,7 @@
         boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
 
         boolean allowed =
-                    (gprsState == ServiceState.STATE_IN_SERVICE || mAutoAttachOnCreation) &&
+                    gprsState == ServiceState.STATE_IN_SERVICE &&
                     mPhone.mSIMRecords.getRecordsLoaded() &&
                     mPhone.getState() == Phone.State.IDLE &&
                     mInternalDataEnabled &&
@@ -619,7 +609,7 @@
                     desiredPowerState;
         if (!allowed && DBG) {
             String reason = "";
-            if (!((gprsState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) {
+            if (!(gprsState == ServiceState.STATE_IN_SERVICE)) {
                 reason += " - gprs= " + gprsState;
             }
             if (!mPhone.mSIMRecords.getRecordsLoaded()) reason += " - SIM not loaded";
@@ -637,6 +627,26 @@
         return allowed;
     }
 
+    private void setupDataOnReadyApns(String reason) {
+        // Only check for default APN state
+        for (ApnContext apnContext : mApnContexts.values()) {
+            if (apnContext.isReady()) {
+                if (apnContext.getState() == State.FAILED) {
+                    cleanUpConnection(false, apnContext);
+                    if (apnContext.getDataConnection() != null) {
+                        apnContext.getDataConnection().resetRetryCount();
+                    }
+                }
+                // Do not start ApnContext in SCANNING state
+                // FAILED state must be reset to IDLE by now
+                if (apnContext.getState() == State.IDLE) {
+                    apnContext.setReason(reason);
+                    trySetupData(apnContext);
+                }
+            }
+        }
+    }
+
     private boolean trySetupData(String reason, String type) {
         if (DBG) {
             log("***trySetupData for type:" + type +
@@ -973,10 +983,7 @@
         createAllApnList();
         cleanUpAllConnections(isConnected, Phone.REASON_APN_CHANGED);
         if (!isConnected) {
-            // TODO: Won't work for multiple connections!!!!
-            defaultApnContext.getDataConnection().resetRetryCount();
-            defaultApnContext.setReason(Phone.REASON_APN_CHANGED);
-            trySetupData(defaultApnContext);
+            setupDataOnReadyApns(Phone.REASON_APN_CHANGED);
         }
     }
 
@@ -1316,18 +1323,7 @@
     private void onRecordsLoaded() {
         if (DBG) log("onRecordsLoaded: createAllApnList");
         createAllApnList();
-        for (ApnContext apnContext : mApnContexts.values()) {
-            if (apnContext.isReady()) {
-                apnContext.setReason(Phone.REASON_SIM_LOADED);
-                if (apnContext.getState() == State.FAILED) {
-                    if (DBG) {
-                        log("onRecordsLoaded clean connection for " + apnContext.getApnType());
-                    }
-                    cleanUpConnection(false, apnContext);
-                }
-                sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext));
-            }
-        }
+        setupDataOnReadyApns(Phone.REASON_SIM_LOADED);
     }
 
     @Override
@@ -1413,7 +1409,8 @@
     @Override
     // TODO: We shouldnt need this.
     protected boolean onTrySetupData(String reason) {
-        return trySetupData(reason, Phone.APN_TYPE_DEFAULT);
+        setupDataOnReadyApns(reason);
+        return true;
     }
 
     protected boolean onTrySetupData(ApnContext apnContext) {
@@ -1421,16 +1418,14 @@
     }
 
     @Override
-    // TODO: Need to understand if more than DEFAULT is impacted?
     protected void onRoamingOff() {
-        trySetupData(Phone.REASON_ROAMING_OFF, Phone.APN_TYPE_DEFAULT);
+        setupDataOnReadyApns(Phone.REASON_ROAMING_OFF);
     }
 
     @Override
-    // TODO: Need to understand if more than DEFAULT is impacted?
     protected void onRoamingOn() {
         if (getDataOnRoamingEnabled()) {
-            trySetupData(Phone.REASON_ROAMING_ON, Phone.APN_TYPE_DEFAULT);
+            setupDataOnReadyApns(Phone.REASON_ROAMING_ON);
         } else {
             if (DBG) log("Tear down data connection on roaming.");
             cleanUpAllConnections(true, Phone.REASON_ROAMING_ON);
@@ -1618,14 +1613,12 @@
             }
         }
 
-        if (TextUtils.equals(apnContext.getApnType(), Phone.APN_TYPE_DEFAULT)
-            && retryAfterDisconnected(apnContext.getReason())) {
+        // If APN is still enabled, try to bring it back up automatically
+        if (apnContext.isReady() && retryAfterDisconnected(apnContext.getReason())) {
             SystemProperties.set("gsm.defaultpdpcontext.active", "false");
-            trySetupData(apnContext);
-        }
-        else if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_RECONNECT)
-        {
-            apnContext.setPendingAction(ApnContext.PENDING_ACTION_NONE);
+            if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_RECONNECT) {
+                apnContext.setPendingAction(ApnContext.PENDING_ACTION_NONE);
+            }
             trySetupData(apnContext);
         }
     }
@@ -1658,13 +1651,7 @@
             }
         } else {
             // reset reconnect timer
-            ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
-            if (defaultApnContext != null) {
-                defaultApnContext.getDataConnection().resetRetryCount();
-                mReregisterOnReconnectFailure = false;
-                // in case data setup was attempted when we were on a voice call
-                trySetupData(Phone.REASON_VOICE_CALL_ENDED, Phone.APN_TYPE_DEFAULT);
-            }
+            setupDataOnReadyApns(Phone.REASON_VOICE_CALL_ENDED);
         }
     }
 
diff --git a/tests/BiDiTests/AndroidManifest.xml b/tests/BiDiTests/AndroidManifest.xml
index 346ace8..727f980 100644
--- a/tests/BiDiTests/AndroidManifest.xml
+++ b/tests/BiDiTests/AndroidManifest.xml
@@ -25,7 +25,8 @@
     android:versionName="1.0">
 
     <application android:label="BiDiTests">
-        <activity android:name="BiDiTestActivity">
+        <activity android:name="BiDiTestActivity"
+                android:windowSoftInputMode="stateAlwaysHidden">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml
index 632a02e..d20600e 100644
--- a/tests/BiDiTests/res/values/strings.xml
+++ b/tests/BiDiTests/res/values/strings.xml
@@ -20,9 +20,10 @@
     <string name="normal_long_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
     <string name="normal_long_text_2">nnnnnnnnnnnnnnnnnnnnnnnn</string>
     <string name="normal_long_text_3">Notify me when an open network is available</string>
-    <string name="arabic_text">&#x0644;&#x0627;</string>
+    <string name="arabic_text">&#x0644;&#x0627; &#x0627;&#x0646;&#x0627; hello world</string>
     <string name="chinese_text">利比亚局势或影响美俄关系发展</string>
     <string name="italic_text">Italic String</string>
     <string name="bold_text">Bold String - other text</string>
     <string name="bold_italic_text">Bold Italic String</string>
+    <string name="mixed_text_1">he said in Arabic: &#x0644;&#x0627;. Wow this is cool</string>
 </resources>
\ No newline at end of file
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
index f00bd06..2f9b026 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
@@ -49,6 +49,7 @@
     private String BOLD_ITALIC_TEXT;
     private String ARABIC_TEXT;
     private String CHINESE_TEXT;
+    private String MIXED_TEXT_1;
 
     private Typeface typeface;
 
@@ -79,6 +80,7 @@
         BOLD_ITALIC_TEXT = context.getString(R.string.bold_italic_text);
         ARABIC_TEXT = context.getString(R.string.arabic_text);
         CHINESE_TEXT = context.getString(R.string.chinese_text);
+        MIXED_TEXT_1 = context.getString(R.string.mixed_text_1);
 
         typeface = paint.getTypeface();
         paint.setAntiAlias(true);
@@ -124,6 +126,10 @@
         // Test Chinese
         deltaX = testString(canvas, CHINESE_TEXT, ORIGIN, ORIGIN + 10 * currentTextSize,
                 paint, typeface, false, false,  Paint.DIRECTION_LTR, currentTextSize);
+
+        // Test Mixed (English and Arabic)
+        deltaX = testString(canvas, MIXED_TEXT_1, ORIGIN, ORIGIN + 12 * currentTextSize,
+                paint, typeface, false, false,  Paint.DIRECTION_LTR, currentTextSize);
     }
 
     private int testString(Canvas canvas, String text, int x, int y, Paint paint, Typeface typeface,
@@ -139,12 +145,15 @@
             paint.setTextSkewX(DEFAULT_ITALIC_SKEW_X);
         }
 
-        drawTextWithCanvasDrawText(text, canvas, x, y, textSize, Color.WHITE);
+        Log.v(TAG, "START -- drawTextWithCanvasDrawText");
+        drawTextWithCanvasDrawText(text, canvas, x, y, textSize, Color.WHITE, dir);
+        Log.v(TAG, "END   -- drawTextWithCanvasDrawText");
 
         int length = text.length();
         float[] advances = new float[length];
-        float textWidthHB = paint.getTextRunAdvances(text, 0, length, 0, length, 0, advances, 0);
-        float textWidthICU = paint.getTextRunAdvancesICU(text, 0, length, 0, length, 0, advances, 0);
+        float textWidthHB = paint.getTextRunAdvances(text, 0, length, 0, length, dir, advances, 0);
+        setPaintDir(paint, dir);
+        float textWidthICU = paint.getTextRunAdvancesICU(text, 0, length, 0, length, dir, advances, 0);
 
         logAdvances(text, textWidthHB, textWidthICU, advances);
         drawMetricsAroundText(canvas, x, y, textWidthHB, textWidthICU, textSize, Color.RED, Color.GREEN);
@@ -156,7 +165,9 @@
 //        logGlypths(glyphs, count);
 //        drawTextWithDrawGlyph(canvas, glyphs, count, x, y + currentTextSize);
 
+        Log.v(TAG, "START -- drawTextWithGlyphs");
         drawTextWithGlyphs(canvas, text, x, y + currentTextSize, dir);
+        Log.v(TAG, "END   -- drawTextWithGlyphs");
 
         // Restore old paint properties
         paint.setFakeBoldText(oldFakeBold);
@@ -165,12 +176,17 @@
         return (int) Math.ceil(textWidthHB) + TEXT_PADDING;
     }
 
+    private void setPaintDir(Paint paint, int dir) {
+        Log.v(TAG, "Setting Paint dir=" + dir);
+        paint.setBidiFlags(dir);
+    }
+
     private void drawTextWithDrawGlyph(Canvas canvas, char[] glyphs, int count, int x, int y) {
         canvas.drawGlyphs(glyphs, 0, count, x, y, paint);
     }
 
     private void drawTextWithGlyphs(Canvas canvas, String text, int x, int y, int dir) {
-        paint.setBidiFlags(dir);
+        setPaintDir(paint, dir);
         canvas.drawTextWithGlyphs(text, x, y, paint);
     }
 
@@ -182,7 +198,6 @@
     }
 
     private int getGlyphs(String text, char[] glyphs, int dir) {
-//        int dir = 1; // Paint.DIRECTION_LTR;
         return paint.getTextGlypths(text, 0, text.length(), 0, text.length(), dir, glyphs);
     }
 
@@ -195,7 +210,8 @@
     }
 
     private void drawTextWithCanvasDrawText(String text, Canvas canvas,
-            float x, float y, float textSize, int color) {
+            float x, float y, float textSize, int color, int dir) {
+        setPaintDir(paint, dir);
         paint.setColor(color);
         paint.setTextSize(textSize);
         canvas.drawText(text, x, y, paint);
diff --git a/wifi/java/android/net/wifi/SupplicantStateTracker.java b/wifi/java/android/net/wifi/SupplicantStateTracker.java
index 3cde949..9ae26da 100644
--- a/wifi/java/android/net/wifi/SupplicantStateTracker.java
+++ b/wifi/java/android/net/wifi/SupplicantStateTracker.java
@@ -16,8 +16,8 @@
 
 package android.net.wifi;
 
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
 
 import android.net.wifi.WifiStateMachine.StateChangeResult;
 import android.content.Context;
@@ -33,7 +33,7 @@
  * - detect a failed WPA handshake that loops indefinitely
  * - authentication failure handling
  */
-class SupplicantStateTracker extends HierarchicalStateMachine {
+class SupplicantStateTracker extends StateMachine {
 
     private static final String TAG = "SupplicantStateTracker";
     private static final boolean DBG = false;
@@ -53,14 +53,14 @@
 
     private Context mContext;
 
-    private HierarchicalState mUninitializedState = new UninitializedState();
-    private HierarchicalState mDefaultState = new DefaultState();
-    private HierarchicalState mInactiveState = new InactiveState();
-    private HierarchicalState mDisconnectState = new DisconnectedState();
-    private HierarchicalState mScanState = new ScanState();
-    private HierarchicalState mHandshakeState = new HandshakeState();
-    private HierarchicalState mCompletedState = new CompletedState();
-    private HierarchicalState mDormantState = new DormantState();
+    private State mUninitializedState = new UninitializedState();
+    private State mDefaultState = new DefaultState();
+    private State mInactiveState = new InactiveState();
+    private State mDisconnectState = new DisconnectedState();
+    private State mScanState = new ScanState();
+    private State mHandshakeState = new HandshakeState();
+    private State mCompletedState = new CompletedState();
+    private State mDormantState = new DormantState();
 
     public SupplicantStateTracker(Context context, WifiStateMachine wsm, Handler target) {
         super(TAG, target.getLooper());
@@ -146,7 +146,7 @@
      * HSM states
      *******************************************************/
 
-    class DefaultState extends HierarchicalState {
+    class DefaultState extends State {
         @Override
          public void enter() {
              if (DBG) Log.d(TAG, getName() + "\n");
@@ -188,21 +188,21 @@
      * or after we have lost the control channel
      * connection to the supplicant
      */
-    class UninitializedState extends HierarchicalState {
+    class UninitializedState extends State {
         @Override
          public void enter() {
              if (DBG) Log.d(TAG, getName() + "\n");
          }
     }
 
-    class InactiveState extends HierarchicalState {
+    class InactiveState extends State {
         @Override
          public void enter() {
              if (DBG) Log.d(TAG, getName() + "\n");
          }
     }
 
-    class DisconnectedState extends HierarchicalState {
+    class DisconnectedState extends State {
         @Override
          public void enter() {
              if (DBG) Log.d(TAG, getName() + "\n");
@@ -221,14 +221,14 @@
          }
     }
 
-    class ScanState extends HierarchicalState {
+    class ScanState extends State {
         @Override
          public void enter() {
              if (DBG) Log.d(TAG, getName() + "\n");
          }
     }
 
-    class HandshakeState extends HierarchicalState {
+    class HandshakeState extends State {
         /**
          * The max number of the WPA supplicant loop iterations before we
          * decide that the loop should be terminated:
@@ -277,7 +277,7 @@
         }
     }
 
-    class CompletedState extends HierarchicalState {
+    class CompletedState extends State {
         @Override
          public void enter() {
              if (DBG) Log.d(TAG, getName() + "\n");
@@ -318,7 +318,7 @@
     }
 
     //TODO: remove after getting rid of the state in supplicant
-    class DormantState extends HierarchicalState {
+    class DormantState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 46c07a3..f7157d4 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -73,8 +73,8 @@
 
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
 
 import java.net.InetAddress;
 import java.util.ArrayList;
@@ -88,7 +88,7 @@
  *
  * @hide
  */
-public class WifiStateMachine extends HierarchicalStateMachine {
+public class WifiStateMachine extends StateMachine {
 
     private static final String TAG = "WifiStateMachine";
     private static final String NETWORKTYPE = "WIFI";
@@ -358,50 +358,50 @@
     private static final int MAX_RSSI = 256;
 
     /* Default parent state */
-    private HierarchicalState mDefaultState = new DefaultState();
+    private State mDefaultState = new DefaultState();
     /* Temporary initial state */
-    private HierarchicalState mInitialState = new InitialState();
+    private State mInitialState = new InitialState();
     /* Unloading the driver */
-    private HierarchicalState mDriverUnloadingState = new DriverUnloadingState();
+    private State mDriverUnloadingState = new DriverUnloadingState();
     /* Loading the driver */
-    private HierarchicalState mDriverUnloadedState = new DriverUnloadedState();
+    private State mDriverUnloadedState = new DriverUnloadedState();
     /* Driver load/unload failed */
-    private HierarchicalState mDriverFailedState = new DriverFailedState();
+    private State mDriverFailedState = new DriverFailedState();
     /* Driver loading */
-    private HierarchicalState mDriverLoadingState = new DriverLoadingState();
+    private State mDriverLoadingState = new DriverLoadingState();
     /* Driver loaded */
-    private HierarchicalState mDriverLoadedState = new DriverLoadedState();
+    private State mDriverLoadedState = new DriverLoadedState();
     /* Driver loaded, waiting for supplicant to start */
-    private HierarchicalState mSupplicantStartingState = new SupplicantStartingState();
+    private State mSupplicantStartingState = new SupplicantStartingState();
     /* Driver loaded and supplicant ready */
-    private HierarchicalState mSupplicantStartedState = new SupplicantStartedState();
+    private State mSupplicantStartedState = new SupplicantStartedState();
     /* Waiting for supplicant to stop and monitor to exit */
-    private HierarchicalState mSupplicantStoppingState = new SupplicantStoppingState();
+    private State mSupplicantStoppingState = new SupplicantStoppingState();
     /* Driver start issued, waiting for completed event */
-    private HierarchicalState mDriverStartingState = new DriverStartingState();
+    private State mDriverStartingState = new DriverStartingState();
     /* Driver started */
-    private HierarchicalState mDriverStartedState = new DriverStartedState();
+    private State mDriverStartedState = new DriverStartedState();
     /* Driver stopping */
-    private HierarchicalState mDriverStoppingState = new DriverStoppingState();
+    private State mDriverStoppingState = new DriverStoppingState();
     /* Driver stopped */
-    private HierarchicalState mDriverStoppedState = new DriverStoppedState();
+    private State mDriverStoppedState = new DriverStoppedState();
     /* Scan for networks, no connection will be established */
-    private HierarchicalState mScanModeState = new ScanModeState();
+    private State mScanModeState = new ScanModeState();
     /* Connecting to an access point */
-    private HierarchicalState mConnectModeState = new ConnectModeState();
+    private State mConnectModeState = new ConnectModeState();
     /* Fetching IP after network connection (assoc+auth complete) */
-    private HierarchicalState mConnectingState = new ConnectingState();
+    private State mConnectingState = new ConnectingState();
     /* Connected with IP addr */
-    private HierarchicalState mConnectedState = new ConnectedState();
+    private State mConnectedState = new ConnectedState();
     /* disconnect issued, waiting for network disconnect confirmation */
-    private HierarchicalState mDisconnectingState = new DisconnectingState();
+    private State mDisconnectingState = new DisconnectingState();
     /* Network is not connected, supplicant assoc+auth is not complete */
-    private HierarchicalState mDisconnectedState = new DisconnectedState();
+    private State mDisconnectedState = new DisconnectedState();
     /* Waiting for WPS to be completed*/
-    private HierarchicalState mWaitForWpsCompletionState = new WaitForWpsCompletionState();
+    private State mWaitForWpsCompletionState = new WaitForWpsCompletionState();
 
     /* Soft Ap is running */
-    private HierarchicalState mSoftApStartedState = new SoftApStartedState();
+    private State mSoftApStartedState = new SoftApStartedState();
 
 
     /**
@@ -1543,7 +1543,7 @@
      * HSM states
      *******************************************************/
 
-    class DefaultState extends HierarchicalState {
+    class DefaultState extends State {
         @Override
         public boolean processMessage(Message message) {
             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
@@ -1617,7 +1617,7 @@
         }
     }
 
-    class InitialState extends HierarchicalState {
+    class InitialState extends State {
         @Override
         //TODO: could move logging into a common class
         public void enter() {
@@ -1636,7 +1636,7 @@
         }
     }
 
-    class DriverLoadingState extends HierarchicalState {
+    class DriverLoadingState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
@@ -1715,7 +1715,7 @@
         }
     }
 
-    class DriverLoadedState extends HierarchicalState {
+    class DriverLoadedState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
@@ -1768,7 +1768,7 @@
         }
     }
 
-    class DriverUnloadingState extends HierarchicalState {
+    class DriverUnloadingState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
@@ -1849,7 +1849,7 @@
         }
     }
 
-    class DriverUnloadedState extends HierarchicalState {
+    class DriverUnloadedState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
@@ -1870,7 +1870,7 @@
         }
     }
 
-    class DriverFailedState extends HierarchicalState {
+    class DriverFailedState extends State {
         @Override
         public void enter() {
             Log.e(TAG, getName() + "\n");
@@ -1884,7 +1884,7 @@
     }
 
 
-    class SupplicantStartingState extends HierarchicalState {
+    class SupplicantStartingState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
@@ -1956,7 +1956,7 @@
         }
     }
 
-    class SupplicantStartedState extends HierarchicalState {
+    class SupplicantStartedState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
@@ -2084,7 +2084,7 @@
         }
     }
 
-    class SupplicantStoppingState extends HierarchicalState {
+    class SupplicantStoppingState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
@@ -2127,7 +2127,7 @@
         }
     }
 
-    class DriverStartingState extends HierarchicalState {
+    class DriverStartingState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
@@ -2168,7 +2168,7 @@
         }
     }
 
-    class DriverStartedState extends HierarchicalState {
+    class DriverStartedState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
@@ -2272,7 +2272,7 @@
         }
     }
 
-    class DriverStoppingState extends HierarchicalState {
+    class DriverStoppingState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
@@ -2308,7 +2308,7 @@
         }
     }
 
-    class DriverStoppedState extends HierarchicalState {
+    class DriverStoppedState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
@@ -2332,7 +2332,7 @@
         }
     }
 
-    class ScanModeState extends HierarchicalState {
+    class ScanModeState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
@@ -2369,7 +2369,7 @@
         }
     }
 
-    class ConnectModeState extends HierarchicalState {
+    class ConnectModeState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
@@ -2479,7 +2479,7 @@
         }
     }
 
-    class ConnectingState extends HierarchicalState {
+    class ConnectingState extends State {
         boolean mModifiedBluetoothCoexistenceMode;
         int mPowerMode;
         boolean mUseStaticIp;
@@ -2677,7 +2677,7 @@
       }
     }
 
-    class ConnectedState extends HierarchicalState {
+    class ConnectedState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
@@ -2789,7 +2789,7 @@
         }
     }
 
-    class DisconnectingState extends HierarchicalState {
+    class DisconnectingState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
@@ -2819,7 +2819,7 @@
         }
     }
 
-    class DisconnectedState extends HierarchicalState {
+    class DisconnectedState extends State {
         private boolean mAlarmEnabled = false;
         /* This is set from the overlay config file or from a secure setting.
          * A value of 0 disables scanning in the framework.
@@ -2931,7 +2931,7 @@
         }
     }
 
-    class WaitForWpsCompletionState extends HierarchicalState {
+    class WaitForWpsCompletionState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
@@ -2970,7 +2970,7 @@
         }
     }
 
-    class SoftApStartedState extends HierarchicalState {
+    class SoftApStartedState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");
diff --git a/wifi/java/android/net/wifi/WpsStateMachine.java b/wifi/java/android/net/wifi/WpsStateMachine.java
index 32d77a1..120b228 100644
--- a/wifi/java/android/net/wifi/WpsStateMachine.java
+++ b/wifi/java/android/net/wifi/WpsStateMachine.java
@@ -17,8 +17,8 @@
 package android.net.wifi;
 
 import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
 
 import android.content.Context;
 import android.content.Intent;
@@ -46,7 +46,7 @@
  * reloads the configuration and updates the IP and proxy
  * settings, if any.
  */
-class WpsStateMachine extends HierarchicalStateMachine {
+class WpsStateMachine extends StateMachine {
 
     private static final String TAG = "WpsStateMachine";
     private static final boolean DBG = false;
@@ -58,9 +58,9 @@
     private Context mContext;
     AsyncChannel mReplyChannel = new AsyncChannel();
 
-    private HierarchicalState mDefaultState = new DefaultState();
-    private HierarchicalState mInactiveState = new InactiveState();
-    private HierarchicalState mActiveState = new ActiveState();
+    private State mDefaultState = new DefaultState();
+    private State mInactiveState = new InactiveState();
+    private State mActiveState = new ActiveState();
 
     public WpsStateMachine(Context context, WifiStateMachine wsm, Handler target) {
         super(TAG, target.getLooper());
@@ -82,7 +82,7 @@
      * HSM states
      *******************************************************/
 
-    class DefaultState extends HierarchicalState {
+    class DefaultState extends State {
         @Override
          public void enter() {
              if (DBG) Log.d(TAG, getName() + "\n");
@@ -128,7 +128,7 @@
         }
     }
 
-    class ActiveState extends HierarchicalState {
+    class ActiveState extends State {
         @Override
          public void enter() {
              if (DBG) Log.d(TAG, getName() + "\n");
@@ -182,7 +182,7 @@
         }
     }
 
-    class InactiveState extends HierarchicalState {
+    class InactiveState extends State {
         @Override
         public void enter() {
             if (DBG) Log.d(TAG, getName() + "\n");