Merge "Begin adding async allocation creation."
diff --git a/api/current.xml b/api/current.xml
index 715b49a..bac65eb 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -40322,13 +40322,15 @@
 </method>
 </class>
 <class name="ClipData"
- extends="android.content.ClipDescription"
+ extends="java.lang.Object"
  abstract="false"
  static="false"
  final="false"
  deprecated="not deprecated"
  visibility="public"
 >
+<implements name="android.os.Parcelable">
+</implements>
 <constructor name="ClipData"
  type="android.content.ClipData"
  static="false"
@@ -40345,6 +40347,20 @@
 <parameter name="item" type="android.content.ClipData.Item">
 </parameter>
 </constructor>
+<constructor name="ClipData"
+ type="android.content.ClipData"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="description" type="android.content.ClipDescription">
+</parameter>
+<parameter name="icon" type="android.graphics.Bitmap">
+</parameter>
+<parameter name="item" type="android.content.ClipData.Item">
+</parameter>
+</constructor>
 <method name="addItem"
  return="void"
  abstract="false"
@@ -40358,6 +40374,28 @@
 <parameter name="item" type="android.content.ClipData.Item">
 </parameter>
 </method>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDescription"
+ return="android.content.ClipDescription"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getIcon"
  return="android.graphics.Bitmap"
  abstract="false"
@@ -40463,6 +40501,21 @@
 <parameter name="uri" type="android.net.Uri">
 </parameter>
 </method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
 <field name="CREATOR"
  type="android.os.Parcelable.Creator"
  transient="false"
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f08d88d..378a8bd 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -645,11 +645,13 @@
     Activity mParent;
     boolean mCalled;
     boolean mCheckedForLoaderManager;
-    boolean mStarted;
+    boolean mLoadersStarted;
     private boolean mResumed;
     private boolean mStopped;
     boolean mFinished;
     boolean mStartedActivity;
+    /** true if the activity is going through a transient pause */
+    /*package*/ boolean mTemporaryPause = false;
     /** true if the activity is being destroyed in order to recreate it with a new configuration */
     /*package*/ boolean mChangingConfigurations = false;
     /*package*/ int mConfigChangeFlags;
@@ -768,7 +770,7 @@
             return mLoaderManager;
         }
         mCheckedForLoaderManager = true;
-        mLoaderManager = getLoaderManager(-1, mStarted, true);
+        mLoaderManager = getLoaderManager(-1, mLoadersStarted, true);
         return mLoaderManager;
     }
     
@@ -777,9 +779,13 @@
             mAllLoaderManagers = new SparseArray<LoaderManagerImpl>();
         }
         LoaderManagerImpl lm = mAllLoaderManagers.get(index);
-        if (lm == null && create) {
-            lm = new LoaderManagerImpl(started);
-            mAllLoaderManagers.put(index, lm);
+        if (lm == null) {
+            if (create) {
+                lm = new LoaderManagerImpl(this, started);
+                mAllLoaderManagers.put(index, lm);
+            }
+        } else {
+            lm.updateActivity(this);
         }
         return lm;
     }
@@ -979,13 +985,16 @@
      */
     protected void onStart() {
         mCalled = true;
-        mStarted = true;
-        if (mLoaderManager != null) {
-            mLoaderManager.doStart();
-        } else if (!mCheckedForLoaderManager) {
-            mLoaderManager = getLoaderManager(-1, mStarted, false);
+        
+        if (!mLoadersStarted) {
+            mLoadersStarted = true;
+            if (mLoaderManager != null) {
+                mLoaderManager.doStart();
+            } else if (!mCheckedForLoaderManager) {
+                mLoaderManager = getLoaderManager(-1, mLoadersStarted, false);
+            }
+            mCheckedForLoaderManager = true;
         }
-        mCheckedForLoaderManager = true;
     }
 
     /**
@@ -4249,7 +4258,7 @@
     }
     
     final void performStart() {
-        mFragments.mStateSaved = false;
+        mFragments.noteStateNotSaved();
         mCalled = false;
         mFragments.execPendingActions();
         mInstrumentation.callActivityOnStart(this);
@@ -4267,7 +4276,7 @@
     }
     
     final void performRestart() {
-        mFragments.mStateSaved = false;
+        mFragments.noteStateNotSaved();
 
         synchronized (mManagedCursors) {
             final int N = mManagedCursors.size();
@@ -4347,8 +4356,8 @@
     }
     
     final void performStop() {
-        if (mStarted) {
-            mStarted = false;
+        if (mLoadersStarted) {
+            mLoadersStarted = false;
             if (mLoaderManager != null) {
                 if (!mChangingConfigurations) {
                     mLoaderManager.doStop();
@@ -4407,7 +4416,7 @@
         if (Config.LOGV) Log.v(
             TAG, "Dispatching result: who=" + who + ", reqCode=" + requestCode
             + ", resCode=" + resultCode + ", data=" + data);
-        mFragments.mStateSaved = false;
+        mFragments.noteStateNotSaved();
         if (who == null) {
             onActivityResult(requestCode, resultCode, data);
         } else {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f3f7ee7..2abe822 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1757,6 +1757,7 @@
         for (int i=0; i<N; i++) {
             Intent intent = intents.get(i);
             intent.setExtrasClassLoader(r.activity.getClassLoader());
+            r.activity.mFragments.noteStateNotSaved();
             mInstrumentation.callActivityOnNewIntent(r.activity, intent);
         }
     }
@@ -1767,11 +1768,13 @@
         if (r != null) {
             final boolean resumed = !r.paused;
             if (resumed) {
+                r.activity.mTemporaryPause = true;
                 mInstrumentation.callActivityOnPause(r.activity);
             }
             deliverNewIntents(r, intents);
             if (resumed) {
                 mInstrumentation.callActivityOnResume(r.activity);
+                r.activity.mTemporaryPause = false;
             }
         }
     }
@@ -2594,6 +2597,7 @@
                 try {
                     // Now we are idle.
                     r.activity.mCalled = false;
+                    r.activity.mTemporaryPause = true;
                     mInstrumentation.callActivityOnPause(r.activity);
                     if (!r.activity.mCalled) {
                         throw new SuperNotCalledException(
@@ -2614,6 +2618,7 @@
             deliverResults(r, res.results);
             if (resumed) {
                 mInstrumentation.callActivityOnResume(r.activity);
+                r.activity.mTemporaryPause = false;
             }
         }
     }
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 12bf7e5..3ec0912 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -403,7 +403,7 @@
     View mView;
     
     LoaderManagerImpl mLoaderManager;
-    boolean mStarted;
+    boolean mLoadersStarted;
     boolean mCheckedForLoaderManager;
     
     /**
@@ -728,7 +728,7 @@
             return mLoaderManager;
         }
         mCheckedForLoaderManager = true;
-        mLoaderManager = mActivity.getLoaderManager(mIndex, mStarted, true);
+        mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, true);
         return mLoaderManager;
     }
     
@@ -880,13 +880,16 @@
      */
     public void onStart() {
         mCalled = true;
-        mStarted = true;
-        if (!mCheckedForLoaderManager) {
-            mCheckedForLoaderManager = true;
-            mLoaderManager = mActivity.getLoaderManager(mIndex, mStarted, false);
-        }
-        if (mLoaderManager != null) {
-            mLoaderManager.doStart();
+        
+        if (!mLoadersStarted) {
+            mLoadersStarted = true;
+            if (!mCheckedForLoaderManager) {
+                mCheckedForLoaderManager = true;
+                mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, false);
+            }
+            if (mLoaderManager != null) {
+                mLoaderManager.doStart();
+            }
         }
     }
     
@@ -971,7 +974,7 @@
         //        + " mLoaderManager=" + mLoaderManager);
         if (!mCheckedForLoaderManager) {
             mCheckedForLoaderManager = true;
-            mLoaderManager = mActivity.getLoaderManager(mIndex, mStarted, false);
+            mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, false);
         }
         if (mLoaderManager != null) {
             mLoaderManager.doDestroy();
@@ -1182,7 +1185,7 @@
         }
         if (mLoaderManager != null) {
             writer.print(prefix); writer.print("mLoaderManager="); writer.print(mLoaderManager);
-                    writer.print(" mStarted="); writer.print(mStarted);
+                    writer.print(" mLoadersStarted="); writer.print(mLoadersStarted);
                     writer.print(" mCheckedForLoaderManager=");
                     writer.println(mCheckedForLoaderManager);
         }
@@ -1190,11 +1193,12 @@
 
     void performStop() {
         onStop();
-        if (mStarted) {
-            mStarted = false;
+        
+        if (mLoadersStarted) {
+            mLoadersStarted = false;
             if (!mCheckedForLoaderManager) {
                 mCheckedForLoaderManager = true;
-                mLoaderManager = mActivity.getLoaderManager(mIndex, mStarted, false);
+                mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, false);
             }
             if (mLoaderManager != null) {
                 if (mActivity == null || !mActivity.mChangingConfigurations) {
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 37e7253..d9a6171 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -86,6 +86,15 @@
     /**
      * Start a series of edit operations on the Fragments associated with
      * this FragmentManager.
+     * 
+     * <p>Note: A fragment transaction can only be created/committed prior
+     * to an activity saving its state.  If you try to commit a transaction
+     * after {@link Activity#onSaveInstanceState Activity.onSaveInstanceState()}
+     * (and prior to a following {@link Activity#onStart Activity.onStart}
+     * or {@link Activity#onResume Activity.onResume()}, you will get an error.
+     * This is because the framework takes care of saving your current fragments
+     * in the state, and if changes are made after the state is saved then they
+     * will be lost.</p>
      */
     public FragmentTransaction openTransaction();
 
@@ -271,6 +280,7 @@
     
     boolean mNeedMenuInvalidate;
     boolean mStateSaved;
+    String mNoTransactionsBecause;
     
     // Temporary vars for state save and restore.
     Bundle mStateBundle = null;
@@ -843,6 +853,10 @@
             throw new IllegalStateException(
                     "Can not perform this action after onSaveInstanceState");
         }
+        if (mNoTransactionsBecause != null) {
+            throw new IllegalStateException(
+                    "Can not perform this action inside of " + mNoTransactionsBecause);
+        }
         synchronized (this) {
             if (mPendingActions == null) {
                 mPendingActions = new ArrayList<Runnable>();
@@ -1271,6 +1285,10 @@
         mActivity = activity;
     }
     
+    public void noteStateNotSaved() {
+        mStateSaved = false;
+    }
+    
     public void dispatchCreate() {
         mStateSaved = false;
         moveToState(Fragment.CREATED, false);
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index 28abcaa..4d4ea9a 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -40,7 +40,12 @@
         public Loader<D> onCreateLoader(int id, Bundle args);
 
         /**
-         * Called when a previously created loader has finished its load.
+         * Called when a previously created loader has finished its load.  Note
+         * that normally an application is <em>not</em> allowed to commit fragment
+         * transactions while in this call, since it can happen after an
+         * activity's state is saved.  See {@link FragmentManager#openTransaction()
+         * FragmentManager.openTransaction()} for further discussion on this.
+         * 
          * @param loader The Loader that has finished.
          * @param data The data generated by the Loader.
          */
@@ -102,6 +107,7 @@
     // previously run loader until the new loader's data is available.
     final SparseArray<LoaderInfo> mInactiveLoaders = new SparseArray<LoaderInfo>();
 
+    Activity mActivity;
     boolean mStarted;
     boolean mRetaining;
     boolean mRetainingStarted;
@@ -172,12 +178,12 @@
                         stop();
                     }
                 }
-                if (mStarted && mData != null && mCallbacks != null) {
+                if (mStarted && mData != null) {
                     // This loader was retained, and now at the point of
                     // finishing the retain we find we remain started, have
                     // our data, and the owner has a new callback...  so
                     // let's deliver the data now.
-                    mCallbacks.onLoadFinished(mLoader, mData);
+                    callOnLoadFinished(mLoader, mData);
                 }
             }
         }
@@ -219,9 +225,7 @@
             // Notify of the new data so the app can switch out the old data before
             // we try to destroy it.
             mData = data;
-            if (mCallbacks != null) {
-                mCallbacks.onLoadFinished(loader, data);
-            }
+            callOnLoadFinished(loader, data);
 
             if (DEBUG) Log.v(TAG, "onLoadFinished returned: " + this);
 
@@ -236,6 +240,23 @@
             }
         }
 
+        void callOnLoadFinished(Loader<Object> loader, Object data) {
+            if (mCallbacks != null) {
+                String lastBecause = null;
+                if (mActivity != null) {
+                    lastBecause = mActivity.mFragments.mNoTransactionsBecause;
+                    mActivity.mFragments.mNoTransactionsBecause = "onLoadFinished";
+                }
+                try {
+                    mCallbacks.onLoadFinished(loader, data);
+                } finally {
+                    if (mActivity != null) {
+                        mActivity.mFragments.mNoTransactionsBecause = lastBecause;
+                    }
+                }
+            }
+        }
+        
         @Override
         public String toString() {
             StringBuilder sb = new StringBuilder(64);
@@ -252,10 +273,15 @@
         }
     }
     
-    LoaderManagerImpl(boolean started) {
+    LoaderManagerImpl(Activity activity, boolean started) {
+        mActivity = activity;
         mStarted = started;
     }
     
+    void updateActivity(Activity activity) {
+        mActivity = activity;
+    }
+    
     private LoaderInfo createLoader(int id, Bundle args,
             LoaderManager.LoaderCallbacks<Object> callback) {
         LoaderInfo info = new LoaderInfo(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
@@ -286,7 +312,7 @@
         
         if (info.mData != null && mStarted) {
             // If the loader has already generated its data, report it now.
-            info.mCallbacks.onLoadFinished(info.mLoader, info.mData);
+            info.callOnLoadFinished(info.mLoader, info.mData);
         }
         
         return (Loader<D>)info.mLoader;
@@ -348,7 +374,13 @@
  
     void doStart() {
         if (DEBUG) Log.v(TAG, "Starting: " + this);
-
+        if (mStarted) {
+            RuntimeException e = new RuntimeException("here");
+            e.fillInStackTrace();
+            Log.w(TAG, "Called doStart when already started: " + this, e);
+            return;
+        }
+        
         // Call out to sub classes so they can start their loaders
         // Let the existing loaders know that we want to be notified when a load is complete
         for (int i = mLoaders.size()-1; i >= 0; i--) {
@@ -359,6 +391,12 @@
     
     void doStop() {
         if (DEBUG) Log.v(TAG, "Stopping: " + this);
+        if (!mStarted) {
+            RuntimeException e = new RuntimeException("here");
+            e.fillInStackTrace();
+            Log.w(TAG, "Called doStop when not started: " + this, e);
+            return;
+        }
 
         for (int i = mLoaders.size()-1; i >= 0; i--) {
             mLoaders.valueAt(i).stop();
@@ -368,6 +406,12 @@
     
     void doRetain() {
         if (DEBUG) Log.v(TAG, "Retaining: " + this);
+        if (!mStarted) {
+            RuntimeException e = new RuntimeException("here");
+            e.fillInStackTrace();
+            Log.w(TAG, "Called doRetain when not started: " + this, e);
+            return;
+        }
 
         mRetaining = true;
         mStarted = false;
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index f0252b7..1eb269d 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -92,4 +92,6 @@
     List<BluetoothDevice> getConnectedPanDevices();
     boolean connectPanDevice(in BluetoothDevice device);
     boolean disconnectPanDevice(in BluetoothDevice device);
+
+    void sendConnectionStateChange(in BluetoothDevice device, int state, int prevState);
 }
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index a19b132..6f4d098 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -37,8 +37,9 @@
  * each of which can hold one or more representations of an item of data.
  * For display to the user, it also has a label and iconic representation.</p>
  *
- * <p>A ClipData is a sub-class of {@link ClipDescription}, which describes
- * important meta-data about the clip.  In particular, its {@link #getMimeType(int)}
+ * <p>A ClipData contains a {@link ClipDescription}, which describes
+ * important meta-data about the clip.  In particular, its
+ * {@link ClipDescription#getMimeType(int) getDescription().getMimeType(int)}
  * must return correct MIME type(s) describing the data in the clip.  For help
  * in correctly constructing a clip with the correct MIME type, use
  * {@link #newPlainText(CharSequence, Bitmap, CharSequence)},
@@ -62,8 +63,8 @@
  * <p>If all you want is the textual representation of the clipped data, you
  * can use the convenience method {@link Item#coerceToText Item.coerceToText}.
  * In this case there is generally no need to worry about the MIME types
- * reported by {@link #getMimeType(int)}, since any clip item an always be
- * converted to a string.
+ * reported by {@link ClipDescription#getMimeType(int) getDescription().getMimeType(int)},
+ * since any clip item an always be converted to a string.
  *
  * <p>More complicated exchanges will be done through URIs, in particular
  * "content:" URIs.  A content URI allows the recipient of a ClippedData item
@@ -133,11 +134,16 @@
  * into an editor), then {@link Item#coerceToText(Context)} will ask the content
  * provider for the clip URI as text and successfully paste the entire note.
  */
-public class ClipData extends ClipDescription {
-    static final String[] MIMETYPES_TEXT_PLAIN = new String[] { MIMETYPE_TEXT_PLAIN };
-    static final String[] MIMETYPES_TEXT_URILIST = new String[] { MIMETYPE_TEXT_URILIST };
-    static final String[] MIMETYPES_TEXT_INTENT = new String[] { MIMETYPE_TEXT_INTENT };
+public class ClipData implements Parcelable {
+    static final String[] MIMETYPES_TEXT_PLAIN = new String[] {
+        ClipDescription.MIMETYPE_TEXT_PLAIN };
+    static final String[] MIMETYPES_TEXT_URILIST = new String[] {
+        ClipDescription.MIMETYPE_TEXT_URILIST };
+    static final String[] MIMETYPES_TEXT_INTENT = new String[] {
+        ClipDescription.MIMETYPE_TEXT_INTENT };
 
+    final ClipDescription mClipDescription;
+    
     final Bitmap mIcon;
 
     final ArrayList<Item> mItems = new ArrayList<Item>();
@@ -320,7 +326,7 @@
      * @param item The contents of the first item in the clip.
      */
     public ClipData(CharSequence label, String[] mimeTypes, Bitmap icon, Item item) {
-        super(label, mimeTypes);
+        mClipDescription = new ClipDescription(label, mimeTypes);
         if (item == null) {
             throw new NullPointerException("item is null");
         }
@@ -329,7 +335,25 @@
     }
 
     /**
-     * Create a new ClipData holding data of the type {@link #MIMETYPE_TEXT_PLAIN}.
+     * Create a new clip.
+     *
+     * @param description The ClipDescription describing the clip contents.
+     * @param icon Bitmap providing the user with an iconing representation of
+     * the clip.
+     * @param item The contents of the first item in the clip.
+     */
+    public ClipData(ClipDescription description, Bitmap icon, Item item) {
+        mClipDescription = description;
+        if (item == null) {
+            throw new NullPointerException("item is null");
+        }
+        mIcon = icon;
+        mItems.add(item);
+    }
+
+    /**
+     * Create a new ClipData holding data of the type
+     * {@link ClipDescription#MIMETYPE_TEXT_PLAIN}.
      *
      * @param label User-visible label for the clip data.
      * @param icon Iconic representation of the clip data.
@@ -342,7 +366,8 @@
     }
 
     /**
-     * Create a new ClipData holding an Intent with MIME type {@link #MIMETYPE_TEXT_INTENT}.
+     * Create a new ClipData holding an Intent with MIME type
+     * {@link ClipDescription#MIMETYPE_TEXT_INTENT}.
      *
      * @param label User-visible label for the clip data.
      * @param icon Iconic representation of the clip data.
@@ -358,7 +383,7 @@
      * Create a new ClipData holding a URI.  If the URI is a content: URI,
      * this will query the content provider for the MIME type of its data and
      * use that as the MIME type.  Otherwise, it will use the MIME type
-     * {@link #MIMETYPE_TEXT_URILIST}.
+     * {@link ClipDescription#MIMETYPE_TEXT_URILIST}.
      *
      * @param resolver ContentResolver used to get information about the URI.
      * @param label User-visible label for the clip data.
@@ -375,7 +400,7 @@
             mimeTypes = resolver.getStreamTypes(uri, "*/*");
             if (mimeTypes == null) {
                 if (realType != null) {
-                    mimeTypes = new String[] { realType, MIMETYPE_TEXT_URILIST };
+                    mimeTypes = new String[] { realType, ClipDescription.MIMETYPE_TEXT_URILIST };
                 }
             } else {
                 String[] tmp = new String[mimeTypes.length + (realType != null ? 2 : 1)];
@@ -385,7 +410,7 @@
                     i++;
                 }
                 System.arraycopy(mimeTypes, 0, tmp, i, mimeTypes.length);
-                tmp[i + mimeTypes.length] = MIMETYPE_TEXT_URILIST;
+                tmp[i + mimeTypes.length] = ClipDescription.MIMETYPE_TEXT_URILIST;
                 mimeTypes = tmp;
             }
         }
@@ -396,7 +421,8 @@
     }
 
     /**
-     * Create a new ClipData holding an URI with MIME type {@link #MIMETYPE_TEXT_URILIST}.
+     * Create a new ClipData holding an URI with MIME type
+     * {@link ClipDescription#MIMETYPE_TEXT_URILIST}.
      * Unlike {@link #newUri(ContentResolver, CharSequence, Bitmap, Uri)}, nothing
      * is inferred about the URI -- if it is a content: URI holding a bitmap,
      * the reported type will still be uri-list.  Use this with care!
@@ -411,6 +437,14 @@
         return new ClipData(label, MIMETYPES_TEXT_URILIST, icon, item);
     }
 
+    /**
+     * Return the {@link ClipDescription} associated with this data, describing
+     * what it contains.
+     */
+    public ClipDescription getDescription() {
+        return mClipDescription;
+    }
+    
     public void addItem(Item item) {
         if (item == null) {
             throw new NullPointerException("item is null");
@@ -437,7 +471,7 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        super.writeToParcel(dest, flags);
+        mClipDescription.writeToParcel(dest, flags);
         if (mIcon != null) {
             dest.writeInt(1);
             mIcon.writeToParcel(dest, flags);
@@ -465,7 +499,7 @@
     }
 
     ClipData(Parcel in) {
-        super(in);
+        mClipDescription = new ClipDescription(in);
         if (in.readInt() != 0) {
             mIcon = Bitmap.CREATOR.createFromParcel(in);
         } else {
diff --git a/core/java/android/nfc/ErrorCodes.java b/core/java/android/nfc/ErrorCodes.java
index 5b76d84..69329df 100644
--- a/core/java/android/nfc/ErrorCodes.java
+++ b/core/java/android/nfc/ErrorCodes.java
@@ -33,6 +33,34 @@
         }
     }
 
+    public static String asString(int code) {
+        switch (code) {
+            case SUCCESS: return "SUCCESS";
+            case ERROR_IO: return "IO";
+            case ERROR_CANCELLED: return "CANCELLED";
+            case ERROR_TIMEOUT: return "TIMEOUT";
+            case ERROR_BUSY: return "BUSY";
+            case ERROR_CONNECT: return "CONNECT/DISCONNECT";
+//            case ERROR_DISCONNECT: return "DISCONNECT";
+            case ERROR_READ: return "READ";
+            case ERROR_WRITE: return "WRITE";
+            case ERROR_INVALID_PARAM: return "INVALID_PARAM";
+            case ERROR_INSUFFICIENT_RESOURCES: return "INSUFFICIENT_RESOURCES";
+            case ERROR_SOCKET_CREATION: return "SOCKET_CREATION";
+            case ERROR_SOCKET_NOT_CONNECTED: return "SOCKET_NOT_CONNECTED";
+            case ERROR_BUFFER_TO_SMALL: return "BUFFER_TO_SMALL";
+            case ERROR_SAP_USED: return "SAP_USED";
+            case ERROR_SERVICE_NAME_USED: return "SERVICE_NAME_USED";
+            case ERROR_SOCKET_OPTIONS: return "SOCKET_OPTIONS";
+            case ERROR_NFC_ON: return "NFC_ON";
+            case ERROR_NOT_INITIALIZED: return "NOT_INITIALIZED";
+            case ERROR_SE_ALREADY_SELECTED: return "SE_ALREADY_SELECTED";
+            case ERROR_SE_CONNECTED: return "SE_CONNECTED";
+            case ERROR_NO_SE_CONNECTED: return "NO_SE_CONNECTED";
+            default: return "UNKNOWN ERROR";
+        }
+    }
+
     public static final int SUCCESS = 0;
 
     public static final int ERROR_IO = -1;
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 61e2305..b5e85a0 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -483,6 +483,8 @@
 
         if (name.equals(PROPERTY_STATE)) {
             int state = convertBluezSinkStringtoState(propValues[1]);
+            log("A2DP: onSinkPropertyChanged newState is: " + state + "mPlayingA2dpDevice: " + mPlayingA2dpDevice);
+
             if (mAudioDevices.get(device) == null) {
                 // This is for an incoming connection for a device not known to us.
                 // We have authorized it and bluez state has changed.
@@ -496,6 +498,7 @@
                     handleSinkPlayingStateChange(device, BluetoothA2dp.STATE_NOT_PLAYING,
                         BluetoothA2dp.STATE_PLAYING);
                 } else {
+                   mPlayingA2dpDevice = null;
                    int prevState = mAudioDevices.get(device);
                    handleSinkStateChange(device, prevState, state);
                 }
@@ -510,7 +513,6 @@
                 mSinkCount--;
             } else if (state == BluetoothA2dp.STATE_CONNECTED) {
                 mSinkCount ++;
-                mPlayingA2dpDevice = null;
             }
             mAudioDevices.put(device, state);
 
@@ -534,6 +536,8 @@
             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
 
             if (DBG) log("A2DP state : device: " + device + " State:" + prevState + "->" + state);
+
+            mBluetoothService.sendConnectionStateChange(device, state, prevState);
         }
     }
 
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index ec6ca7d..4f56281 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -253,6 +253,7 @@
             // we filled up our cache.
             mBluetoothService.getAllProperties();
         }
+        log("Property Changed: " + propValues[0] + " : " + propValues[1]);
         String name = propValues[0];
         if (name.equals("Name")) {
             mBluetoothService.setProperty(name, propValues[1]);
@@ -321,10 +322,9 @@
             Log.e(TAG, "onDevicePropertyChanged: Address of the remote device in null");
             return;
         }
-        if (DBG) {
-            log("Device property changed: " + address + " property: "
-                    + name + " value: " + propValues[1]);
-        }
+        log("Device property changed: " + address + " property: "
+            + name + " value: " + propValues[1]);
+
         BluetoothDevice device = mAdapter.getRemoteDevice(address);
         if (name.equals("Name")) {
             mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 660f9ab..65047c0 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -162,6 +162,7 @@
     private final HashMap<BluetoothDevice, Pair<Integer, String>> mPanDevices;
     private final HashMap<String, Pair<byte[], byte[]>> mDeviceOobData;
 
+    private int mProfilesConnected = 0, mProfilesConnecting = 0, mProfilesDisconnecting = 0;
 
     private static String mDockAddress;
     private String mDockPin;
@@ -411,6 +412,10 @@
         mAdapterProperties.clear();
         mServiceRecordToPid.clear();
 
+        mProfilesConnected = 0;
+        mProfilesConnecting = 0;
+        mProfilesDisconnecting = 0;
+
         if (saveSetting) {
             persistBluetoothOnSetting(false);
         }
@@ -1563,6 +1568,7 @@
         mContext.sendBroadcast(intent, BLUETOOTH_PERM);
 
         if (DBG) log("Pan Device state : device: " + device + " State:" + prevState + "->" + state);
+        sendConnectionStateChange(device, state, prevState);
     }
 
     /*package*/ synchronized void handlePanDeviceStateChange(BluetoothDevice device,
@@ -1790,7 +1796,7 @@
         mContext.sendBroadcast(intent, BLUETOOTH_PERM);
 
         if (DBG) log("InputDevice state : device: " + device + " State:" + prevState + "->" + state);
-
+        sendConnectionStateChange(device, state, prevState);
     }
 
     /*package*/ void handleInputDevicePropertyChange(String address, boolean connected) {
@@ -2731,6 +2737,75 @@
         }
     }
 
+    public synchronized void sendConnectionStateChange(BluetoothDevice device, int state,
+                                                        int prevState) {
+        if (updateCountersAndCheckForConnectionStateChange(device, state, prevState)) {
+            state = getAdapterConnectionState(state);
+            prevState = getAdapterConnectionState(prevState);
+            Intent intent = new Intent(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
+            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
+            intent.putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, state);
+            intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE, prevState);
+            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+            log("CONNECTION_STATE_CHANGE: " + device + ": " + prevState + "-> " + state);
+        }
+    }
+
+    private int getAdapterConnectionState(int state) {
+        switch (state) {
+            case BluetoothProfile.STATE_CONNECTING:
+                return BluetoothAdapter.STATE_CONNECTING;
+            case BluetoothProfile.STATE_CONNECTED:
+              return BluetoothAdapter.STATE_CONNECTED;
+            case BluetoothProfile.STATE_DISCONNECTING:
+              return BluetoothAdapter.STATE_DISCONNECTING;
+            case BluetoothProfile.STATE_DISCONNECTED:
+              return BluetoothAdapter.STATE_DISCONNECTED;
+            default:
+              Log.e(TAG, "Error in getAdapterConnectionState");
+              return -1;
+        }
+    }
+
+    private boolean updateCountersAndCheckForConnectionStateChange(BluetoothDevice device,
+                                                                   int state,
+                                                                   int prevState) {
+        switch (state) {
+            case BluetoothProfile.STATE_CONNECTING:
+                mProfilesConnecting++;
+                if (prevState == BluetoothAdapter.STATE_DISCONNECTING) mProfilesDisconnecting--;
+                if (mProfilesConnected > 0 || mProfilesConnecting > 1) return false;
+
+                break;
+            case BluetoothProfile.STATE_CONNECTED:
+                if (prevState == BluetoothAdapter.STATE_CONNECTING) mProfilesConnecting--;
+                if (prevState == BluetoothAdapter.STATE_DISCONNECTING) mProfilesDisconnecting--;
+
+                mProfilesConnected++;
+
+                if (mProfilesConnected > 1) return false;
+                break;
+            case BluetoothProfile.STATE_DISCONNECTING:
+                mProfilesDisconnecting++;
+                mProfilesConnected--;
+
+                if (mProfilesConnected > 0 || mProfilesDisconnecting > 1) return false;
+
+                break;
+            case BluetoothProfile.STATE_DISCONNECTED:
+                if (prevState == BluetoothAdapter.STATE_CONNECTING) mProfilesConnecting--;
+                if (prevState == BluetoothAdapter.STATE_DISCONNECTING) mProfilesDisconnecting--;
+
+                if (prevState == BluetoothAdapter.STATE_CONNECTED) {
+                    mProfilesConnected--;
+                }
+
+                if (mProfilesConnected  > 0 || mProfilesConnecting > 0) return false;
+                break;
+        }
+        return true;
+    }
+
     private static void log(String msg) {
         Log.d(TAG, msg);
     }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0456463..87e03cf 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7579,6 +7579,11 @@
      * the auto scaling to true. Doing so, however, will generate a bitmap of a different
      * size than the view. This implies that your application must be able to handle this
      * size.</p>
+     * 
+     * <p>You should avoid calling this method when hardware acceleration is enabled. If
+     * you do not need the drawing cache bitmap, calling this method will increase memory
+     * usage and cause the view to be rendered in software once, thus negatively impacting 
+     * performance.</p>
      *
      * @see #getDrawingCache()
      * @see #destroyDrawingCache()
@@ -7699,7 +7704,9 @@
             canvas.translate(-mScrollX, -mScrollY);
 
             mPrivateFlags |= DRAWN;
-            mPrivateFlags |= DRAWING_CACHE_VALID;
+            if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated) {
+                mPrivateFlags |= DRAWING_CACHE_VALID;
+            }
 
             // Fast path for layouts with no backgrounds
             if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 7b2703b..b881bdd 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1867,12 +1867,15 @@
         if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
             final int count = mChildrenCount;
             final View[] children = mChildren;
+            final boolean buildCache = !isHardwareAccelerated();
 
             for (int i = 0; i < count; i++) {
                 final View child = children[i];
                 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
                     child.setDrawingCacheEnabled(true);
-                    child.buildDrawingCache(true);
+                    if (buildCache) {
+                        child.buildDrawingCache(true);
+                    }
                 }
             }
 
@@ -1933,6 +1936,7 @@
         if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
             final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
 
+            final boolean buildCache = !isHardwareAccelerated();
             for (int i = 0; i < count; i++) {
                 final View child = children[i];
                 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
@@ -1941,7 +1945,9 @@
                     bindLayoutAnimation(child);
                     if (cache) {
                         child.setDrawingCacheEnabled(true);
-                        child.buildDrawingCache(true);
+                        if (buildCache) {                        
+                            child.buildDrawingCache(true);
+                        }
                     }
                 }
             }
@@ -2205,8 +2211,7 @@
             if (!canvas.isHardwareAccelerated()) {
                 cache = child.getDrawingCache(true);
             } else {
-                // TODO: bring back
-                // displayList = child.getDisplayList();
+                displayList = child.getDisplayList();
             }
         }
 
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 2e368b8..06261bb 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -561,6 +561,11 @@
             scheduleTraversals();
         }
     }
+    
+    void invalidate() {
+        mDirty.set(0, 0, mWidth, mHeight);
+        scheduleTraversals();
+    }
 
     public ViewParent getParent() {
         return null;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index c095199..908a6ab 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2471,7 +2471,7 @@
 
         int viewWidth = getViewWidth();
         int newWidth = Math.round(viewWidth * mZoomManager.getInvScale());
-        int newHeight = Math.round(getViewHeight() * mZoomManager.getInvScale());
+        int newHeight = Math.round((getViewHeightWithTitle() - getTitleHeight()) * mZoomManager.getInvScale());
         /*
          * Because the native side may have already done a layout before the
          * View system was able to measure us, we have to send a height of 0 to
diff --git a/core/java/android/widget/SlidingDrawer.java b/core/java/android/widget/SlidingDrawer.java
index 11d72de..bdeb5c2 100644
--- a/core/java/android/widget/SlidingDrawer.java
+++ b/core/java/android/widget/SlidingDrawer.java
@@ -652,7 +652,7 @@
         // Try only once... we should really loop but it's not a big deal
         // if the draw was cancelled, it will only be temporary anyway
         content.getViewTreeObserver().dispatchOnPreDraw();
-        content.buildDrawingCache();
+        if (!content.isHardwareAccelerated()) content.buildDrawingCache();
 
         content.setVisibility(View.GONE);        
     }
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 0e92eeb..e6d5984 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -114,6 +114,7 @@
     private int mTouchSlop;
     private int mMaximumVelocity;
     private VelocityTracker mVelocityTracker;
+    private boolean mTransitionIsSetup = false;
 
     private static HolographicHelper sHolographicHelper;
     private ImageView mHighlight;
@@ -225,6 +226,48 @@
         }
     }
 
+    private void setupStackSlider(View v, int mode) {
+        mStackSlider.setMode(mode);
+        if (v != null) {
+            mHighlight.setImageBitmap(sHolographicHelper.createOutline(v));
+            mHighlight.setRotation(v.getRotation());
+            mHighlight.setTranslationY(v.getTranslationY());
+            mHighlight.bringToFront();
+            v.bringToFront();
+            mStackSlider.setView(v);
+
+            v.setVisibility(VISIBLE);
+        }
+    }
+
+    @Override
+    @android.view.RemotableViewMethod
+    public void showNext() {
+        if (!mTransitionIsSetup) {
+            View v = getViewAtRelativeIndex(1);
+            if (v != null) {
+                setupStackSlider(v, StackSlider.NORMAL_MODE);
+                mStackSlider.setYProgress(0);
+                mStackSlider.setXProgress(0);
+            }
+        }
+        super.showNext();
+    }
+
+    @Override
+    @android.view.RemotableViewMethod
+    public void showPrevious() {
+        if (!mTransitionIsSetup) {
+            View v = getViewAtRelativeIndex(0);
+            if (v != null) {
+                setupStackSlider(v, StackSlider.NORMAL_MODE);
+                mStackSlider.setYProgress(1);
+                mStackSlider.setXProgress(0);
+            }
+        }
+        super.showPrevious();
+    }
+
     private void transformViewAtIndex(int index, View view) {
         float maxPerpectiveShift = mMeasuredHeight * PERSPECTIVE_SHIFT_FACTOR;
 
@@ -256,11 +299,12 @@
         super.showOnly(childIndex, animate, onLayout);
 
         // Here we need to make sure that the z-order of the children is correct
-	for (int i = mCurrentWindowEnd; i >= mCurrentWindowStart; i--) {
+        for (int i = mCurrentWindowEnd; i >= mCurrentWindowStart; i--) {
             int index = modulo(i, getWindowSize());
             View v = mViewsMap.get(index).view;
             if (v != null) v.bringToFront();
         }
+        mTransitionIsSetup = false;
     }
 
     private void updateChildTransforms() {
@@ -364,29 +408,24 @@
                 activeIndex = (swipeGestureType == GESTURE_SLIDE_DOWN) ? 1 : 0;
             }
 
+            int stackMode;
             if (mLoopViews) {
-                mStackSlider.setMode(StackSlider.NORMAL_MODE);
+                stackMode = StackSlider.NORMAL_MODE;
             } else if (mCurrentWindowStartUnbounded + activeIndex == -1) {
                 activeIndex++;
-                mStackSlider.setMode(StackSlider.BEGINNING_OF_STACK_MODE);
+                stackMode = StackSlider.BEGINNING_OF_STACK_MODE;
             } else if (mCurrentWindowStartUnbounded + activeIndex == mAdapter.getCount() - 1) {
-                mStackSlider.setMode(StackSlider.END_OF_STACK_MODE);
+                stackMode = StackSlider.END_OF_STACK_MODE;
             } else {
-                mStackSlider.setMode(StackSlider.NORMAL_MODE);
+                stackMode = StackSlider.NORMAL_MODE;
             }
 
+            mTransitionIsSetup = stackMode == StackSlider.NORMAL_MODE;
+
             View v = getViewAtRelativeIndex(activeIndex);
             if (v == null) return;
 
-            mHighlight.setImageBitmap(sHolographicHelper.createOutline(v));
-            mHighlight.setRotation(v.getRotation());
-            mHighlight.setTranslationY(v.getTranslationY());
-            mHighlight.bringToFront();
-            v.bringToFront();
-            mStackSlider.setView(v);
-
-            if (swipeGestureType == GESTURE_SLIDE_DOWN)
-                v.setVisibility(VISIBLE);
+            setupStackSlider(v, stackMode);
 
             // We only register this gesture if we've made it this far without a problem
             mSwipeGestureType = swipeGestureType;
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index ff31dec..2949208 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -21,6 +21,7 @@
 import android.app.LocalActivityManager;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.util.AttributeSet;
@@ -63,6 +64,8 @@
     private OnTabChangeListener mOnTabChangeListener;
     private OnKeyListener mTabKeyListener;
 
+    private int mTabLayoutId;
+
     public TabHost(Context context) {
         super(context);
         initTabHost();
@@ -70,6 +73,18 @@
 
     public TabHost(Context context, AttributeSet attrs) {
         super(context, attrs);
+
+        TypedArray a = context.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.TabWidget,
+                com.android.internal.R.attr.tabWidgetStyle, 0);
+
+        mTabLayoutId = a.getResourceId(R.styleable.TabWidget_tabLayout, 0);
+        if (mTabLayoutId == 0) {
+            throw new IllegalArgumentException("Invalid TabWidget tabLayout id");
+        }
+
+        a.recycle();
+
         initTabHost();
     }
 
@@ -214,6 +229,7 @@
         if (tabSpec.mIndicatorStrategy instanceof ViewIndicatorStrategy) {
             mTabWidget.setStripEnabled(false);
         }
+
         mTabWidget.addView(tabIndicator);
         mTabSpecs.add(tabSpec);
 
@@ -513,7 +529,7 @@
             final Context context = getContext();
             LayoutInflater inflater =
                     (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-            View tabIndicator = inflater.inflate(R.layout.tab_indicator,
+            View tabIndicator = inflater.inflate(mTabLayoutId,
                     mTabWidget, // tab widget is the parent
                     false); // no inflate params
 
@@ -525,7 +541,7 @@
                 tabIndicator.setBackgroundResource(R.drawable.tab_indicator_v4);
                 tv.setTextColor(context.getResources().getColorStateList(R.color.tab_indicator_text_v4));
             }
-            
+
             return tabIndicator;
         }
     }
@@ -547,7 +563,7 @@
             final Context context = getContext();
             LayoutInflater inflater =
                     (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-            View tabIndicator = inflater.inflate(R.layout.tab_indicator,
+            View tabIndicator = inflater.inflate(mTabLayoutId,
                     mTabWidget, // tab widget is the parent
                     false); // no inflate params
 
@@ -555,14 +571,17 @@
             tv.setText(mLabel);
 
             final ImageView iconView = (ImageView) tabIndicator.findViewById(R.id.icon);
-            iconView.setImageDrawable(mIcon);
+            if (mIcon != null) {
+                iconView.setImageDrawable(mIcon);
+                iconView.setVisibility(VISIBLE);
+            }
 
             if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
                 // Donut apps get old color scheme
                 tabIndicator.setBackgroundResource(R.drawable.tab_indicator_v4);
                 tv.setTextColor(context.getResources().getColorStateList(R.color.tab_indicator_text_v4));
             }
-            
+
             return tabIndicator;
         }
     }
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 0469e7b..36adacd 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -120,7 +120,9 @@
 
         final Context context = mContext;
         final Resources resources = context.getResources();
-        
+
+        // Tests the target Sdk version, as set in the Manifest. Could not be set using styles.xml
+        // in a values-v? directory which targets the current platform Sdk version instead.
         if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
             // Donut apps get old color scheme
             if (mLeftStrip == null) {
@@ -131,16 +133,6 @@
                 mRightStrip = resources.getDrawable(
                         com.android.internal.R.drawable.tab_bottom_right_v4);
             }
-        } else {
-            // Use modern color scheme for Eclair and beyond
-            if (mLeftStrip == null) {
-                mLeftStrip = resources.getDrawable(
-                        com.android.internal.R.drawable.tab_bottom_left);
-            }
-            if (mRightStrip == null) {
-                mRightStrip = resources.getDrawable(
-                        com.android.internal.R.drawable.tab_bottom_right);
-            }
         }
 
         // Deal with focus, as we don't want the focus to go by default
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 09563fc..6897537 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -7142,6 +7142,7 @@
                     case Gravity.RIGHT:
                         return 0.0f;
                     case Gravity.CENTER_HORIZONTAL:
+                    case Gravity.FILL_HORIZONTAL:
                         return (mLayout.getLineWidth(0) - ((mRight - mLeft) -
                                 getCompoundPaddingLeft() - getCompoundPaddingRight())) /
                                 getHorizontalFadingEdgeLength();
diff --git a/core/java/com/android/internal/nfc/LlcpServiceSocket.java b/core/java/com/android/internal/nfc/LlcpServiceSocket.java
index 4607527..318982b 100644
--- a/core/java/com/android/internal/nfc/LlcpServiceSocket.java
+++ b/core/java/com/android/internal/nfc/LlcpServiceSocket.java
@@ -78,8 +78,9 @@
 	 * @param handle
 	 *            The handle returned by the NFC service and used to identify
 	 *            the socket in subsequent calls.
+	 * @hide
 	 */
-	LlcpServiceSocket(ILlcpServiceSocket service, ILlcpSocket socketService, int handle) {
+	public LlcpServiceSocket(ILlcpServiceSocket service, ILlcpSocket socketService, int handle) {
 		this.mService = service;
 		this.mHandle = handle;
 		this.mLlcpSocketService = socketService;
diff --git a/core/java/com/android/internal/nfc/LlcpSocket.java b/core/java/com/android/internal/nfc/LlcpSocket.java
index ae74002..b1b1320 100644
--- a/core/java/com/android/internal/nfc/LlcpSocket.java
+++ b/core/java/com/android/internal/nfc/LlcpSocket.java
@@ -78,8 +78,9 @@
 	 * @param handle
 	 *            The handle returned by the NFC service and used to identify
 	 *            the socket in subsequent calls.
+	 * @hide
 	 */
-	LlcpSocket(ILlcpSocket service, int handle) {
+	public LlcpSocket(ILlcpSocket service, int handle) {
 		this.mService = service;
 		this.mHandle = handle;
 	}
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index f3be8b0..e2a959d 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -24,6 +24,7 @@
 #include "SkPorterDuff.h"
 
 #include <SkiaColorFilter.h>
+#include <Caches.h>
 
 namespace android {
 
@@ -32,28 +33,37 @@
 class SkColorFilterGlue {
 public:
     static void finalizer(JNIEnv* env, jobject clazz, SkColorFilter* obj, SkiaColorFilter* f) {
-        delete f;
         obj->safeUnref();
+        // f == NULL when not !USE_OPENGL_RENDERER, so no need to delete outside the ifdef
+#ifdef USE_OPENGL_RENDERER
+        if (android::uirenderer::Caches::hasInstance()) {
+            android::uirenderer::Caches::getInstance().resourceCache.destructor(f);
+        } else {
+            delete f;
+        }
+#endif
     }
 
-    static SkiaColorFilter* glCreatePorterDuffFilter(JNIEnv* env, jobject, jint srcColor,
-            SkPorterDuff::Mode mode) {
+    static SkiaColorFilter* glCreatePorterDuffFilter(JNIEnv* env, jobject, SkColorFilter *skFilter,
+            jint srcColor, SkPorterDuff::Mode mode) {
 #ifdef USE_OPENGL_RENDERER
-        return new SkiaBlendFilter(srcColor, SkPorterDuff::ToXfermodeMode(mode));
+        return new SkiaBlendFilter(skFilter, srcColor, SkPorterDuff::ToXfermodeMode(mode));
 #else
         return NULL;
 #endif
     }
 
-    static SkiaColorFilter* glCreateLightingFilter(JNIEnv* env, jobject, jint mul, jint add) {
+    static SkiaColorFilter* glCreateLightingFilter(JNIEnv* env, jobject, SkColorFilter *skFilter,
+            jint mul, jint add) {
 #ifdef USE_OPENGL_RENDERER
-        return new SkiaLightingFilter(mul, add);
+        return new SkiaLightingFilter(skFilter, mul, add);
 #else
         return NULL;
 #endif
     }
 
-    static SkiaColorFilter* glCreateColorMatrixFilter(JNIEnv* env, jobject, jfloatArray jarray) {
+    static SkiaColorFilter* glCreateColorMatrixFilter(JNIEnv* env, jobject, SkColorFilter *skFilter,
+            jfloatArray jarray) {
 #ifdef USE_OPENGL_RENDERER
         AutoJavaFloatArray autoArray(env, jarray, 20);
         const float* src = autoArray.ptr();
@@ -70,7 +80,7 @@
         colorVector[2] = src[14];
         colorVector[3] = src[19];
 
-        return new SkiaColorMatrixFilter(colorMatrix, colorVector);
+        return new SkiaColorMatrixFilter(skFilter, colorMatrix, colorVector);
 #else
         return NULL;
 #endif
@@ -107,17 +117,17 @@
 
 static JNINativeMethod porterduff_methods[] = {
     { "native_CreatePorterDuffFilter", "(II)I", (void*) SkColorFilterGlue::CreatePorterDuffFilter   },
-    { "nCreatePorterDuffFilter",       "(II)I", (void*) SkColorFilterGlue::glCreatePorterDuffFilter }
+    { "nCreatePorterDuffFilter",       "(III)I", (void*) SkColorFilterGlue::glCreatePorterDuffFilter }
 };
 
 static JNINativeMethod lighting_methods[] = {
     { "native_CreateLightingFilter", "(II)I", (void*) SkColorFilterGlue::CreateLightingFilter   },
-    { "nCreateLightingFilter",       "(II)I", (void*) SkColorFilterGlue::glCreateLightingFilter },
+    { "nCreateLightingFilter",       "(III)I", (void*) SkColorFilterGlue::glCreateLightingFilter },
 };
 
 static JNINativeMethod colormatrix_methods[] = {
     { "nativeColorMatrixFilter", "([F)I", (void*) SkColorFilterGlue::CreateColorMatrixFilter   },
-    { "nColorMatrixFilter",      "([F)I", (void*) SkColorFilterGlue::glCreateColorMatrixFilter }
+    { "nColorMatrixFilter",      "(I[F)I", (void*) SkColorFilterGlue::glCreateColorMatrixFilter }
 };
 
 #define REG(env, name, array) \
diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp
index b305506..d0871ac5 100644
--- a/core/jni/android/graphics/Matrix.cpp
+++ b/core/jni/android/graphics/Matrix.cpp
@@ -32,12 +32,6 @@
 public:
 
     static void finalizer(JNIEnv* env, jobject clazz, SkMatrix* obj) {
-#ifdef USE_OPENGL_RENDERER
-        if (android::uirenderer::Caches::hasInstance()) {
-            android::uirenderer::Caches::getInstance().resourceCache.destructor(obj);
-            return;
-        }
-#endif // USE_OPENGL_RENDERER
         delete obj;
     }
 
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 79a02f1..e62b034 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -63,12 +63,6 @@
     };
 
     static void finalizer(JNIEnv* env, jobject clazz, SkPaint* obj) {
-#ifdef USE_OPENGL_RENDERER
-        if (android::uirenderer::Caches::hasInstance()) {
-            android::uirenderer::Caches::getInstance().resourceCache.destructor(obj);
-            return;
-        }
-#endif // USE_OPENGL_RENDERER
         delete obj;
     }
 
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 79051c2..4be1321 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -58,6 +58,8 @@
 #ifdef USE_OPENGL_RENDERER
     if (android::uirenderer::Caches::hasInstance()) {
         android::uirenderer::Caches::getInstance().resourceCache.destructor(skiaShader);
+    } else {
+        delete skiaShader;
     }
 #endif
 }
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 45fd5a0..a586f49 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -1029,7 +1029,7 @@
 
 #define FIND_CLASS(var, className) \
         var = env->FindClass(className); \
-        LOG_FATAL_IF(! var, "Unable to find class " className); \
+        LOG_FATAL_IF(! var, "Unable to find class %s", className); \
         var = jclass(env->NewGlobalRef(var));
 
 #define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index defd0a0..a024420 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -25,6 +25,7 @@
 #include "wifi.h"
 
 #define WIFI_PKG_NAME "android/net/wifi/WifiNative"
+#define BUF_SIZE 256
 
 namespace android {
 
@@ -67,7 +68,7 @@
 
 static jint doIntCommand(const char *cmd)
 {
-    char reply[256];
+    char reply[BUF_SIZE];
 
     if (doCommand(cmd, reply, sizeof(reply)) != 0) {
         return (jint)-1;
@@ -78,7 +79,7 @@
 
 static jboolean doBooleanCommand(const char *cmd, const char *expect)
 {
-    char reply[256];
+    char reply[BUF_SIZE];
 
     if (doCommand(cmd, reply, sizeof(reply)) != 0) {
         return (jboolean)JNI_FALSE;
@@ -137,7 +138,7 @@
 
 static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject clazz)
 {
-    char buf[256];
+    char buf[BUF_SIZE];
 
     int nread = ::wifi_wait_for_event(buf, sizeof buf);
     if (nread > 0) {
@@ -159,7 +160,7 @@
 
 static jboolean android_net_wifi_wpsPbcCommand(JNIEnv* env, jobject clazz, jstring bssid)
 {
-    char cmdstr[50];
+    char cmdstr[BUF_SIZE];
     jboolean isCopy;
 
     const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy);
@@ -172,9 +173,9 @@
     return doBooleanCommand(cmdstr, "OK");
 }
 
-static jboolean android_net_wifi_wpsPinCommand(JNIEnv* env, jobject clazz, jstring bssid, int apPin)
+static jboolean android_net_wifi_wpsPinFromAccessPointCommand(JNIEnv* env, jobject clazz, jstring bssid, int apPin)
 {
-    char cmdstr[50];
+    char cmdstr[BUF_SIZE];
     jboolean isCopy;
 
     const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy);
@@ -187,13 +188,29 @@
     return doBooleanCommand(cmdstr, "OK");
 }
 
+static jint android_net_wifi_wpsPinFromDeviceCommand(JNIEnv* env, jobject clazz, jstring bssid)
+{
+    char cmdstr[BUF_SIZE];
+    jboolean isCopy;
+
+    const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy);
+    int numWritten = snprintf(cmdstr, sizeof(cmdstr), "WPS_PIN %s", bssidStr);
+    env->ReleaseStringUTFChars(bssid, bssidStr);
+
+    if ((numWritten == -1) || (numWritten >= (int)sizeof(cmdstr))) {
+        return false;
+    }
+    return doIntCommand(cmdstr);
+}
+
+
 static jboolean android_net_wifi_setNetworkVariableCommand(JNIEnv* env,
                                                            jobject clazz,
                                                            jint netId,
                                                            jstring name,
                                                            jstring value)
 {
-    char cmdstr[256];
+    char cmdstr[BUF_SIZE];
     jboolean isCopy;
 
     const char *nameStr = env->GetStringUTFChars(name, &isCopy);
@@ -216,7 +233,7 @@
                                                           jint netId,
                                                           jstring name)
 {
-    char cmdstr[256];
+    char cmdstr[BUF_SIZE];
     jboolean isCopy;
 
     const char *nameStr = env->GetStringUTFChars(name, &isCopy);
@@ -234,7 +251,7 @@
 
 static jboolean android_net_wifi_removeNetworkCommand(JNIEnv* env, jobject clazz, jint netId)
 {
-    char cmdstr[256];
+    char cmdstr[BUF_SIZE];
 
     int numWritten = snprintf(cmdstr, sizeof(cmdstr), "REMOVE_NETWORK %d", netId);
     int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
@@ -247,7 +264,7 @@
                                                   jint netId,
                                                   jboolean disableOthers)
 {
-    char cmdstr[256];
+    char cmdstr[BUF_SIZE];
     const char *cmd = disableOthers ? "SELECT_NETWORK" : "ENABLE_NETWORK";
 
     int numWritten = snprintf(cmdstr, sizeof(cmdstr), "%s %d", cmd, netId);
@@ -258,7 +275,7 @@
 
 static jboolean android_net_wifi_disableNetworkCommand(JNIEnv* env, jobject clazz, jint netId)
 {
-    char cmdstr[256];
+    char cmdstr[BUF_SIZE];
 
     int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DISABLE_NETWORK %d", netId);
     int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
@@ -352,7 +369,7 @@
 
 static jint android_net_wifi_getRssiHelper(const char *cmd)
 {
-    char reply[256];
+    char reply[BUF_SIZE];
     int rssi = -200;
 
     if (doCommand(cmd, reply, sizeof(reply)) != 0) {
@@ -391,7 +408,7 @@
 
 static jint android_net_wifi_getLinkSpeedCommand(JNIEnv* env, jobject clazz)
 {
-    char reply[256];
+    char reply[BUF_SIZE];
     int linkspeed;
 
     if (doCommand("DRIVER LINKSPEED", reply, sizeof(reply)) != 0) {
@@ -405,8 +422,8 @@
 
 static jstring android_net_wifi_getMacAddressCommand(JNIEnv* env, jobject clazz)
 {
-    char reply[256];
-    char buf[256];
+    char reply[BUF_SIZE];
+    char buf[BUF_SIZE];
 
     if (doCommand("DRIVER MACADDR", reply, sizeof(reply)) != 0) {
         return env->NewStringUTF(NULL);
@@ -421,7 +438,7 @@
 
 static jboolean android_net_wifi_setPowerModeCommand(JNIEnv* env, jobject clazz, jint mode)
 {
-    char cmdstr[256];
+    char cmdstr[BUF_SIZE];
 
     int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER POWERMODE %d", mode);
     int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
@@ -431,7 +448,7 @@
 
 static jint android_net_wifi_getPowerModeCommand(JNIEnv* env, jobject clazz)
 {
-    char reply[256];
+    char reply[BUF_SIZE];
     int power;
 
     if (doCommand("DRIVER GETPOWER", reply, sizeof(reply)) != 0) {
@@ -469,7 +486,7 @@
 
 static jboolean android_net_wifi_setNumAllowedChannelsCommand(JNIEnv* env, jobject clazz, jint numChannels)
 {
-    char cmdstr[256];
+    char cmdstr[BUF_SIZE];
 
     int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER SCAN-CHANNELS %u", numChannels);
     int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
@@ -479,7 +496,7 @@
 
 static jint android_net_wifi_getNumAllowedChannelsCommand(JNIEnv* env, jobject clazz)
 {
-    char reply[256];
+    char reply[BUF_SIZE];
     int numChannels;
 
     if (doCommand("DRIVER SCAN-CHANNELS", reply, sizeof(reply)) != 0) {
@@ -495,7 +512,7 @@
 
 static jboolean android_net_wifi_setBluetoothCoexistenceModeCommand(JNIEnv* env, jobject clazz, jint mode)
 {
-    char cmdstr[256];
+    char cmdstr[BUF_SIZE];
 
     int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER BTCOEXMODE %d", mode);
     int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
@@ -505,7 +522,7 @@
 
 static jboolean android_net_wifi_setBluetoothCoexistenceScanModeCommand(JNIEnv* env, jobject clazz, jboolean setCoexScanMode)
 {
-    char cmdstr[256];
+    char cmdstr[BUF_SIZE];
 
     int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER BTCOEXSCAN-%s", setCoexScanMode ? "START" : "STOP");
     int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
@@ -527,7 +544,7 @@
 
 static jboolean android_net_wifi_setScanResultHandlingCommand(JNIEnv* env, jobject clazz, jint mode)
 {
-    char cmdstr[256];
+    char cmdstr[BUF_SIZE];
 
     int numWritten = snprintf(cmdstr, sizeof(cmdstr), "AP_SCAN %d", mode);
     int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
@@ -537,7 +554,7 @@
 
 static jboolean android_net_wifi_addToBlacklistCommand(JNIEnv* env, jobject clazz, jstring bssid)
 {
-    char cmdstr[256];
+    char cmdstr[BUF_SIZE];
     jboolean isCopy;
 
     const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy);
@@ -554,6 +571,15 @@
     return doBooleanCommand("BLACKLIST clear", "OK");
 }
 
+static jboolean android_net_wifi_setSuspendOptimizationsCommand(JNIEnv* env, jobject clazz, jboolean enabled)
+{
+    char cmdstr[BUF_SIZE];
+
+    snprintf(cmdstr, sizeof(cmdstr), "DRIVER SETSUSPENDOPT %d", enabled ? 0 : 1);
+    return doBooleanCommand(cmdstr, "OK");
+}
+
+
 static jboolean android_net_wifi_doDhcpRequest(JNIEnv* env, jobject clazz, jobject info)
 {
     jint ipaddr, gateway, mask, dns1, dns2, server, lease;
@@ -636,7 +662,12 @@
     { "addToBlacklistCommand", "(Ljava/lang/String;)Z", (void*) android_net_wifi_addToBlacklistCommand },
     { "clearBlacklistCommand", "()Z", (void*) android_net_wifi_clearBlacklistCommand },
     { "startWpsPbcCommand", "(Ljava/lang/String;)Z", (void*) android_net_wifi_wpsPbcCommand },
-    { "startWpsPinCommand", "(Ljava/lang/String;I)Z", (void*) android_net_wifi_wpsPinCommand },
+    { "startWpsWithPinFromAccessPointCommand", "(Ljava/lang/String;I)Z",
+        (void*) android_net_wifi_wpsPinFromAccessPointCommand },
+    { "startWpsWithPinFromDeviceCommand", "(Ljava/lang/String;)I",
+        (void*) android_net_wifi_wpsPinFromDeviceCommand },
+    { "setSuspendOptimizationsCommand", "(Z)Z",
+        (void*) android_net_wifi_setSuspendOptimizationsCommand},
     { "doDhcpRequest", "(Landroid/net/DhcpInfo;)Z", (void*) android_net_wifi_doDhcpRequest },
     { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_wifi_getDhcpError },
 };
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index a9b91b04..b0ba695 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -813,7 +813,7 @@
         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     }
 
-    LOGE("%s: Received signal %s:%s from %s", __FUNCTION__,
+    LOGV("%s: Received signal %s:%s from %s", __FUNCTION__,
         dbus_message_get_interface(msg), dbus_message_get_member(msg),
         dbus_message_get_path(msg));
 
diff --git a/core/res/res/drawable-hdpi/tab_arrow_left_holo_dark.png b/core/res/res/drawable-hdpi/tab_arrow_left_holo_dark.png
deleted file mode 100644
index cfd6f78..0000000
--- a/core/res/res/drawable-hdpi/tab_arrow_left_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_arrow_left_holo_light.png b/core/res/res/drawable-hdpi/tab_arrow_left_holo_light.png
deleted file mode 100644
index 036aa8c..0000000
--- a/core/res/res/drawable-hdpi/tab_arrow_left_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_arrow_right_holo_dark.png b/core/res/res/drawable-hdpi/tab_arrow_right_holo_dark.png
deleted file mode 100644
index b226038..0000000
--- a/core/res/res/drawable-hdpi/tab_arrow_right_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_arrow_right_holo_light.png b/core/res/res/drawable-hdpi/tab_arrow_right_holo_light.png
deleted file mode 100644
index 0e5fbe6..0000000
--- a/core/res/res/drawable-hdpi/tab_arrow_right_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_bottom_holo.9.png b/core/res/res/drawable-hdpi/tab_bottom_holo.9.png
new file mode 100644
index 0000000..ec9fa8d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_bottom_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_divider_holo_dark.png b/core/res/res/drawable-hdpi/tab_divider_holo_dark.png
deleted file mode 100644
index 112cb04..0000000
--- a/core/res/res/drawable-hdpi/tab_divider_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_divider_holo_light.png b/core/res/res/drawable-hdpi/tab_divider_holo_light.png
deleted file mode 100644
index 1bf4d38..0000000
--- a/core/res/res/drawable-hdpi/tab_divider_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected_focused_holo.9.png b/core/res/res/drawable-hdpi/tab_selected_focused_holo.9.png
new file mode 100644
index 0000000..1ba35d5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_selected_focused_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected_holo.9.png b/core/res/res/drawable-hdpi/tab_selected_holo.9.png
new file mode 100644
index 0000000..ef913cc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_selected_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected_pressed_focused_holo.9.png b/core/res/res/drawable-hdpi/tab_selected_pressed_focused_holo.9.png
new file mode 100644
index 0000000..d7e9688
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_selected_pressed_focused_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png b/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png
new file mode 100644
index 0000000..b8b1fcf
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selector_holo_dark.9.png b/core/res/res/drawable-hdpi/tab_selector_holo_dark.9.png
deleted file mode 100644
index f01b9bc..0000000
--- a/core/res/res/drawable-hdpi/tab_selector_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_strip_holo.9.png b/core/res/res/drawable-hdpi/tab_strip_holo.9.png
deleted file mode 100644
index d937f6b..0000000
--- a/core/res/res/drawable-hdpi/tab_strip_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_unselected_focused_holo.9.png b/core/res/res/drawable-hdpi/tab_unselected_focused_holo.9.png
new file mode 100644
index 0000000..256e8e7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_unselected_focused_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_unselected_holo.9.png b/core/res/res/drawable-hdpi/tab_unselected_holo.9.png
new file mode 100644
index 0000000..eaa306a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_unselected_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_unselected_pressed_focused_holo.9.png b/core/res/res/drawable-hdpi/tab_unselected_pressed_focused_holo.9.png
new file mode 100644
index 0000000..d17b820
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_unselected_pressed_focused_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png b/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png
new file mode 100644
index 0000000..a344994
--- /dev/null
+++ b/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_arrow_left_holo_dark.png b/core/res/res/drawable-mdpi/tab_arrow_left_holo_dark.png
deleted file mode 100644
index 4f8bafe..0000000
--- a/core/res/res/drawable-mdpi/tab_arrow_left_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_arrow_left_holo_light.png b/core/res/res/drawable-mdpi/tab_arrow_left_holo_light.png
deleted file mode 100644
index 8e225fc..0000000
--- a/core/res/res/drawable-mdpi/tab_arrow_left_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_arrow_right_holo_dark.png b/core/res/res/drawable-mdpi/tab_arrow_right_holo_dark.png
deleted file mode 100644
index 0a8006d..0000000
--- a/core/res/res/drawable-mdpi/tab_arrow_right_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_arrow_right_holo_light.png b/core/res/res/drawable-mdpi/tab_arrow_right_holo_light.png
deleted file mode 100644
index 85aae47..0000000
--- a/core/res/res/drawable-mdpi/tab_arrow_right_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_bottom_holo.9.png b/core/res/res/drawable-mdpi/tab_bottom_holo.9.png
new file mode 100644
index 0000000..1e40b9c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_bottom_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_divider_holo_dark.png b/core/res/res/drawable-mdpi/tab_divider_holo_dark.png
deleted file mode 100644
index 89d7b8b..0000000
--- a/core/res/res/drawable-mdpi/tab_divider_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_divider_holo_light.png b/core/res/res/drawable-mdpi/tab_divider_holo_light.png
deleted file mode 100644
index 878b2b4..0000000
--- a/core/res/res/drawable-mdpi/tab_divider_holo_light.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_focused_holo.9.png b/core/res/res/drawable-mdpi/tab_focused_holo.9.png
new file mode 100644
index 0000000..187d8c5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_focused_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_pressed_holo.9.png b/core/res/res/drawable-mdpi/tab_pressed_holo.9.png
new file mode 100644
index 0000000..a76fbae
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_selected_focused_holo.9.png b/core/res/res/drawable-mdpi/tab_selected_focused_holo.9.png
new file mode 100644
index 0000000..9a33cd2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_selected_focused_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_selected_holo.9.png b/core/res/res/drawable-mdpi/tab_selected_holo.9.png
new file mode 100644
index 0000000..e029e57
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_selected_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_selected_pressed_focused_holo.9.png b/core/res/res/drawable-mdpi/tab_selected_pressed_focused_holo.9.png
new file mode 100644
index 0000000..285116e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_selected_pressed_focused_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png b/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png
new file mode 100644
index 0000000..dadefa7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_selector_holo_dark.9.png b/core/res/res/drawable-mdpi/tab_selector_holo_dark.9.png
deleted file mode 100644
index 30d30df..0000000
--- a/core/res/res/drawable-mdpi/tab_selector_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_unselected_focused_holo.9.png b/core/res/res/drawable-mdpi/tab_unselected_focused_holo.9.png
new file mode 100644
index 0000000..032a992
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_unselected_focused_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_unselected_holo.9.png b/core/res/res/drawable-mdpi/tab_unselected_holo.9.png
new file mode 100644
index 0000000..848f3f1
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_unselected_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_unselected_pressed_focused_holo.9.png b/core/res/res/drawable-mdpi/tab_unselected_pressed_focused_holo.9.png
new file mode 100644
index 0000000..3845135
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_unselected_pressed_focused_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.png b/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.png
new file mode 100644
index 0000000..23fd8c9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable/tab_bottom_right.xml b/core/res/res/drawable/tab_bottom_right.xml
index f7f5c2f..450c461 100644
--- a/core/res/res/drawable/tab_bottom_right.xml
+++ b/core/res/res/drawable/tab_bottom_right.xml
@@ -16,6 +16,6 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_pressed="true" android:drawable="@drawable/tab_press_bar_right"/>
-    <item android:state_focused="false" android:state_pressed="false" android:drawable="@drawable/tab_selected_bar_right"/>
-    <item android:state_focused="true" android:state_pressed="false" android:drawable="@drawable/tab_focus_bar_right"/>
+    <item android:state_focused="false" android:drawable="@drawable/tab_selected_bar_right"/>
+    <item android:state_focused="true" android:drawable="@drawable/tab_focus_bar_right"/>
 </selector>
diff --git a/core/res/res/drawable/tab_indicator_holo.xml b/core/res/res/drawable/tab_indicator_holo.xml
new file mode 100644
index 0000000..0d46e0c
--- /dev/null
+++ b/core/res/res/drawable/tab_indicator_holo.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- Non focused states -->
+    <item android:state_focused="false" android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/tab_unselected_holo" />
+    <item android:state_focused="false" android:state_selected="true"  android:state_pressed="false" android:drawable="@drawable/tab_selected_holo" />
+
+    <!-- Focused states -->
+    <item android:state_focused="true" android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/tab_unselected_focused_holo" />
+    <item android:state_focused="true" android:state_selected="true"  android:state_pressed="false" android:drawable="@drawable/tab_selected_focused_holo" />
+
+    <!-- Pressed -->
+    <!--    Non focused states -->
+    <item android:state_focused="false" android:state_selected="false" android:state_pressed="true" android:drawable="@drawable/tab_unselected_pressed_holo" />
+    <item android:state_focused="false" android:state_selected="true"  android:state_pressed="true" android:drawable="@drawable/tab_selected_pressed_holo" />
+
+    <!--    Focused states -->
+    <item android:state_focused="true" android:state_selected="false" android:state_pressed="true" android:drawable="@drawable/tab_unselected_pressed_focused_holo" />
+    <item android:state_focused="true" android:state_selected="true"  android:state_pressed="true" android:drawable="@drawable/tab_selected_pressed_focused_holo" />
+</selector>
diff --git a/core/res/res/layout/tab_indicator.xml b/core/res/res/layout/tab_indicator.xml
index 71e4001..bc657c3 100644
--- a/core/res/res/layout/tab_indicator.xml
+++ b/core/res/res/layout/tab_indicator.xml
@@ -20,7 +20,6 @@
     android:layout_weight="1"
     android:layout_marginLeft="-3dip"
     android:layout_marginRight="-3dip"
-    android:orientation="vertical"
     android:background="@android:drawable/tab_indicator">
 
     <ImageView android:id="@+id/icon"
diff --git a/core/res/res/layout/tab_indicator_holo.xml b/core/res/res/layout/tab_indicator_holo.xml
new file mode 100644
index 0000000..d37476b
--- /dev/null
+++ b/core/res/res/layout/tab_indicator_holo.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="56dip"
+    android:layout_weight="0"
+    android:layout_marginLeft="0dip"
+    android:layout_marginRight="0dip"
+    android:background="@android:drawable/tab_indicator_holo">
+
+    <View android:id="@+id/tab_indicator_left_spacer"
+        android:layout_width="16dip"
+        android:layout_height="0dip" />
+
+    <ImageView android:id="@+id/icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:visibility="gone"
+        android:layout_toRightOf="@id/tab_indicator_left_spacer"
+        android:paddingRight="8dip" />
+
+    <TextView android:id="@+id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:layout_toRightOf="@id/icon"
+        android:paddingLeft="0dip"
+        android:paddingRight="16dip"
+        style="?android:attr/tabWidgetStyle" />
+
+</RelativeLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d5f1610..dab627c 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2137,6 +2137,8 @@
         <attr name="tabStripLeft" format="reference" />
         <!-- Drawable used to draw the right part of the strip underneath the tabs. -->
         <attr name="tabStripRight" format="reference" />
+        <!-- Layout used to organize each tab's content. -->
+        <attr name="tabLayout" format="reference" />
     </declare-styleable>
     <declare-styleable name="TextAppearance">
         <!-- Text color. -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d5ea09e..749b3c7 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1633,7 +1633,7 @@
 
     <!-- Do not translate.  WebView User Agent string -->
     <string name="web_user_agent" translatable="false">Mozilla/5.0 (Linux; U; <xliff:g id="x">Android %s</xliff:g>)
-        AppleWebKit/534.10 (KHTML, like Gecko) Version/4.0 <xliff:g id="mobile">%s</xliff:g>Safari/534.10</string>
+        AppleWebKit/534.11 (KHTML, like Gecko) Version/4.0 <xliff:g id="mobile">%s</xliff:g>Safari/534.11</string>
     <!-- Do not translate.  WebView User Agent targeted content -->
     <string name="web_user_agent_target_content" translatable="false">"Mobile "</string>
 
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index c441f5a..76a3c34 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -560,6 +560,12 @@
         <item name="android:textAppearance">@style/TextAppearance.Widget.TabWidget</item>
         <item name="ellipsize">marquee</item>
         <item name="singleLine">true</item>
+        <item name="android:tabStripLeft">@android:drawable/tab_bottom_left</item>
+        <item name="android:tabStripRight">@android:drawable/tab_bottom_right</item>
+        <item name="android:tabStripEnabled">true</item>
+        <item name="android:divider">@null</item>
+        <item name="android:gravity">fill_horizontal|center_vertical</item>
+        <item name="android:tabLayout">@android:layout/tab_indicator</item>
     </style>
 
     <style name="Widget.Gallery">
@@ -1070,7 +1076,7 @@
     </style>
 
     <style name="TextAppearance.Holo.Widget.TabWidget">
-        <item name="android:textSize">14sp</item>
+        <item name="android:textSize">18sp</item>
         <item name="android:textStyle">normal</item>
         <item name="android:textColor">@android:color/tab_indicator_text</item>
     </style>
@@ -1421,6 +1427,13 @@
     </style>
 
     <style name="Widget.Holo.TabWidget" parent="Widget.TabWidget">
+        <item name="android:textAppearance">@style/TextAppearance.Holo.Widget.TabWidget</item>
+        <item name="android:tabStripLeft">@null</item>
+        <item name="android:tabStripRight">@null</item>
+        <item name="android:tabStripEnabled">false</item>
+        <item name="android:divider">@null</item>
+        <item name="android:gravity">left|center_vertical</item>
+        <item name="android:tabLayout">@android:layout/tab_indicator_holo</item>
     </style>
 
     <style name="Widget.Holo.WebTextView" parent="Widget.WebTextView">
@@ -1693,7 +1706,7 @@
     <style name="Widget.Holo.Light.CompoundButton.Star" parent="Widget.CompoundButton.Star">
     </style>
 
-    <style name="Widget.Holo.Light.TabWidget" parent="Widget.TabWidget">
+    <style name="Widget.Holo.Light.TabWidget" parent="Widget.Holo.TabWidget">
     </style>
 
     <style name="Widget.Holo.Light.WebTextView" parent="Widget.WebTextView">
diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp
index 843dddb..cf9bab1 100644
--- a/drm/drmserver/DrmManagerService.cpp
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -28,25 +28,10 @@
 using namespace android;
 
 #define SUCCESS 0
-#define DRM_DIRECTORY_PERMISSION 0700
-#define DRM_PLUGINS_ROOT "/data/drm/plugins"
-#define DRM_PLUGINS_NATIVE "/data/drm/plugins/native"
-#define DRM_PLUGINS_NATIVE_DATABASES "/data/drm/plugins/native/databases"
 
 void DrmManagerService::instantiate() {
     LOGV("instantiate");
-
-    int res = mkdir(DRM_PLUGINS_ROOT, DRM_DIRECTORY_PERMISSION);
-    if (SUCCESS == res || EEXIST == errno) {
-        res = mkdir(DRM_PLUGINS_NATIVE, DRM_DIRECTORY_PERMISSION);
-        if (SUCCESS == res || EEXIST == errno) {
-            res = mkdir(DRM_PLUGINS_NATIVE_DATABASES, DRM_DIRECTORY_PERMISSION);
-            if (SUCCESS == res || EEXIST == errno) {
-                defaultServiceManager()
-                    ->addService(String16("drm.drmManager"), new DrmManagerService());
-            }
-        }
-    }
+    defaultServiceManager()->addService(String16("drm.drmManager"), new DrmManagerService());
 }
 
 DrmManagerService::DrmManagerService() {
diff --git a/graphics/java/android/graphics/ColorMatrixColorFilter.java b/graphics/java/android/graphics/ColorMatrixColorFilter.java
index 245c615..4f32342 100644
--- a/graphics/java/android/graphics/ColorMatrixColorFilter.java
+++ b/graphics/java/android/graphics/ColorMatrixColorFilter.java
@@ -27,7 +27,7 @@
     public ColorMatrixColorFilter(ColorMatrix matrix) {
         final float[] colorMatrix = matrix.getArray();
         native_instance = nativeColorMatrixFilter(colorMatrix);
-        nativeColorFilter = nColorMatrixFilter(colorMatrix);
+        nativeColorFilter = nColorMatrixFilter(native_instance, colorMatrix);
     }
 
     /**
@@ -42,9 +42,9 @@
             throw new ArrayIndexOutOfBoundsException();
         }
         native_instance = nativeColorMatrixFilter(array);
-        nativeColorFilter = nColorMatrixFilter(array);
+        nativeColorFilter = nColorMatrixFilter(native_instance, array);
     }
 
     private static native int nativeColorMatrixFilter(float[] array);
-    private static native int nColorMatrixFilter(float[] array);
+    private static native int nColorMatrixFilter(int nativeFilter, float[] array);
 }
diff --git a/graphics/java/android/graphics/LightingColorFilter.java b/graphics/java/android/graphics/LightingColorFilter.java
index 715ce86..c621de6 100644
--- a/graphics/java/android/graphics/LightingColorFilter.java
+++ b/graphics/java/android/graphics/LightingColorFilter.java
@@ -30,9 +30,9 @@
      */
     public LightingColorFilter(int mul, int add) {
         native_instance = native_CreateLightingFilter(mul, add);
-        nativeColorFilter = nCreateLightingFilter(mul, add);
+        nativeColorFilter = nCreateLightingFilter(native_instance, mul, add);
     }
 
     private static native int native_CreateLightingFilter(int mul, int add);
-    private static native int nCreateLightingFilter(int mul, int add);
+    private static native int nCreateLightingFilter(int nativeFilter, int mul, int add);
 }
diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java
index b02dab1..ecc7c24 100644
--- a/graphics/java/android/graphics/PorterDuffColorFilter.java
+++ b/graphics/java/android/graphics/PorterDuffColorFilter.java
@@ -26,9 +26,10 @@
      */
     public PorterDuffColorFilter(int srcColor, PorterDuff.Mode mode) {
         native_instance = native_CreatePorterDuffFilter(srcColor, mode.nativeInt);
-        nativeColorFilter = nCreatePorterDuffFilter(srcColor, mode.nativeInt);
+        nativeColorFilter = nCreatePorterDuffFilter(native_instance, srcColor, mode.nativeInt);
     }
 
     private static native int native_CreatePorterDuffFilter(int srcColor, int porterDuffMode);
-    private static native int nCreatePorterDuffFilter(int srcColor, int porterDuffMode);
+    private static native int nCreatePorterDuffFilter(int nativeFilter, int srcColor,
+            int porterDuffMode);
 }
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 6fef2e7..0f4fbfb 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -39,6 +39,11 @@
         // The client wants to access the output buffer's video
         // data for example for thumbnail extraction.
         kClientNeedsFramebuffer  = 4,
+
+        // Request for software or hardware codecs. If request
+        // can not be fullfilled, Create() returns NULL.
+        kSoftwareCodecsOnly      = 8,
+        kHardwareCodecsOnly      = 16,
     };
     static sp<MediaSource> Create(
             const sp<IOMX> &omx,
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index a4def0b..e0094d8 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -43,7 +43,7 @@
     glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
     glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
 
-    currentBuffer = meshBuffer;
+    mCurrentBuffer = meshBuffer;
 }
 
 /**
@@ -57,9 +57,9 @@
  * Binds the specified VBO.
  */
 void Caches::bindMeshBuffer(const GLuint buffer) {
-    if (currentBuffer != buffer) {
+    if (mCurrentBuffer != buffer) {
         glBindBuffer(GL_ARRAY_BUFFER, buffer);
-        currentBuffer = buffer;
+        mCurrentBuffer = buffer;
     }
 }
 
@@ -67,9 +67,9 @@
  * Unbinds the VBO used to render simple textured quads.
  */
 void Caches::unbindMeshBuffer() {
-    if (currentBuffer) {
+    if (mCurrentBuffer) {
         glBindBuffer(GL_ARRAY_BUFFER, 0);
-        currentBuffer = 0;
+        mCurrentBuffer = 0;
     }
 }
 
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 79644a5..aff5366 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -79,7 +79,9 @@
 
     friend class Singleton<Caches>;
 
-    CacheLogger logger;
+    CacheLogger mlogger;
+
+    GLuint mCurrentBuffer;
 
 public:
     void bindMeshBuffer();
@@ -92,7 +94,6 @@
     Program* currentProgram;
 
     GLuint meshBuffer;
-    GLuint currentBuffer;
 
     TextureCache textureCache;
     LayerCache layerCache;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index a43f164..0dd9c5a 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -108,18 +108,7 @@
         mBitmapResources.add(resource);
         caches.resourceCache.incrementRefcount(resource);
     }
-    const Vector<SkMatrix*> &matrixResources = recorder.getMatrixResources();
-    for (size_t i = 0; i < matrixResources.size(); i++) {
-        SkMatrix* resource = matrixResources.itemAt(i);
-        mMatrixResources.add(resource);
-        caches.resourceCache.incrementRefcount(resource);
-    }
-    const Vector<SkPaint*> &paintResources = recorder.getPaintResources();
-    for (size_t i = 0; i < paintResources.size(); i++) {
-        SkPaint* resource = paintResources.itemAt(i);
-        mPaintResources.add(resource);
-        caches.resourceCache.incrementRefcount(resource);
-    }
+
     const Vector<SkiaShader*> &shaderResources = recorder.getShaderResources();
     for (size_t i = 0; i < shaderResources.size(); i++) {
         SkiaShader* resource = shaderResources.itemAt(i);
@@ -127,6 +116,16 @@
         caches.resourceCache.incrementRefcount(resource);
     }
 
+    const Vector<SkPaint*> &paints = recorder.getPaints();
+    for (size_t i = 0; i < paints.size(); i++) {
+        mPaints.add(paints.itemAt(i));
+    }
+
+    const Vector<SkMatrix*> &matrices = recorder.getMatrices();
+    for (size_t i = 0; i < matrices.size(); i++) {
+        mMatrices.add(matrices.itemAt(i));
+    }
+
     mPathHeap = recorder.mPathHeap;
     mPathHeap->safeRef();
 }
@@ -137,25 +136,25 @@
     Caches& caches = Caches::getInstance();
 
     for (size_t i = 0; i < mBitmapResources.size(); i++) {
-        SkBitmap* resource = mBitmapResources.itemAt(i);
-        caches.resourceCache.decrementRefcount(resource);
+        caches.resourceCache.decrementRefcount(mBitmapResources.itemAt(i));
     }
     mBitmapResources.clear();
-    for (size_t i = 0; i < mMatrixResources.size(); i++) {
-        SkMatrix* resource = mMatrixResources.itemAt(i);
-        caches.resourceCache.decrementRefcount(resource);
-    }
-    mMatrixResources.clear();
-    for (size_t i = 0; i < mPaintResources.size(); i++) {
-        SkPaint* resource = mPaintResources.itemAt(i);
-        caches.resourceCache.decrementRefcount(resource);
-    }
-    mPaintResources.clear();
+
     for (size_t i = 0; i < mShaderResources.size(); i++) {
-        SkiaShader* resource = mShaderResources.itemAt(i);
-        caches.resourceCache.decrementRefcount(resource);
+        caches.resourceCache.decrementRefcount(mShaderResources.itemAt(i));
     }
     mShaderResources.clear();
+
+    for (size_t i = 0; i < mPaints.size(); i++) {
+        delete mPaints.itemAt(i);
+    }
+    mPaints.clear();
+
+    for (size_t i = 0; i < mMatrices.size(); i++) {
+        delete  mMatrices.itemAt(i);
+    }
+    mMatrices.clear();
+
     mPathHeap->safeUnref();
 }
 
@@ -289,7 +288,7 @@
             }
             break;
             case SetupColorFilter: {
-                // TODO: Implement
+                renderer.setupColorFilter(getColorFilter());
             }
             break;
             case ResetShadow: {
@@ -335,21 +334,16 @@
         caches.resourceCache.decrementRefcount(resource);
     }
     mBitmapResources.clear();
-    for (size_t i = 0; i < mMatrixResources.size(); i++) {
-        SkMatrix* resource = mMatrixResources.itemAt(i);
-        caches.resourceCache.decrementRefcount(resource);
-    }
-    mMatrixResources.clear();
-    for (size_t i = 0; i < mPaintResources.size(); i++) {
-        SkPaint* resource = mPaintResources.itemAt(i);
-        caches.resourceCache.decrementRefcount(resource);
-    }
-    mPaintResources.clear();
+
     for (size_t i = 0; i < mShaderResources.size(); i++) {
         SkiaShader* resource = mShaderResources.itemAt(i);
         caches.resourceCache.decrementRefcount(resource);
     }
     mShaderResources.clear();
+
+    mPaints.clear();
+    mPaintMap.clear();
+    mMatrices.clear();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -518,7 +512,6 @@
 
 void DisplayListRenderer::resetShader() {
     addOp(DisplayList::ResetShader);
-    OpenGLRenderer::resetShader();
 }
 
 void DisplayListRenderer::setupShader(SkiaShader* shader) {
@@ -528,17 +521,15 @@
 
 void DisplayListRenderer::resetColorFilter() {
     addOp(DisplayList::ResetColorFilter);
-    OpenGLRenderer::resetColorFilter();
 }
 
 void DisplayListRenderer::setupColorFilter(SkiaColorFilter* filter) {
-    // TODO: Implement
-    OpenGLRenderer::setupColorFilter(filter);
+    addOp(DisplayList::SetupColorFilter);
+    addColorFilter(filter);
 }
 
 void DisplayListRenderer::resetShadow() {
     addOp(DisplayList::ResetShadow);
-    OpenGLRenderer::resetShadow();
 }
 
 void DisplayListRenderer::setupShadow(float radius, float dx, float dy, int color) {
@@ -546,7 +537,6 @@
     addFloat(radius);
     addPoint(dx, dy);
     addInt(color);
-    OpenGLRenderer::setupShadow(radius, dx, dy, color);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index c8cd801..6636de6 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -135,6 +135,10 @@
         return (SkiaShader*) getInt();
     }
 
+    SkiaColorFilter* getColorFilter() {
+        return (SkiaColorFilter*) getInt();
+    }
+
     inline int getIndex() {
         return mReader.readInt();
     }
@@ -182,9 +186,11 @@
     PathHeap* mPathHeap;
 
     Vector<SkBitmap*> mBitmapResources;
-    Vector<SkMatrix*> mMatrixResources;
-    Vector<SkPaint*> mPaintResources;
     Vector<SkiaShader*> mShaderResources;
+    Vector<SkiaColorFilter*> mFilterResources;
+
+    Vector<SkPaint*> mPaints;
+    Vector<SkMatrix*> mMatrices;
 
     mutable SkFlattenableReadBuffer mReader;
 
@@ -263,18 +269,22 @@
         return mBitmapResources;
     }
 
-    const Vector<SkMatrix*>& getMatrixResources() const {
-        return mMatrixResources;
-    }
-
-    const Vector<SkPaint*>& getPaintResources() const {
-        return mPaintResources;
-    }
-
     const Vector<SkiaShader*>& getShaderResources() const {
         return mShaderResources;
     }
 
+    const Vector<SkPaint*>& getPaints() const {
+        return mPaints;
+    }
+
+    const Vector<SkMatrix*>& getMatrices() const {
+        return mMatrices;
+    }
+
+    const Vector<SkiaColorFilter*>& getFilterResources() const {
+        return mFilterResources;
+    }
+
 private:
     inline void addOp(DisplayList::Op drawOp) {
         mWriter.writeInt(drawOp);
@@ -334,20 +344,30 @@
     }
 
     inline void addPaint(SkPaint* paint) {
-        addInt((int)paint);
-        mPaintResources.add(paint);
-        Caches& caches = Caches::getInstance();
-        caches.resourceCache.incrementRefcount(paint);
+        if (paint == NULL) {
+            addInt((int)NULL);
+            return;
+        }
+        SkPaint *paintCopy =  mPaintMap.valueFor(paint);
+        if (paintCopy == NULL || paintCopy->getGenerationID() != paint->getGenerationID()) {
+            paintCopy = new SkPaint(*paint);
+            mPaintMap.add(paint, paintCopy);
+            mPaints.add(paintCopy);
+        }
+        addInt((int)paintCopy);
     }
 
     inline void addMatrix(SkMatrix* matrix) {
-        addInt((int)matrix);
-        mMatrixResources.add(matrix);
-        Caches& caches = Caches::getInstance();
-        caches.resourceCache.incrementRefcount(matrix);
+        // Copying the matrix is cheap and prevents against the user changing the original
+        // matrix before the operation that uses it
+        addInt((int) new SkMatrix(*matrix));
     }
 
     inline void addBitmap(SkBitmap* bitmap) {
+        // Note that this assumes the bitmap is immutable. There are cases this won't handle
+        // correctly, such as creating the bitmap from scratch, drawing with it, changing its
+        // contents, and drawing again. The only fix would be to always copy it the first time,
+        // which doesn't seem worth the extra cycles for this unlikely case.
         addInt((int)bitmap);
         mBitmapResources.add(bitmap);
         Caches& caches = Caches::getInstance();
@@ -361,12 +381,22 @@
         caches.resourceCache.incrementRefcount(shader);
     }
 
+    inline void addColorFilter(SkiaColorFilter* colorFilter) {
+        addInt((int)colorFilter);
+        mFilterResources.add(colorFilter);
+        Caches& caches = Caches::getInstance();
+        caches.resourceCache.incrementRefcount(colorFilter);
+    }
+
     SkChunkAlloc mHeap;
 
     Vector<SkBitmap*> mBitmapResources;
-    Vector<SkMatrix*> mMatrixResources;
-    Vector<SkPaint*> mPaintResources;
     Vector<SkiaShader*> mShaderResources;
+    Vector<SkiaColorFilter*> mFilterResources;
+
+    Vector<SkPaint*> mPaints;
+    DefaultKeyedVector<SkPaint *, SkPaint *> mPaintMap;
+    Vector<SkMatrix*> mMatrices;
 
     PathHeap* mPathHeap;
     SkWriter32 mWriter;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 7495a06..8592511 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -644,7 +644,7 @@
     }
 
     glActiveTexture(GL_TEXTURE0);
-    const Texture* texture = mCaches.textureCache.get(bitmap);
+    Texture* texture = mCaches.textureCache.get(bitmap);
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
@@ -661,7 +661,7 @@
     }
 
     glActiveTexture(GL_TEXTURE0);
-    const Texture* texture = mCaches.textureCache.get(bitmap);
+    Texture* texture = mCaches.textureCache.get(bitmap);
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
@@ -677,9 +677,10 @@
     }
 
     glActiveTexture(GL_TEXTURE0);
-    const Texture* texture = mCaches.textureCache.get(bitmap);
+    Texture* texture = mCaches.textureCache.get(bitmap);
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
+    setTextureWrapModes(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
 
     const float width = texture->width;
     const float height = texture->height;
@@ -711,9 +712,10 @@
     }
 
     glActiveTexture(GL_TEXTURE0);
-    const Texture* texture = mCaches.textureCache.get(bitmap);
+    Texture* texture = mCaches.textureCache.get(bitmap);
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
+    setTextureWrapModes(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
 
     int alpha;
     SkXfermode::Mode mode;
@@ -1046,7 +1048,7 @@
      // Build and use the appropriate shader
      useProgram(mCaches.programCache.get(description));
 
-     bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, textureUnit);
+     bindTexture(texture, textureUnit);
      glUniform1i(mCaches.currentProgram->getUniform("sampler"), textureUnit);
 
      int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
@@ -1220,11 +1222,13 @@
 }
 
 void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
-        const Texture* texture, SkPaint* paint) {
+        Texture* texture, SkPaint* paint) {
     int alpha;
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
+    setTextureWrapModes(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
+
     drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode,
             texture->blend, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset,
             GL_TRIANGLE_STRIP, gMeshCount);
@@ -1263,7 +1267,7 @@
     }
 
     // Texture
-    bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0);
+    bindTexture(texture);
     glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0);
 
     // Always premultiplied
@@ -1380,11 +1384,29 @@
     return mode->fMode;
 }
 
-void OpenGLRenderer::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) {
+void OpenGLRenderer::bindTexture(GLuint texture, GLuint textureUnit) {
     glActiveTexture(gTextureUnits[textureUnit]);
     glBindTexture(GL_TEXTURE_2D, texture);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
+}
+
+void OpenGLRenderer::setTextureWrapModes(Texture* texture, GLenum wrapS, GLenum wrapT,
+        GLuint textureUnit) {
+    bool bound = false;
+    if (wrapS != texture->wrapS) {
+        glActiveTexture(gTextureUnits[textureUnit]);
+        glBindTexture(GL_TEXTURE_2D, texture->id);
+        bound = true;
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
+        texture->wrapS = wrapS;
+    }
+    if (wrapT != texture->wrapT) {
+        if (!bound) {
+            glActiveTexture(gTextureUnits[textureUnit]);
+            glBindTexture(GL_TEXTURE_2D, texture->id);
+        }
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
+        texture->wrapT = wrapT;
+    }
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index b7615fe..07188d4 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -231,7 +231,7 @@
      * @param paint The paint containing the alpha, blending mode, etc.
      */
     void drawTextureRect(float left, float top, float right, float bottom,
-            const Texture* texture, SkPaint* paint);
+            Texture* texture, SkPaint* paint);
 
     /**
      * Draws a textured mesh with the specified texture. If the indices are omitted,
@@ -360,9 +360,11 @@
     inline void getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode);
 
     /**
-     * Binds the specified texture with the specified wrap modes.
+     * Binds the specified texture to the specified texture unit.
      */
-    inline void bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit = 0);
+    inline void bindTexture(GLuint texture, GLuint textureUnit = 0);
+    inline void setTextureWrapModes(Texture* texture, GLenum wrapS, GLenum wrapT,
+            GLuint textureUnit = 0);
 
     /**
      * Enable or disable blending as necessary. This function sets the appropriate
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index 253a19b..3d21431 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -26,8 +26,6 @@
 namespace android {
 namespace uirenderer {
 
-class Caches;
-
 ///////////////////////////////////////////////////////////////////////////////
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index 20b8d6c..47c5d48 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -62,19 +62,16 @@
     incrementRefcount((void*)bitmapResource, kBitmap);
 }
 
-void ResourceCache::incrementRefcount(SkMatrix* matrixResource) {
-    incrementRefcount((void*)matrixResource, kMatrix);
-}
-
-void ResourceCache::incrementRefcount(SkPaint* paintResource) {
-    incrementRefcount((void*)paintResource, kPaint);
-}
-
 void ResourceCache::incrementRefcount(SkiaShader* shaderResource) {
     shaderResource->getSkShader()->safeRef();
     incrementRefcount((void*)shaderResource, kShader);
 }
 
+void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) {
+    filterResource->getSkColorFilter()->safeRef();
+    incrementRefcount((void*)filterResource, kColorFilter);
+}
+
 void ResourceCache::decrementRefcount(void* resource) {
     ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
     if (ref == NULL) {
@@ -98,6 +95,11 @@
     decrementRefcount((void*)shaderResource);
 }
 
+void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) {
+    filterResource->getSkColorFilter()->safeUnref();
+    decrementRefcount((void*)filterResource);
+}
+
 void ResourceCache::recycle(SkBitmap* resource) {
     if (mCache->indexOfKey(resource) < 0) {
         // not tracking this resource; just recycle the pixel data
@@ -136,34 +138,6 @@
     }
 }
 
-void ResourceCache::destructor(SkMatrix* resource) {
-    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
-    if (ref == NULL) {
-        // If we're not tracking this resource, just delete it
-        delete resource;
-        return;
-    }
-    ref->destroyed = true;
-    if (ref->refCount == 0) {
-        deleteResourceReference(resource, ref);
-        return;
-    }
-}
-
-void ResourceCache::destructor(SkPaint* resource) {
-    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
-    if (ref == NULL) {
-        // If we're not tracking this resource, just delete it
-        delete resource;
-        return;
-    }
-    ref->destroyed = true;
-    if (ref->refCount == 0) {
-        deleteResourceReference(resource, ref);
-        return;
-    }
-}
-
 void ResourceCache::destructor(SkiaShader* resource) {
     ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
     if (ref == NULL) {
@@ -181,6 +155,20 @@
     }
 }
 
+void ResourceCache::destructor(SkiaColorFilter* resource) {
+    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
+    if (ref == NULL) {
+        // If we're not tracking this resource, just delete it
+        delete resource;
+        return;
+    }
+    ref->destroyed = true;
+    if (ref->refCount == 0) {
+        deleteResourceReference(resource, ref);
+        return;
+    }
+}
+
 void ResourceCache::deleteResourceReference(void* resource, ResourceReference* ref) {
     if (ref->recycled && ref->resourceType == kBitmap) {
         ((SkBitmap*) resource)->setPixels(NULL, NULL);
@@ -196,19 +184,21 @@
                 delete bitmap;
             }
             break;
-            case kMatrix:
-                delete (SkMatrix*) resource;
-                break;
-            case kPaint:
-                delete (SkPaint*) resource;
-                break;
             case kShader:
+            {
                 SkiaShader* shader = (SkiaShader*)resource;
                 if (Caches::hasInstance()) {
                     Caches::getInstance().gradientCache.remove(shader->getSkShader());
                 }
                 delete shader;
-                break;
+            }
+            break;
+            case kColorFilter:
+            {
+                SkiaColorFilter* filter = (SkiaColorFilter*)resource;
+                delete filter;
+            }
+            break;
         }
     }
     mCache->removeItem(resource);
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index cda2718..d9b3718 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -18,8 +18,7 @@
 #define ANDROID_UI_RESOURCE_CACHE_H
 
 #include <SkBitmap.h>
-#include <SkMatrix.h>
-#include <SkPaint.h>
+#include <SkiaColorFilter.h>
 #include <SkiaShader.h>
 #include <utils/KeyedVector.h>
 
@@ -31,9 +30,8 @@
  */
 enum ResourceType {
     kBitmap,
-    kMatrix,
-    kPaint,
     kShader,
+    kColorFilter,
 };
 
 class ResourceReference {
@@ -56,19 +54,18 @@
     ResourceCache();
     ~ResourceCache();
     void incrementRefcount(SkBitmap* resource);
-    void incrementRefcount(SkMatrix* resource);
-    void incrementRefcount(SkPaint* resource);
     void incrementRefcount(SkiaShader* resource);
+    void incrementRefcount(SkiaColorFilter* resource);
     void incrementRefcount(const void* resource, ResourceType resourceType);
     void decrementRefcount(void* resource);
     void decrementRefcount(SkBitmap* resource);
     void decrementRefcount(SkiaShader* resource);
+    void decrementRefcount(SkiaColorFilter* resource);
     void recycle(void* resource);
     void recycle(SkBitmap* resource);
     void destructor(SkBitmap* resource);
-    void destructor(SkMatrix* resource);
-    void destructor(SkPaint* resource);
     void destructor(SkiaShader* resource);
+    void destructor(SkiaColorFilter* resource);
 private:
     void deleteResourceReference(void* resource, ResourceReference* ref);
     void incrementRefcount(void* resource, ResourceType resourceType);
diff --git a/libs/hwui/SkiaColorFilter.cpp b/libs/hwui/SkiaColorFilter.cpp
index fe57ae7..91b1c32 100644
--- a/libs/hwui/SkiaColorFilter.cpp
+++ b/libs/hwui/SkiaColorFilter.cpp
@@ -23,7 +23,8 @@
 // Base color filter
 ///////////////////////////////////////////////////////////////////////////////
 
-SkiaColorFilter::SkiaColorFilter(Type type, bool blend): mType(type), mBlend(blend) {
+SkiaColorFilter::SkiaColorFilter(SkColorFilter *skFilter, Type type, bool blend):
+        mType(type), mBlend(blend), mSkFilter(skFilter) {
 }
 
 SkiaColorFilter::~SkiaColorFilter() {
@@ -33,8 +34,8 @@
 // Color matrix filter
 ///////////////////////////////////////////////////////////////////////////////
 
-SkiaColorMatrixFilter::SkiaColorMatrixFilter(float* matrix, float* vector):
-        SkiaColorFilter(kColorMatrix, true), mMatrix(matrix), mVector(vector) {
+SkiaColorMatrixFilter::SkiaColorMatrixFilter(SkColorFilter *skFilter, float* matrix, float* vector):
+        SkiaColorFilter(skFilter, kColorMatrix, true), mMatrix(matrix), mVector(vector) {
 }
 
 SkiaColorMatrixFilter::~SkiaColorMatrixFilter() {
@@ -56,8 +57,8 @@
 // Lighting color filter
 ///////////////////////////////////////////////////////////////////////////////
 
-SkiaLightingFilter::SkiaLightingFilter(int multiply, int add):
-        SkiaColorFilter(kLighting, true) {
+SkiaLightingFilter::SkiaLightingFilter(SkColorFilter *skFilter, int multiply, int add):
+        SkiaColorFilter(skFilter, kLighting, true) {
     mMulR = ((multiply >> 16) & 0xFF) / 255.0f;
     mMulG = ((multiply >>  8) & 0xFF) / 255.0f;
     mMulB = ((multiply      ) & 0xFF) / 255.0f;
@@ -80,8 +81,8 @@
 // Blend color filter
 ///////////////////////////////////////////////////////////////////////////////
 
-SkiaBlendFilter::SkiaBlendFilter(int color, SkXfermode::Mode mode):
-        SkiaColorFilter(kBlend, true), mMode(mode) {
+SkiaBlendFilter::SkiaBlendFilter(SkColorFilter *skFilter, int color, SkXfermode::Mode mode):
+        SkiaColorFilter(skFilter, kBlend, true), mMode(mode) {
     const int alpha = (color >> 24) & 0xFF;
     mA = alpha / 255.0f;
     mR = mA * ((color >> 16) & 0xFF) / 255.0f;
diff --git a/libs/hwui/SkiaColorFilter.h b/libs/hwui/SkiaColorFilter.h
index 865b6f0..17f49f9 100644
--- a/libs/hwui/SkiaColorFilter.h
+++ b/libs/hwui/SkiaColorFilter.h
@@ -18,6 +18,7 @@
 #define ANDROID_UI_SKIA_COLOR_FILTER_H
 
 #include <GLES2/gl2.h>
+#include <SkColorFilter.h>
 
 #include "ProgramCache.h"
 #include "Extensions.h"
@@ -44,7 +45,7 @@
         kBlend,
     };
 
-    SkiaColorFilter(Type type, bool blend);
+    SkiaColorFilter(SkColorFilter *skFilter, Type type, bool blend);
     virtual ~SkiaColorFilter();
 
     virtual void describe(ProgramDescription& description, const Extensions& extensions) = 0;
@@ -58,9 +59,16 @@
         return mType;
     }
 
+    SkColorFilter *getSkColorFilter() {
+        return mSkFilter;
+    }
+
 protected:
     Type mType;
     bool mBlend;
+
+private:
+    SkColorFilter *mSkFilter;
 }; // struct SkiaColorFilter
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -71,7 +79,7 @@
  * A color filter that multiplies the source color with a matrix and adds a vector.
  */
 struct SkiaColorMatrixFilter: public SkiaColorFilter {
-    SkiaColorMatrixFilter(float* matrix, float* vector);
+    SkiaColorMatrixFilter(SkColorFilter *skFilter, float* matrix, float* vector);
     ~SkiaColorMatrixFilter();
 
     void describe(ProgramDescription& description, const Extensions& extensions);
@@ -87,7 +95,7 @@
  * another fixed value. Ignores the alpha channel of both arguments.
  */
 struct SkiaLightingFilter: public SkiaColorFilter {
-    SkiaLightingFilter(int multiply, int add);
+    SkiaLightingFilter(SkColorFilter *skFilter, int multiply, int add);
 
     void describe(ProgramDescription& description, const Extensions& extensions);
     void setupProgram(Program* program);
@@ -102,7 +110,7 @@
  * and PorterDuff blending mode.
  */
 struct SkiaBlendFilter: public SkiaColorFilter {
-    SkiaBlendFilter(int color, SkXfermode::Mode mode);
+    SkiaBlendFilter(SkColorFilter *skFilter, int color, SkXfermode::Mode mode);
 
     void describe(ProgramDescription& description, const Extensions& extensions);
     void setupProgram(Program* program);
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index fa85d20..e7e1187 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -63,11 +63,17 @@
         GLuint* textureUnit) {
 }
 
-void SkiaShader::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) {
+void SkiaShader::bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) {
     glActiveTexture(gTextureUnitsMap[textureUnit]);
-    glBindTexture(GL_TEXTURE_2D, texture);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
+    glBindTexture(GL_TEXTURE_2D, texture->id);
+    if (wrapS != texture->wrapS) {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
+        texture->wrapS = wrapS;
+    }
+    if (wrapT != texture->wrapT) {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
+        texture->wrapT = wrapT;
+    }
 }
 
 void SkiaShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) {
@@ -86,7 +92,7 @@
 }
 
 void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) {
-    const Texture* texture = mTextureCache->get(mBitmap);
+    Texture* texture = mTextureCache->get(mBitmap);
     if (!texture) return;
     mTexture = texture;
 
@@ -114,7 +120,7 @@
     GLuint textureSlot = (*textureUnit)++;
     glActiveTexture(gTextureUnitsMap[textureSlot]);
 
-    const Texture* texture = mTexture;
+    Texture* texture = mTexture;
     mTexture = NULL;
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
@@ -126,7 +132,7 @@
     computeScreenSpaceMatrix(textureTransform, modelView);
 
     // Uniforms
-    bindTexture(texture->id, mWrapS, mWrapT, textureSlot);
+    bindTexture(texture, mWrapS, mWrapT, textureSlot);
     glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
     glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
             GL_FALSE, &textureTransform.data[0]);
@@ -198,7 +204,7 @@
     computeScreenSpaceMatrix(screenSpace, modelView);
 
     // Uniforms
-    bindTexture(texture->id, gTileModes[mTileX], gTileModes[mTileY], textureSlot);
+    bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY], textureSlot);
     glUniform1i(program->getUniform("gradientSampler"), textureSlot);
     glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
 }
@@ -291,7 +297,7 @@
     computeScreenSpaceMatrix(screenSpace, modelView);
 
     // Uniforms
-    bindTexture(texture->id, gTileModes[mTileX], gTileModes[mTileY], textureSlot);
+    bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY], textureSlot);
     glUniform1i(program->getUniform("gradientSampler"), textureSlot);
     glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
 }
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index 011991a..4cd1b8b 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -97,7 +97,7 @@
     void computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView);
 
 protected:
-    inline void bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit);
+    inline void bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit);
 
     Type mType;
     SkShader* mKey;
@@ -138,7 +138,7 @@
     }
 
     SkBitmap* mBitmap;
-    const Texture* mTexture;
+    Texture* mTexture;
     GLenum mWrapS;
     GLenum mWrapT;
 }; // struct SkiaBitmapShader
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index 817f143..755074d 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -29,6 +29,8 @@
     Texture() {
         cleanup = false;
         bitmapSize = 0;
+        wrapS = GL_CLAMP_TO_EDGE;
+        wrapT = GL_CLAMP_TO_EDGE;
     }
 
     /**
@@ -59,6 +61,12 @@
      * Optional, size of the original bitmap.
      */
     uint32_t bitmapSize;
+
+    /**
+     * Last wrap modes set on this texture. Defaults to GL_CLAMP_TO_EDGE.
+     */
+    GLenum wrapS;
+    GLenum wrapT;
 }; // struct Texture
 
 class AutoTexture {
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 701df83..d860953 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -94,6 +94,8 @@
     // This will be called already locked
     if (texture) {
         mSize -= texture->bitmapSize;
+        TEXTURE_LOGD("TextureCache::callback: removed size, mSize = %d, %d",
+                texture->bitmapSize, mSize);
         glDeleteTextures(1, &texture->id);
         delete texture;
     }
@@ -131,6 +133,8 @@
         if (size < mMaxSize) {
             mLock.lock();
             mSize += size;
+            TEXTURE_LOGD("TextureCache::get: create texture(0x%p): size, mSize = %d, %d",
+                     bitmap, size, mSize);
             mCache.put(bitmap, texture);
             mLock.unlock();
         } else {
@@ -151,6 +155,7 @@
 void TextureCache::clear() {
     Mutex::Autolock _l(mLock);
     mCache.clear();
+    TEXTURE_LOGD("TextureCache:clear(), miSize = %d", mSize);
 }
 
 void TextureCache::generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate) {
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index 467e851..6718597 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -25,6 +25,20 @@
 namespace android {
 namespace uirenderer {
 
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+// Debug
+#define DEBUG_TEXTURES 0
+
+// Debug
+#if DEBUG_TEXTURES
+    #define TEXTURE_LOGD(...) LOGD(__VA_ARGS__)
+#else
+    #define TEXTURE_LOGD(...)
+#endif
+
 /**
  * A simple LRU texture cache. The cache has a maximum size expressed in bytes.
  * Any texture added to the cache causing the cache to grow beyond the maximum
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index 0994980..7af6ce8 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -867,7 +867,18 @@
         return BAD_VALUE;
 
     Mutex::Autolock _l(mSurfaceLock);
+    if (mConnected == NATIVE_WINDOW_API_EGL) {
+        return INVALID_OPERATION;
+    }
+
     mBufferInfo.set(w, h, format);
+    if (format != 0) {
+        // we update the format of the surface as reported by query().
+        // this is to allow applications to change the format of a surface's
+        // buffer, and have it reflected in EGL; which is needed for
+        // EGLConfig validation.
+        mFormat = format;
+    }
     return NO_ERROR;
 }
 
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 629234b..4c86ebe 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -1163,7 +1163,10 @@
 
         // If the pointer is not currently down, then ignore the event.
         if (! mTempTouchState.down) {
-            LOGI("Dropping event because the pointer is not down.");
+#if DEBUG_INPUT_DISPATCHER_POLICY
+            LOGD("Dropping event because the pointer is not down or we previously "
+                    "dropped the pointer down event.");
+#endif
             injectionResult = INPUT_EVENT_INJECTION_FAILED;
             goto Failed;
         }
@@ -2775,7 +2778,7 @@
         dump.append(INDENT "ActiveConnections:\n");
         for (size_t i = 0; i < mActiveConnections.size(); i++) {
             const Connection* connection = mActiveConnections[i];
-            dump.appendFormat(INDENT2 "%d: '%s', status=%s, outboundQueueLength=%u"
+            dump.appendFormat(INDENT2 "%d: '%s', status=%s, outboundQueueLength=%u, "
                     "inputState.isNeutral=%s\n",
                     i, connection->getInputChannelName(), connection->getStatusLabel(),
                     connection->outboundQueue.count(),
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 68524c3..fcf6510 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -480,16 +480,6 @@
     }
 
     /**
-     * Sets the level of the encoder. Call this before prepare().
-     *
-     * @param encoderLevel the video encoder level.
-     * @hide
-     */
-    public void setVideoEncoderLevel(int encoderLevel) {
-        setParameter(String.format("video-param-encoder-level=%d", encoderLevel));
-    }
-
-    /**
      * Sets the auxiliary time lapse video's resolution and bitrate.
      *
      * The auxiliary video's resolution and bitrate are determined by the CamcorderProfile
diff --git a/media/java/android/media/videoeditor/MediaImageItem.java b/media/java/android/media/videoeditor/MediaImageItem.java
index df3c5fb..d2f3694 100755
--- a/media/java/android/media/videoeditor/MediaImageItem.java
+++ b/media/java/android/media/videoeditor/MediaImageItem.java
@@ -163,7 +163,9 @@
     public void setDuration(long durationMs) {

         mDurationMs = durationMs;

 

-        adjustElementsDuration();

+        adjustTransitions();

+        adjustOverlays();

+        adjustEffects();

     }

 

     /*

diff --git a/media/java/android/media/videoeditor/MediaItem.java b/media/java/android/media/videoeditor/MediaItem.java
index d9c38af..40d3619 100755
--- a/media/java/android/media/videoeditor/MediaItem.java
+++ b/media/java/android/media/videoeditor/MediaItem.java
@@ -40,13 +40,21 @@
      * clip are rendered black.

      */

     public static final int RENDERING_MODE_BLACK_BORDER = 0;

+

     /**

      * When using the RENDERING_MODE_STRETCH rendering mode video frames are

      * stretched horizontally or vertically to match the current aspect ratio of

-     * the movie.

+     * the video editor.

      */

     public static final int RENDERING_MODE_STRETCH = 1;

 

+    /**

+     * When using the RENDERING_MODE_CROPPING rendering mode video frames are

+     * scaled horizontally or vertically by preserving the original aspect

+     * ratio of the media item.

+     */

+    public static final int RENDERING_MODE_CROPPING = 2;

+

 

     // The unique id of the MediaItem

     private final String mUniqueId;

@@ -476,10 +484,9 @@
     }

 

     /**

-     * Adjust the duration of effects, overlays and transitions.

-     * This method will be called after a media item duration is changed.

+     * Adjust the duration transitions.

      */

-    protected void adjustElementsDuration() {

+    protected void adjustTransitions() {

         // Check if the duration of transitions need to be adjusted

         if (mBeginTransition != null) {

             final long maxDurationMs = mBeginTransition.getMaximumDuration();

@@ -494,31 +501,12 @@
                 mEndTransition.setDuration(maxDurationMs);

             }

         }

+    }

 

-        final List<Overlay> overlays = getAllOverlays();

-        for (Overlay overlay : overlays) {

-            // Adjust the start time if necessary

-            final long overlayStartTimeMs;

-            if (overlay.getStartTime() > getTimelineDuration()) {

-                overlayStartTimeMs = 0;

-            } else {

-                overlayStartTimeMs = overlay.getStartTime();

-            }

-

-            // Adjust the duration if necessary

-            final long overlayDurationMs;

-            if (overlayStartTimeMs + overlay.getDuration() > getTimelineDuration()) {

-                overlayDurationMs = getTimelineDuration() - overlayStartTimeMs;

-            } else {

-                overlayDurationMs = overlay.getDuration();

-            }

-

-            if (overlayStartTimeMs != overlay.getStartTime() ||

-                    overlayDurationMs != overlay.getDuration()) {

-                overlay.setStartTimeAndDuration(overlayStartTimeMs, overlayDurationMs);

-            }

-        }

-

+    /**

+     * Adjust the start time and/or duration of effects.

+     */

+    protected void adjustEffects() {

         final List<Effect> effects = getAllEffects();

         for (Effect effect : effects) {

             // Adjust the start time if necessary

@@ -543,4 +531,33 @@
             }

         }

     }

+

+    /**

+     * Adjust the start time and/or duration of overlays.

+     */

+    protected void adjustOverlays() {

+        final List<Overlay> overlays = getAllOverlays();

+        for (Overlay overlay : overlays) {

+            // Adjust the start time if necessary

+            final long overlayStartTimeMs;

+            if (overlay.getStartTime() > getTimelineDuration()) {

+                overlayStartTimeMs = 0;

+            } else {

+                overlayStartTimeMs = overlay.getStartTime();

+            }

+

+            // Adjust the duration if necessary

+            final long overlayDurationMs;

+            if (overlayStartTimeMs + overlay.getDuration() > getTimelineDuration()) {

+                overlayDurationMs = getTimelineDuration() - overlayStartTimeMs;

+            } else {

+                overlayDurationMs = overlay.getDuration();

+            }

+

+            if (overlayStartTimeMs != overlay.getStartTime() ||

+                    overlayDurationMs != overlay.getDuration()) {

+                overlay.setStartTimeAndDuration(overlayStartTimeMs, overlayDurationMs);

+            }

+        }

+    }

 }

diff --git a/media/java/android/media/videoeditor/MediaVideoItem.java b/media/java/android/media/videoeditor/MediaVideoItem.java
index f71f4f4..341bf8e 100755
--- a/media/java/android/media/videoeditor/MediaVideoItem.java
+++ b/media/java/android/media/videoeditor/MediaVideoItem.java
@@ -155,7 +155,11 @@
         mBeginBoundaryTimeMs = beginMs;

         mEndBoundaryTimeMs = endMs;

 

-        adjustElementsDuration();

+        adjustTransitions();

+

+        // Note that the start and duration of any effects and overlays are

+        // not adjusted nor are they automatically removed if they fall

+        // outside the new boundaries.

     }

 

     /**

diff --git a/media/java/android/media/videoeditor/VideoEditorTestImpl.java b/media/java/android/media/videoeditor/VideoEditorTestImpl.java
index f4842b5..505b93e 100644
--- a/media/java/android/media/videoeditor/VideoEditorTestImpl.java
+++ b/media/java/android/media/videoeditor/VideoEditorTestImpl.java
@@ -1155,12 +1155,18 @@
     private void removeAdjacentTransitions(MediaItem mediaItem) {
         final Transition beginTransition = mediaItem.getBeginTransition();
         if (beginTransition != null) {
+            if (beginTransition.getAfterMediaItem() != null) {
+                beginTransition.getAfterMediaItem().setEndTransition(null);
+            }
             beginTransition.invalidate();
             mTransitions.remove(beginTransition);
         }
 
         final Transition endTransition = mediaItem.getEndTransition();
         if (endTransition != null) {
+            if (endTransition.getBeforeMediaItem() != null) {
+                endTransition.getBeforeMediaItem().setBeginTransition(null);
+            }
             endTransition.invalidate();
             mTransitions.remove(endTransition);
         }
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index be23c60..ea5577d 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -105,7 +105,7 @@
     RegisterSniffer(SniffAMR);
     RegisterSniffer(SniffMPEG2TS);
     RegisterSniffer(SniffMP3);
-    RegisterSniffer(SniffDRM);
+    //RegisterSniffer(SniffDRM);
 }
 
 // static
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 2e368b6..0d8abe2 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -156,19 +156,15 @@
 //    { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.Nvidia.mp3.decoder" },
 //    { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
     { MEDIA_MIMETYPE_AUDIO_MPEG, "MP3Decoder" },
-//    { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.PV.mp3dec" },
 //    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" },
 //    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.Nvidia.amr.decoder" },
     { MEDIA_MIMETYPE_AUDIO_AMR_NB, "AMRNBDecoder" },
-//    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrdec" },
 //    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.Nvidia.amrwb.decoder" },
     { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" },
     { MEDIA_MIMETYPE_AUDIO_AMR_WB, "AMRWBDecoder" },
-//    { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.PV.amrdec" },
 //    { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.Nvidia.aac.decoder" },
     { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" },
     { MEDIA_MIMETYPE_AUDIO_AAC, "AACDecoder" },
-//    { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacdec" },
     { MEDIA_MIMETYPE_AUDIO_G711_ALAW, "G711Decoder" },
     { MEDIA_MIMETYPE_AUDIO_G711_MLAW, "G711Decoder" },
 //    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.Nvidia.mp4.decode" },
@@ -177,20 +173,17 @@
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.SEC.MPEG4.Decoder" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "M4vH263Decoder" },
-//    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4dec" },
 //    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.Nvidia.h263.decode" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.7x30.video.decoder.h263" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.decoder.h263" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.SEC.H263.Decoder" },
     { MEDIA_MIMETYPE_VIDEO_H263, "M4vH263Decoder" },
-//    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263dec" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.Nvidia.h264.decode" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.decoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.decoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.Decoder" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.SEC.AVC.Decoder" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "AVCDecoder" },
-//    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcdec" },
     { MEDIA_MIMETYPE_AUDIO_VORBIS, "VorbisDecoder" },
     { MEDIA_MIMETYPE_VIDEO_VPX, "VPXDecoder" },
 };
@@ -202,28 +195,24 @@
     { MEDIA_MIMETYPE_AUDIO_AMR_WB, "AMRWBEncoder" },
     { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.encode" },
     { MEDIA_MIMETYPE_AUDIO_AAC, "AACEncoder" },
-//    { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacenc" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.encoder.mpeg4" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.encoder.mpeg4" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.encoder" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.Nvidia.mp4.encoder" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.SEC.MPEG4.Encoder" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "M4vH263Encoder" },
-//    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4enc" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.7x30.video.encoder.h263" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.encoder" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.Nvidia.h263.encoder" },
     { MEDIA_MIMETYPE_VIDEO_H263, "OMX.SEC.H263.Encoder" },
     { MEDIA_MIMETYPE_VIDEO_H263, "M4vH263Encoder" },
-//    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263enc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.encoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.encoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.Nvidia.h264.encoder" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.SEC.AVC.Encoder" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "AVCEncoder" },
-//    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
 };
 
 #undef OPTIONAL
@@ -318,16 +307,15 @@
 }
 
 static bool IsSoftwareCodec(const char *componentName) {
-    if (!strncmp("OMX.PV.", componentName, 7)) {
-        return true;
+    if (!strncmp("OMX.", componentName, 4)) {
+        return false;
     }
 
-    return false;
+    return true;
 }
 
 // A sort order in which non-OMX components are first,
-// followed by software codecs, i.e. OMX.PV.*, followed
-// by all the others.
+// followed by software codecs, and followed by all the others.
 static int CompareSoftwareCodecsFirst(
         const String8 *elem1, const String8 *elem2) {
     bool isNotOMX1 = strncmp(elem1->string(), "OMX.", 4);
@@ -368,9 +356,6 @@
         quirks |= kDecoderLiesAboutNumberOfChannels;
     }
 
-    if (!strcmp(componentName, "OMX.PV.avcdec")) {
-        quirks |= kWantsNALFragments;
-    }
     if (!strcmp(componentName, "OMX.TI.MP3.decode")) {
         quirks |= kNeedsFlushBeforeDisable;
         quirks |= kDecoderLiesAboutNumberOfChannels;
@@ -465,7 +450,16 @@
             continue;
         }
 
-        matchingCodecs->push(String8(componentName));
+        // When requesting software-only codecs, only push software codecs
+        // When requesting hardware-only codecs, only push hardware codecs
+        // When there is request neither for software-only nor for
+        // hardware-only codecs, push all codecs
+        if (((flags & kSoftwareCodecsOnly) &&   IsSoftwareCodec(componentName)) ||
+            ((flags & kHardwareCodecsOnly) &&  !IsSoftwareCodec(componentName)) ||
+            (!(flags & (kSoftwareCodecsOnly | kHardwareCodecsOnly)))) {
+
+            matchingCodecs->push(String8(componentName));
+        }
     }
 
     if (flags & kPreferSoftwareCodecs) {
@@ -3881,17 +3875,8 @@
                 CHECK(!"Unknown compression format.");
             }
 
-            if (!strcmp(mComponentName, "OMX.PV.avcdec")) {
-                // This component appears to be lying to me.
-                mOutputFormat->setInt32(
-                        kKeyWidth, (video_def->nFrameWidth + 15) & -16);
-                mOutputFormat->setInt32(
-                        kKeyHeight, (video_def->nFrameHeight + 15) & -16);
-            } else {
-                mOutputFormat->setInt32(kKeyWidth, video_def->nFrameWidth);
-                mOutputFormat->setInt32(kKeyHeight, video_def->nFrameHeight);
-            }
-
+            mOutputFormat->setInt32(kKeyWidth, video_def->nFrameWidth);
+            mOutputFormat->setInt32(kKeyHeight, video_def->nFrameHeight);
             mOutputFormat->setInt32(kKeyColorFormat, video_def->eColorFormat);
             break;
         }
diff --git a/native/android/native_window.cpp b/native/android/native_window.cpp
index bada078..7f92eec 100644
--- a/native/android/native_window.cpp
+++ b/native/android/native_window.cpp
@@ -58,8 +58,8 @@
 }
 
 int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width,
-        int32_t height) {
-    native_window_set_buffers_geometry(window, width, height, 0);
+        int32_t height, int32_t format) {
+    native_window_set_buffers_geometry(window, width, height, format);
     return 0;
 }
 
diff --git a/native/include/android/native_window.h b/native/include/android/native_window.h
index ad03d0e..f3d7550 100644
--- a/native/include/android/native_window.h
+++ b/native/include/android/native_window.h
@@ -96,7 +96,7 @@
  * For all of these parameters, if 0 is supplied then the window's base
  * value will come back in force.
  */
-int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, int32_t height);
+int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, int32_t height, int32_t format);
 
 /**
  * Lock the window's next drawing surface for writing.
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 41207f7..c937b06 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -530,7 +530,6 @@
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mGLThread.requestExitAndWait();
     }
 
     // ----------------------------------------------------------------------
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index e38b9cc..e44c485 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -833,6 +833,9 @@
     static bool mask(GLint reqValue, GLint confValue) {
         return (confValue & reqValue) == reqValue;
     }
+    static bool ignore(GLint reqValue, GLint confValue) {
+        return true;
+    }
 };
 
 // ----------------------------------------------------------------------------
@@ -1060,11 +1063,11 @@
         { EGL_CONFIG_CAVEAT,              config_management_t::exact   },
         { EGL_CONFIG_ID,                  config_management_t::exact   },
         { EGL_LEVEL,                      config_management_t::exact   },
-        { EGL_MAX_PBUFFER_HEIGHT,         config_management_t::exact   },
-        { EGL_MAX_PBUFFER_PIXELS,         config_management_t::exact   },
-        { EGL_MAX_PBUFFER_WIDTH,          config_management_t::exact   },
+        { EGL_MAX_PBUFFER_HEIGHT,         config_management_t::ignore   },
+        { EGL_MAX_PBUFFER_PIXELS,         config_management_t::ignore   },
+        { EGL_MAX_PBUFFER_WIDTH,          config_management_t::ignore   },
         { EGL_NATIVE_RENDERABLE,          config_management_t::exact   },
-        { EGL_NATIVE_VISUAL_ID,           config_management_t::exact   },
+        { EGL_NATIVE_VISUAL_ID,           config_management_t::ignore   },
         { EGL_NATIVE_VISUAL_TYPE,         config_management_t::exact   },
         { EGL_SAMPLES,                    config_management_t::exact   },
         { EGL_SAMPLE_BUFFERS,             config_management_t::exact   },
diff --git a/packages/SystemUI/res/drawable-mdpi/sysbar_panel_recents_bg.9.png b/packages/SystemUI/res/drawable-mdpi/sysbar_panel_recents_bg.9.png
new file mode 100644
index 0000000..85726d2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/sysbar_panel_recents_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml
index 429fdf2..dbe4167 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml
@@ -146,7 +146,7 @@
                 android:background="@drawable/ic_sysbar_icon_bg"
                 systemui:keyCode="3"
                 />
-            <ImageButton android:id="@+id/recent"
+            <ImageButton android:id="@+id/recent_apps"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_recent"
diff --git a/packages/SystemUI/res/layout-xlarge/sysbar_panel_recent.xml b/packages/SystemUI/res/layout-xlarge/sysbar_panel_recent.xml
new file mode 100644
index 0000000..2f9e0d7
--- /dev/null
+++ b/packages/SystemUI/res/layout-xlarge/sysbar_panel_recent.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2010, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<com.android.systemui.statusbar.tablet.RecentAppsPanel
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="wrap_content"
+    android:layout_width="wrap_content"
+    android:background="@drawable/sysbar_panel_recents_bg"
+    android:orientation="vertical">
+
+    <TextView android:id="@+id/recents_no_recents"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:text="@string/recent_tasks_empty"
+        android:gravity="center_horizontal|center_vertical"
+        android:visibility="gone">
+    </TextView>
+
+    <HorizontalScrollView android:id="@+id/scroll_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <LinearLayout android:id="@+id/recents_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="right"
+            android:orientation="horizontal"
+        />
+
+    </HorizontalScrollView>
+
+</com.android.systemui.statusbar.tablet.RecentAppsPanel>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
new file mode 100644
index 0000000..6797958
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.tablet;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.ActivityManager;
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.media.AudioManager;
+import android.net.wifi.WifiManager;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.widget.BaseAdapter;
+import android.widget.Gallery;
+import android.widget.HorizontalScrollView;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.systemui.R;
+
+public class RecentAppsPanel extends LinearLayout implements StatusBarPanel, OnClickListener {
+    private static final String TAG = "RecentAppsPanel";
+    private static final boolean DEBUG = TabletStatusBarService.DEBUG;
+    private static final int MAX_RECENT_TASKS = 20;
+    private static final float ITEM_WIDTH = 75;
+    private static final float ITEM_HEIGHT = 75;
+    private TabletStatusBarService mBar;
+    private TextView mNoRecents;
+    private LinearLayout mRecentsContainer;
+    private float mDensity;
+    private HorizontalScrollView mScrollView;
+
+    public boolean isInContentArea(int x, int y) {
+        final int l = getPaddingLeft();
+        final int r = getWidth() - getPaddingRight();
+        final int t = getPaddingTop();
+        final int b = getHeight() - getPaddingBottom();
+        return x >= l && x < r && y >= t && y < b;
+    }
+
+    public void setBar(TabletStatusBarService bar) {
+        mBar = bar;
+    }
+
+    public RecentAppsPanel(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public RecentAppsPanel(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        mDensity = getResources().getDisplayMetrics().density;
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mNoRecents = (TextView) findViewById(R.id.recents_no_recents);
+        mRecentsContainer = (LinearLayout) findViewById(R.id.recents_container);
+        mScrollView = (HorizontalScrollView) findViewById(R.id.scroll_view);
+        mScrollView.setHorizontalFadingEdgeEnabled(true);
+    }
+
+    @Override
+    protected void onVisibilityChanged(View changedView, int visibility) {
+        super.onVisibilityChanged(changedView, visibility);
+        Log.v(TAG, "onVisibilityChanged(" + changedView + ", " + visibility + ")");
+        if (visibility == View.VISIBLE && changedView == this) {
+            refreshIcons();
+            mRecentsContainer.setScrollbarFadingEnabled(true);
+            mRecentsContainer.scrollTo(0, 0);
+        }
+    }
+
+    private void refreshIcons() {
+        mRecentsContainer.removeAllViews();
+        final Context context = getContext();
+        final PackageManager pm = context.getPackageManager();
+        final ActivityManager am = (ActivityManager)
+                context.getSystemService(Context.ACTIVITY_SERVICE);
+        final List<ActivityManager.RecentTaskInfo> recentTasks =
+                am.getRecentTasks(MAX_RECENT_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
+
+        ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN)
+                .addCategory(Intent.CATEGORY_HOME)
+                .resolveActivityInfo(pm, 0);
+
+        int numTasks = recentTasks.size();
+        final int width = (int) (mDensity * ITEM_WIDTH + 0.5f);
+        final int height = (int) (mDensity * ITEM_HEIGHT + 0.5f);
+        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(width, height);
+        for (int i = 0; i < numTasks; ++i) {
+            final ActivityManager.RecentTaskInfo info = recentTasks.get(i);
+
+            Intent intent = new Intent(info.baseIntent);
+            if (info.origActivity != null) {
+                intent.setComponent(info.origActivity);
+            }
+
+            // Exclude home activity.
+            if (homeInfo != null
+                    && homeInfo.packageName.equals(intent.getComponent().getPackageName())
+                    && homeInfo.name.equals(intent.getComponent().getClassName())) {
+                    continue;
+            }
+
+            intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
+                    | Intent.FLAG_ACTIVITY_NEW_TASK);
+            final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
+            if (resolveInfo != null) {
+                final ActivityInfo activityInfo = resolveInfo.activityInfo;
+                final String title = activityInfo.loadLabel(pm).toString();
+                Drawable icon = activityInfo.loadIcon(pm);
+
+                if (title != null && title.length() > 0 && icon != null) {
+                    ImageView imageView = new ImageView(mContext);
+                    imageView.setScaleType(ImageView.ScaleType.FIT_XY);
+                    imageView.setLayoutParams(layoutParams);
+                    imageView.setOnClickListener(this);
+                    imageView.setTag(intent);
+                    imageView.setImageDrawable(icon);
+                    mRecentsContainer.addView(imageView);
+                }
+            }
+        }
+
+        int views = mRecentsContainer.getChildCount();
+        mNoRecents.setVisibility(views == 0 ? View.VISIBLE : View.GONE);
+        mRecentsContainer.setVisibility(views > 0 ? View.VISIBLE : View.GONE);
+    }
+
+    public void onClick(View v) {
+        Intent intent = (Intent) v.getTag();
+        if (DEBUG) Log.v(TAG, "Starting activity " + intent);
+        getContext().startActivity(intent);
+        mBar.animateCollapse();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
index 10b52f2..7ee3c19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
@@ -116,7 +116,7 @@
         mClipping = clipping;
         if (mClipping != null) {
             Bitmap icon = mClipping.getIcon();
-            mDescription.setText(mClipping.getLabel());
+            mDescription.setText(mClipping.getDescription().getLabel());
             if (icon != null) {
                 mPreviewIcon.setImageBitmap(icon);
                 mPreviewIcon.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
index 9fb29ac..fff70bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java
@@ -67,8 +67,11 @@
     public static final int MSG_CLOSE_NOTIFICATION_PANEL = 1001;
     public static final int MSG_OPEN_SYSTEM_PANEL = 1010;
     public static final int MSG_CLOSE_SYSTEM_PANEL = 1011;
-    
+    public static final int MSG_OPEN_RECENTS_PANEL = 1020;
+    public static final int MSG_CLOSE_RECENTS_PANEL = 1021;
+
     private static final int MAX_IMAGE_LEVEL = 10000;
+    private static final boolean USE_2D_RECENTS = true;
 
     int mIconSize;
 
@@ -76,7 +79,7 @@
 
     // tracking all current notifications
     private NotificationData mNotns = new NotificationData();
-    
+
     TabletStatusBarView mStatusBarView;
     ImageView mNotificationTrigger;
     NotificationIconArea mNotificationIconArea;
@@ -110,6 +113,7 @@
     int mDisabled = 0;
 
     boolean mNotificationsOn = true;
+    private RecentAppsPanel mRecentsPanel;
 
     protected void addPanelWindows() {
         final Context context = mContext;
@@ -118,6 +122,7 @@
         final int barHeight= res.getDimensionPixelSize(
             com.android.internal.R.dimen.status_bar_height);
 
+        // Notification Panel
         mNotificationPanel = (NotificationPanel)View.inflate(context,
                 R.layout.sysbar_panel_notifications, null);
         mNotificationPanel.setVisibility(View.GONE);
@@ -139,11 +144,11 @@
 
         WindowManagerImpl.getDefault().addView(mNotificationPanel, lp);
 
+        // System Panel
         mSystemPanel = (SystemPanel) View.inflate(context, R.layout.sysbar_panel_system, null);
         mSystemPanel.setVisibility(View.GONE);
         mSystemPanel.setOnTouchListener(new TouchOutsideListener(MSG_CLOSE_SYSTEM_PANEL,
-                    mSystemPanel));
-
+                mSystemPanel));
         mStatusBarView.setIgnoreChildren(1, mSystemInfo, mSystemPanel);
 
         lp = new WindowManager.LayoutParams(
@@ -159,6 +164,31 @@
 
         WindowManagerImpl.getDefault().addView(mSystemPanel, lp);
         mSystemPanel.setBar(this);
+
+
+        // Recents Panel
+        if (USE_2D_RECENTS) {
+            mRecentsPanel = (RecentAppsPanel) View.inflate(context, R.layout.sysbar_panel_recent,
+                    null);
+            mRecentsPanel.setVisibility(View.GONE);
+            mRecentsPanel.setOnTouchListener(new TouchOutsideListener(MSG_CLOSE_RECENTS_PANEL,
+                    mRecentsPanel));
+            mStatusBarView.setIgnoreChildren(2, mRecentButton, mRecentsPanel);
+
+            lp = new WindowManager.LayoutParams(
+                    ViewGroup.LayoutParams.WRAP_CONTENT,
+                    ViewGroup.LayoutParams.WRAP_CONTENT,
+                    WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+                    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                        | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+                    PixelFormat.TRANSLUCENT);
+            lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
+            lp.setTitle("RecentsPanel");
+            lp.windowAnimations = com.android.internal.R.style.Animation_SlidingCard;
+
+            WindowManagerImpl.getDefault().addView(mRecentsPanel, lp);
+            mRecentsPanel.setBar(this);
+        }
     }
 
     @Override
@@ -181,12 +211,13 @@
         mBarContents = sb.findViewById(R.id.bar_contents);
         mCurtains = sb.findViewById(R.id.lights_out);
         mSystemInfo = sb.findViewById(R.id.systemInfo);
+        mRecentButton = sb.findViewById(R.id.recent_apps);
 
 //        mSystemInfo.setOnClickListener(mOnClickListener);
         mSystemInfo.setOnLongClickListener(new SetLightsOnListener(false));
         mSystemInfo.setOnTouchListener(new ClockTouchListener());
 
-        mRecentButton = sb.findViewById(R.id.recent);
+        mRecentButton = sb.findViewById(R.id.recent_apps);
         mRecentButton.setOnClickListener(mOnClickListener);
 
         SetLightsOnListener on = new SetLightsOnListener(true);
@@ -231,7 +262,7 @@
 
         mPile = (ViewGroup)mNotificationPanel.findViewById(R.id.content);
         mPile.removeAllViews();
-        
+
         ScrollView scroller = (ScrollView)mPile.getParent();
         scroller.setFillViewport(true);
 
@@ -277,6 +308,13 @@
                 case MSG_CLOSE_SYSTEM_PANEL:
                     if (DEBUG) Slog.d(TAG, "closing system panel");
                     mSystemPanel.setVisibility(View.GONE);
+                case MSG_OPEN_RECENTS_PANEL:
+                    if (DEBUG) Slog.d(TAG, "opening recents panel");
+                    if (mRecentsPanel != null) mRecentsPanel.setVisibility(View.VISIBLE);
+                    break;
+                case MSG_CLOSE_RECENTS_PANEL:
+                    if (DEBUG) Slog.d(TAG, "closing recents panel");
+                    if (mRecentsPanel != null) mRecentsPanel.setVisibility(View.GONE);
                     break;
             }
         }
@@ -315,7 +353,7 @@
             mSignalMeter.setImageResource(R.drawable.sysbar_wifimini);
             // adjust to permyriad
             mSignalMeter.setImageLevel(level * (MAX_IMAGE_LEVEL / 100));
-            mSignalIcon.setImageResource(isWifi ? R.drawable.ic_sysbar_wifi_mini 
+            mSignalIcon.setImageResource(isWifi ? R.drawable.ic_sysbar_wifi_mini
                                                 : R.drawable.ic_sysbar_wifi_mini); // XXX
         }
     }
@@ -362,7 +400,7 @@
 
     public void updateNotification(IBinder key, StatusBarNotification notification) {
         if (DEBUG) Slog.d(TAG, "updateNotification(" + key + " -> " + notification + ") // TODO");
-        
+
         final NotificationData.Entry oldEntry = mNotns.findByKey(key);
         if (oldEntry == null) {
             Slog.w(TAG, "updateNotification for unknown key: " + key);
@@ -527,6 +565,8 @@
         mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PANEL);
         mHandler.removeMessages(MSG_CLOSE_SYSTEM_PANEL);
         mHandler.sendEmptyMessage(MSG_CLOSE_SYSTEM_PANEL);
+        mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
+        mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
     }
 
     public void setLightsOn(boolean on) {
@@ -608,7 +648,6 @@
                     if (mVT == null) break;
                     mVT.addMovement(event);
                     mVT.computeCurrentVelocity(1000);
-                    Slog.d("ClockTouchListener", "dy=" + mVT.getYVelocity());
                     if (mVT.getYVelocity() < -200 && mSystemPanel.getVisibility() == View.GONE) {
                         mHandler.removeMessages(MSG_OPEN_SYSTEM_PANEL);
                         mHandler.sendEmptyMessage(MSG_OPEN_SYSTEM_PANEL);
@@ -665,7 +704,7 @@
                 mIconLayout.setVisibility(View.VISIBLE); // TODO: animation
                 refreshNotificationTrigger();
             } else {
-                int msg = (mNotificationPanel.getVisibility() == View.GONE) 
+                int msg = (mNotificationPanel.getVisibility() == View.GONE)
                     ? MSG_OPEN_NOTIFICATION_PANEL
                     : MSG_CLOSE_NOTIFICATION_PANEL;
                 mHandler.removeMessages(msg);
@@ -677,7 +716,7 @@
     public void onClickSystemInfo() {
         if (DEBUG) Slog.d(TAG, "clicked system info");
         if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
-            int msg = (mSystemPanel.getVisibility() == View.GONE) 
+            int msg = (mSystemPanel.getVisibility() == View.GONE)
                 ? MSG_OPEN_SYSTEM_PANEL
                 : MSG_CLOSE_SYSTEM_PANEL;
             mHandler.removeMessages(msg);
@@ -687,11 +726,21 @@
 
     public void onClickRecentButton() {
         if (DEBUG) Slog.d(TAG, "clicked recent apps");
-        Intent intent = new Intent();
-        intent.setClass(mContext, RecentApplicationsActivity.class);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-        mContext.startActivity(intent);
+        if (mRecentsPanel == null) {
+            Intent intent = new Intent();
+            intent.setClass(mContext, RecentApplicationsActivity.class);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+            mContext.startActivity(intent);
+        } else {
+            if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
+                int msg = (mRecentsPanel.getVisibility() == View.GONE)
+                    ? MSG_OPEN_RECENTS_PANEL
+                    : MSG_CLOSE_RECENTS_PANEL;
+                mHandler.removeMessages(msg);
+                mHandler.sendEmptyMessage(msg);
+            }
+        }
     }
 
     private class NotificationClicker implements View.OnClickListener {
@@ -835,7 +884,7 @@
             final String _pkg = sbn.pkg;
             final String _tag = sbn.tag;
             final int _id = sbn.id;
-            vetoButton.setOnClickListener(new View.OnClickListener() { 
+            vetoButton.setOnClickListener(new View.OnClickListener() {
                     public void onClick(View v) {
                         try {
                             mBarService.onNotificationClear(_pkg, _tag, _id);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
index d836e4a..15866fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarView.java
@@ -26,8 +26,8 @@
 public class TabletStatusBarView extends FrameLayout {
     private Handler mHandler;
 
-    private View[] mIgnoreChildren = new View[2];
-    private View[] mPanels = new View[2];
+    private View[] mIgnoreChildren = new View[3];
+    private View[] mPanels = new View[3];
     private int[] mPos = new int[2];
 
     public TabletStatusBarView(Context context) {
@@ -44,9 +44,11 @@
             mHandler.sendEmptyMessage(TabletStatusBarService.MSG_CLOSE_NOTIFICATION_PANEL);
             mHandler.removeMessages(TabletStatusBarService.MSG_CLOSE_SYSTEM_PANEL);
             mHandler.sendEmptyMessage(TabletStatusBarService.MSG_CLOSE_SYSTEM_PANEL);
+            mHandler.removeMessages(TabletStatusBarService.MSG_CLOSE_RECENTS_PANEL);
+            mHandler.sendEmptyMessage(TabletStatusBarService.MSG_CLOSE_RECENTS_PANEL);
 
-            for (int i=0; i<mPanels.length; i++) {
-                if (mPanels[i].getVisibility() == View.VISIBLE) {
+            for (int i=0; i < mPanels.length; i++) {
+                if (mPanels[i] != null && mPanels[i].getVisibility() == View.VISIBLE) {
                     if (eventInside(mIgnoreChildren[i], ev)) {
                         return true;
                     }
diff --git a/services/java/com/android/server/ClipboardService.java b/services/java/com/android/server/ClipboardService.java
index bdf313c..30ea48c 100644
--- a/services/java/com/android/server/ClipboardService.java
+++ b/services/java/com/android/server/ClipboardService.java
@@ -115,7 +115,7 @@
 
     public ClipDescription getPrimaryClipDescription() {
         synchronized (this) {
-            return new ClipDescription(mPrimaryClip);
+            return mPrimaryClip.getDescription();
         }
     }
 
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index e59cc8c..656ec4d 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -577,15 +577,16 @@
                  || LocationManager.PASSIVE_PROVIDER.equals(provider))
             && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
                 != PackageManager.PERMISSION_GRANTED)) {
-            throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
+            throw new SecurityException("Provider " + provider
+                    + " requires ACCESS_FINE_LOCATION permission");
         }
         if (LocationManager.NETWORK_PROVIDER.equals(provider)
             && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
                 != PackageManager.PERMISSION_GRANTED)
             && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
                 != PackageManager.PERMISSION_GRANTED)) {
-            throw new SecurityException(
-                "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
+            throw new SecurityException("Provider " + provider
+                    + " requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
         }
     }
 
@@ -744,9 +745,9 @@
     private LocationProviderInterface best(List<String> providerNames) {
         ArrayList<LocationProviderInterface> providers;
         synchronized (mLock) {
-            providers = new ArrayList<LocationProviderInterface>(mProviders.size());
-            for (int i = mProviders.size() - 1; i >= 0; i--) {
-                providers.add(mProviders.get(i));
+            providers = new ArrayList<LocationProviderInterface>(providerNames.size());
+            for (String name : providerNames) {
+                providers.add(mProvidersByName.get(name));
             }
         }
 
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index b3e9f9d..30e90a8 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -2354,6 +2354,14 @@
             Slog.d(TAG, "lightSensorChangedLocked " + value);
         }
 
+        // Don't do anything if the screen is off.
+        if ((mPowerState & SCREEN_ON_BIT) == 0) {
+            if (mDebugLightSensor) {
+                Slog.d(TAG, "dropping lightSensorChangedLocked because screen is off");
+            }
+            return;
+        }
+
         // do not allow light sensor value to decrease
         if (mHighestLightSensorValue < value) {
             mHighestLightSensorValue = value;
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 4f75366..210fe8a 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -102,6 +102,8 @@
 
     private final LockList mLocks = new LockList();
     // some wifi lock statistics
+    private int mFullHighPerfLocksAcquired;
+    private int mFullHighPerfLocksReleased;
     private int mFullLocksAcquired;
     private int mFullLocksReleased;
     private int mScanLocksAcquired;
@@ -872,9 +874,19 @@
         mWifiStateMachine.startWpsPbc(bssid);
     }
 
-    public void startWpsPin(String bssid, int apPin) {
+    public void startWpsWithPinFromAccessPoint(String bssid, int apPin) {
         enforceChangePermission();
-        mWifiStateMachine.startWpsPin(bssid, apPin);
+        mWifiStateMachine.startWpsWithPinFromAccessPoint(bssid, apPin);
+    }
+
+    public int startWpsWithPinFromDevice(String bssid) {
+        enforceChangePermission();
+        if (mChannel != null) {
+            return mWifiStateMachine.syncStartWpsWithPinFromDevice(mChannel, bssid);
+        } else {
+            Slog.e(TAG, "mChannel is not initialized");
+            return -1;
+        }
     }
 
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -1030,12 +1042,15 @@
         boolean wifiEnabled = getPersistedWifiEnabled();
         boolean airplaneMode = isAirplaneModeOn() && !mAirplaneModeOverwridden.get();
         boolean lockHeld = mLocks.hasLocks();
-        int strongestLockMode;
+        int strongestLockMode = WifiManager.WIFI_MODE_FULL;
         boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode;
         boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld;
-        if (mDeviceIdle && lockHeld) {
+
+        if (lockHeld) {
             strongestLockMode = mLocks.getStrongestLockMode();
-        } else {
+        }
+        /* If device is not idle, lockmode cannot be scan only */
+        if (!mDeviceIdle && strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY) {
             strongestLockMode = WifiManager.WIFI_MODE_FULL;
         }
 
@@ -1057,6 +1072,8 @@
                 mWifiStateMachine.setDriverStart(true);
                 mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                         System.currentTimeMillis() + scanMs, scanMs, mScanIntent);
+                mWifiStateMachine.setHighPerfModeEnabled(strongestLockMode
+                        == WifiManager.WIFI_MODE_FULL_HIGH_PERF);
             } else {
                 mWifiStateMachine.requestCmWakeLock();
                 mWifiStateMachine.setDriverStart(false);
@@ -1135,8 +1152,10 @@
         }
         pw.println();
         pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
+                mFullHighPerfLocksAcquired + " full high perf, " +
                 mScanLocksAcquired + " scan");
         pw.println("Locks released: " + mFullLocksReleased + " full, " +
+                mFullHighPerfLocksReleased + " full high perf, " +
                 mScanLocksReleased + " scan");
         pw.println();
         pw.println("Locks held:");
@@ -1174,11 +1193,15 @@
             if (mList.isEmpty()) {
                 return WifiManager.WIFI_MODE_FULL;
             }
-            for (WifiLock l : mList) {
-                if (l.mMode == WifiManager.WIFI_MODE_FULL) {
-                    return WifiManager.WIFI_MODE_FULL;
-                }
+
+            if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
+                return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
             }
+
+            if (mFullLocksAcquired > mFullLocksReleased) {
+                return WifiManager.WIFI_MODE_FULL;
+            }
+
             return WifiManager.WIFI_MODE_SCAN_ONLY;
         }
 
@@ -1225,7 +1248,11 @@
 
     public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
-        if (lockMode != WifiManager.WIFI_MODE_FULL && lockMode != WifiManager.WIFI_MODE_SCAN_ONLY) {
+        if (lockMode != WifiManager.WIFI_MODE_FULL &&
+                lockMode != WifiManager.WIFI_MODE_SCAN_ONLY &&
+                lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
+            Slog.e(TAG, "Illegal argument, lockMode= " + lockMode);
+            if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode);
             return false;
         }
         if (ws != null && ws.size() == 0) {
@@ -1246,6 +1273,7 @@
     private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException {
         switch(wifiLock.mMode) {
             case WifiManager.WIFI_MODE_FULL:
+            case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
                 mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
                 break;
             case WifiManager.WIFI_MODE_SCAN_ONLY:
@@ -1257,6 +1285,7 @@
     private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException {
         switch(wifiLock.mMode) {
             case WifiManager.WIFI_MODE_FULL:
+            case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
                 mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
                 break;
             case WifiManager.WIFI_MODE_SCAN_ONLY:
@@ -1277,6 +1306,10 @@
             case WifiManager.WIFI_MODE_FULL:
                 ++mFullLocksAcquired;
                 break;
+            case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
+                ++mFullHighPerfLocksAcquired;
+                break;
+
             case WifiManager.WIFI_MODE_SCAN_ONLY:
                 ++mScanLocksAcquired;
                 break;
@@ -1346,6 +1379,9 @@
                     case WifiManager.WIFI_MODE_FULL:
                         ++mFullLocksReleased;
                         break;
+                    case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
+                        ++mFullHighPerfLocksReleased;
+                        break;
                     case WifiManager.WIFI_MODE_SCAN_ONLY:
                         ++mScanLocksReleased;
                         break;
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 9bc24d2..c29e4a9 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -569,7 +569,7 @@
         void broadcastDragStartedLw(final float touchX, final float touchY) {
             // Cache a base-class instance of the clip metadata so that parceling
             // works correctly in calling out to the apps.
-            mDataDescription = new ClipDescription(mData);
+            mDataDescription = mData.getDescription();
             mNotifiedWindows.clear();
             mDragInProgress = true;
 
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index f52d322..463493b 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -2139,7 +2139,7 @@
                     // being started, which means not bringing it to the front
                     // if the caller is not itself in the front.
                     ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);
-                    if (curTop.task != taskTop.task) {
+                    if (curTop != null && curTop.task != taskTop.task) {
                         r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
                         boolean callerAtFront = sourceRecord == null
                                 || curTop.task == sourceRecord.task;
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index ab7b601..5f9a3e7 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -380,7 +380,7 @@
                 break;
             case OFFHOOK:
                 Phone fgPhone = getFgPhone();
-                if (!(fgPhone instanceof SipPhone)) {
+                if (hasActiveFgCall() && !(fgPhone instanceof SipPhone)) {
                     mode = AudioManager.MODE_IN_CALL;
                 }
                 break;
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java
index 2db1071..02eaa7c 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java
@@ -51,27 +51,28 @@
         private LinearGradient mHorGradient;
         private LinearGradient mDiagGradient;
         private LinearGradient mVertGradient;
+        private Bitmap mTexture;
 
         ShadersView(Context c) {
             super(c);
 
-            Bitmap texture = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1);
-            mTexWidth = texture.getWidth();
-            mTexHeight = texture.getHeight();
+            mTexture = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1);
+            mTexWidth = mTexture.getWidth();
+            mTexHeight = mTexture.getHeight();
             mDrawWidth = mTexWidth * 2.2f;
             mDrawHeight = mTexHeight * 1.2f;
 
-            mRepeatShader = new BitmapShader(texture, Shader.TileMode.REPEAT,
+            mRepeatShader = new BitmapShader(mTexture, Shader.TileMode.REPEAT,
                     Shader.TileMode.REPEAT);
 
-            mTranslatedShader = new BitmapShader(texture, Shader.TileMode.REPEAT,
+            mTranslatedShader = new BitmapShader(mTexture, Shader.TileMode.REPEAT,
                     Shader.TileMode.REPEAT);
             Matrix m1 = new Matrix();
             m1.setTranslate(mTexWidth / 2.0f, mTexHeight / 2.0f);
             m1.postRotate(45, 0, 0);
             mTranslatedShader.setLocalMatrix(m1);
             
-            mScaledShader = new BitmapShader(texture, Shader.TileMode.MIRROR,
+            mScaledShader = new BitmapShader(mTexture, Shader.TileMode.MIRROR,
                     Shader.TileMode.MIRROR);
             Matrix m2 = new Matrix();
             m2.setScale(0.5f, 0.5f);
@@ -98,6 +99,7 @@
         protected void onDraw(Canvas canvas) {
             super.onDraw(canvas);
             //canvas.drawRGB(255, 255, 255);
+            canvas.drawBitmap(mTexture, 0.0f, 0.0f, null);
 
             // Bitmap shaders
             canvas.save();
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index cee8546..8551b0f 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -203,13 +203,9 @@
                 }
             }
             if (xliffDepth == 0 && pseudolocalize) {
-#ifdef ENABLE_PSEUDOLOCALIZE
                 std::string orig(String8(text).string());
                 std::string pseudo = pseudolocalize_string(orig);
                 curString.append(String16(String8(pseudo.c_str())));
-#else
-                assert(false);
-#endif
             } else {
                 if (isFormatted && hasSubstitutionErrors(fileName, inXml, text) != NO_ERROR) {
                     return UNKNOWN_ERROR;
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index f760d27..720f6ac 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -108,6 +108,8 @@
 
     void startWpsPbc(String bssid);
 
-    void startWpsPin(String bssid, int apPin);
+    void startWpsWithPinFromAccessPoint(String bssid, int apPin);
+
+    int startWpsWithPinFromDevice(String bssid);
 }
 
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index be5fab4..04b3891 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -361,10 +361,11 @@
     }
 
     /**
-     * Start WPS pin method configuration
+     * Start WPS pin method configuration with pin obtained
+     * from the access point
      */
-    static boolean startWpsPin(String bssid, int apPin) {
-        if (WifiNative.startWpsPinCommand(bssid, apPin)) {
+    static boolean startWpsWithPinFromAccessPoint(String bssid, int apPin) {
+        if (WifiNative.startWpsWithPinFromAccessPointCommand(bssid, apPin)) {
             /* WPS leaves all networks disabled */
             markAllNetworksDisabled();
             return true;
@@ -374,6 +375,21 @@
     }
 
     /**
+     * Start WPS pin method configuration with pin obtained
+     * from the device
+     */
+    static int startWpsWithPinFromDevice(String bssid) {
+        int pin = WifiNative.startWpsWithPinFromDeviceCommand(bssid);
+        /* WPS leaves all networks disabled */
+        if (pin != -1) {
+            markAllNetworksDisabled();
+        } else {
+            Log.e(TAG, "Failed to start WPS pin method configuration");
+        }
+        return pin;
+    }
+
+    /**
      * Start WPS push button configuration
      */
     static boolean startWpsPbc(String bssid) {
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 0b3a782..356a0bd 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -339,6 +339,16 @@
     public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
 
     /**
+     * In this Wi-Fi lock mode, Wi-Fi will behave as in the mode
+     * {@link #WIFI_MODE_FULL} but it operates at high performance
+     * at the expense of power. This mode should be used
+     * only when the wifi connection needs to have minimum loss and low
+     * latency as it can impact the battery life.
+     * @hide
+     */
+    public static final int WIFI_MODE_FULL_HIGH_PERF = 3;
+
+    /**
      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
      * and will behave normally, i.e., it will attempt to automatically
      * establish a connection to a remembered access point that is
@@ -1050,19 +1060,36 @@
 
     /**
      * Start Wi-fi Protected Setup pin method configuration
+     * with pin obtained from the access point
      *
      * @param bssid BSSID of the access point
      * @param apPin PIN issued by the access point
      *
      * @hide
      */
-    public void startWpsPin(String bssid, int apPin) {
+    public void startWpsWithPinFromAccessPoint(String bssid, int apPin) {
         try {
-            mService.startWpsPin(bssid, apPin);
+            mService.startWpsWithPinFromAccessPoint(bssid, apPin);
         } catch (RemoteException e) { }
     }
 
     /**
+     * Start Wi-fi Protected Setup pin method configuration
+     * with pin obtained from the device
+     *
+     * @param bssid BSSID of the access point
+     * @return pin generated by device
+     * @hide
+     */
+    public int startWpsWithPinFromDevice(String bssid) {
+        try {
+            return mService.startWpsWithPinFromDevice(bssid);
+        } catch (RemoteException e) {
+            return -1;
+        }
+    }
+
+    /**
      * Allows an application to keep the Wi-Fi radio awake.
      * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
      * Acquiring a WifiLock will keep the radio on until the lock is released.  Multiple 
@@ -1244,8 +1271,8 @@
     /**
      * Creates a new WifiLock.
      *
-     * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL} and
-     * {@link #WIFI_MODE_SCAN_ONLY} for descriptions of the types of Wi-Fi locks.
+     * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL},
+     * and {@link #WIFI_MODE_SCAN_ONLY} for descriptions of the types of Wi-Fi locks.
      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is 
      *            never shown to the user under normal conditions, but should be descriptive 
      *            enough to identify your application and the specific WifiLock within it, if it
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 1251a25..3d8157c 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -153,12 +153,16 @@
 
     public native static boolean startWpsPbcCommand(String bssid);
 
-    public native static boolean startWpsPinCommand(String bssid, int apPin);
+    public native static boolean startWpsWithPinFromAccessPointCommand(String bssid, int apPin);
+
+    public native static int startWpsWithPinFromDeviceCommand(String bssid);
 
     public native static boolean doDhcpRequest(DhcpInfo results);
 
     public native static String getDhcpError();
 
+    public native static boolean setSuspendOptimizationsCommand(boolean enabled);
+
     /**
      * Wait for the supplicant to send an event, returning the event string.
      * @return the event string sent by the supplicant.
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index e3deeb3..6bd67cc 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -246,11 +246,20 @@
     private static final int CMD_RECONNECT                        = 75;
     /* Reassociate to a network */
     private static final int CMD_REASSOCIATE                      = 76;
-    /* Set power mode
-     * POWER_MODE_ACTIVE
-     * POWER_MODE_AUTO
+    /* Controls power mode and suspend mode optimizations
+     *
+     * When high perf mode is enabled, power mode is set to
+     * POWER_MODE_ACTIVE and suspend mode optimizations are disabled
+     *
+     * When high perf mode is disabled, power mode is set to
+     * POWER_MODE_AUTO and suspend mode optimizations are enabled
+     *
+     * Suspend mode optimizations include:
+     * - packet filtering
+     * - turn off roaming
+     * - DTIM wake up settings
      */
-    private static final int CMD_SET_POWER_MODE                   = 77;
+    private static final int CMD_SET_HIGH_PERF_MODE               = 77;
     /* Set bluetooth co-existence
      * BLUETOOTH_COEXISTENCE_MODE_ENABLED
      * BLUETOOTH_COEXISTENCE_MODE_DISABLED
@@ -301,9 +310,10 @@
      * supplicant config.
      */
     private static final int CMD_FORGET_NETWORK                   = 92;
-    /* Start Wi-Fi protected setup */
-    private static final int CMD_START_WPS                        = 93;
-
+    /* Start Wi-Fi protected setup push button configuration */
+    private static final int CMD_START_WPS_PBC                    = 93;
+    /* Start Wi-Fi protected setup pin method configuration */
+    private static final int CMD_START_WPS_PIN                    = 94;
     /**
      * Interval in milliseconds between polling for connection
      * status items that are not sent via asynchronous events.
@@ -334,8 +344,8 @@
      */
     private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
 
-    private static final int DRIVER_POWER_MODE_ACTIVE = 1;
-    private static final int DRIVER_POWER_MODE_AUTO = 0;
+    private static final int POWER_MODE_ACTIVE = 1;
+    private static final int POWER_MODE_AUTO = 0;
 
     /* Default parent state */
     private HierarchicalState mDefaultState = new DefaultState();
@@ -787,11 +797,18 @@
     }
 
     public void startWpsPbc(String bssid) {
-        sendMessage(obtainMessage(CMD_START_WPS, bssid));
+        sendMessage(obtainMessage(CMD_START_WPS_PBC, bssid));
     }
 
-    public void startWpsPin(String bssid, int apPin) {
-        sendMessage(obtainMessage(CMD_START_WPS, apPin, 0, bssid));
+    public void startWpsWithPinFromAccessPoint(String bssid, int apPin) {
+        sendMessage(obtainMessage(CMD_START_WPS_PIN, apPin, 0, bssid));
+    }
+
+    public int syncStartWpsWithPinFromDevice(AsyncChannel channel, String bssid) {
+        Message resultMsg = channel.sendMessageSynchronously(CMD_START_WPS_PIN, bssid);
+        int result = resultMsg.arg1;
+        resultMsg.recycle();
+        return result;
     }
 
     public void enableRssiPolling(boolean enabled) {
@@ -848,13 +865,13 @@
     }
 
     /**
-     * Set power mode
-     * @param mode
-     *     DRIVER_POWER_MODE_AUTO
-     *     DRIVER_POWER_MODE_ACTIVE
+     * Set high performance mode of operation.
+     * Enabling would set active power mode and disable suspend optimizations;
+     * disabling would set auto power mode and enable suspend optimizations
+     * @param enable true if enable, false otherwise
      */
-    public void setPowerMode(int mode) {
-        sendMessage(obtainMessage(CMD_SET_POWER_MODE, mode, 0));
+    public void setHighPerfModeEnabled(boolean enable) {
+        sendMessage(obtainMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0));
     }
 
     /**
@@ -1261,6 +1278,21 @@
         return null;
     }
 
+    private void setHighPerfModeEnabledNative(boolean enable) {
+        if(!WifiNative.setSuspendOptimizationsCommand(!enable)) {
+            Log.e(TAG, "set suspend optimizations failed!");
+        }
+        if (enable) {
+            if (!WifiNative.setPowerModeCommand(POWER_MODE_ACTIVE)) {
+                Log.e(TAG, "set power mode active failed!");
+            }
+        } else {
+            if (!WifiNative.setPowerModeCommand(POWER_MODE_AUTO)) {
+                Log.e(TAG, "set power mode auto failed!");
+            }
+        }
+    }
+
     private void configureLinkProperties() {
         if (WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
             mLinkProperties = WifiConfigStore.getLinkProperties(mLastNetworkId);
@@ -1646,7 +1678,7 @@
                 case CMD_CLEAR_BLACKLIST:
                 case CMD_SET_SCAN_MODE:
                 case CMD_SET_SCAN_TYPE:
-                case CMD_SET_POWER_MODE:
+                case CMD_SET_HIGH_PERF_MODE:
                 case CMD_SET_BLUETOOTH_COEXISTENCE:
                 case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_NUM_ALLOWED_CHANNELS:
@@ -1654,7 +1686,8 @@
                 case CMD_CONNECT_NETWORK:
                 case CMD_SAVE_NETWORK:
                 case CMD_FORGET_NETWORK:
-                case CMD_START_WPS:
+                case CMD_START_WPS_PBC:
+                case CMD_START_WPS_PIN:
                     break;
                 default:
                     Log.e(TAG, "Error! unhandled message" + message);
@@ -1747,7 +1780,7 @@
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
                 case CMD_SET_SCAN_TYPE:
-                case CMD_SET_POWER_MODE:
+                case CMD_SET_HIGH_PERF_MODE:
                 case CMD_SET_BLUETOOTH_COEXISTENCE:
                 case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_NUM_ALLOWED_CHANNELS:
@@ -1875,7 +1908,7 @@
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
                 case CMD_SET_SCAN_TYPE:
-                case CMD_SET_POWER_MODE:
+                case CMD_SET_HIGH_PERF_MODE:
                 case CMD_SET_BLUETOOTH_COEXISTENCE:
                 case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_NUM_ALLOWED_CHANNELS:
@@ -1972,7 +2005,7 @@
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_MODE:
                 case CMD_SET_SCAN_TYPE:
-                case CMD_SET_POWER_MODE:
+                case CMD_SET_HIGH_PERF_MODE:
                 case CMD_SET_BLUETOOTH_COEXISTENCE:
                 case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_NUM_ALLOWED_CHANNELS:
@@ -2129,7 +2162,7 @@
                 case NETWORK_DISCONNECTION_EVENT:
                 case PASSWORD_MAY_BE_INCORRECT_EVENT:
                 case CMD_SET_SCAN_TYPE:
-                case CMD_SET_POWER_MODE:
+                case CMD_SET_HIGH_PERF_MODE:
                 case CMD_SET_BLUETOOTH_COEXISTENCE:
                 case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_NUM_ALLOWED_CHANNELS:
@@ -2183,8 +2216,8 @@
                         WifiNative.setScanModeCommand(false);
                     }
                     break;
-                case CMD_SET_POWER_MODE:
-                    WifiNative.setPowerModeCommand(message.arg1);
+                case CMD_SET_HIGH_PERF_MODE:
+                    setHighPerfModeEnabledNative(message.arg1 == 1);
                     break;
                 case CMD_SET_BLUETOOTH_COEXISTENCE:
                     WifiNative.setBluetoothCoexistenceModeCommand(message.arg1);
@@ -2247,7 +2280,7 @@
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_TYPE:
-                case CMD_SET_POWER_MODE:
+                case CMD_SET_HIGH_PERF_MODE:
                 case CMD_SET_BLUETOOTH_COEXISTENCE:
                 case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_NUM_ALLOWED_CHANNELS:
@@ -2395,17 +2428,11 @@
                     /* Expect a disconnection from the old connection */
                     transitionTo(mDisconnectingState);
                     break;
-                case CMD_START_WPS:
+                case CMD_START_WPS_PBC:
                     String bssid = (String) message.obj;
-                    int apPin = message.arg1;
-                    boolean success;
-                    if (apPin != 0) {
-                        /* WPS pin method configuration */
-                        success = WifiConfigStore.startWpsPin(bssid, apPin);
-                    } else {
-                        /* WPS push button configuration */
-                        success = WifiConfigStore.startWpsPbc(bssid);
-                    }
+                    /* WPS push button configuration */
+                    boolean success = WifiConfigStore.startWpsPbc(bssid);
+
                     /* During WPS setup, all other networks are disabled. After
                      * a successful connect a new config is created in the supplicant.
                      *
@@ -2422,6 +2449,24 @@
                         transitionTo(mDisconnectingState);
                     }
                     break;
+                case CMD_START_WPS_PIN:
+                    bssid = (String) message.obj;
+                    int apPin = message.arg1;
+                    int pin;
+                    if (apPin != 0) {
+                        /* WPS pin from access point */
+                        success = WifiConfigStore.startWpsWithPinFromAccessPoint(bssid, apPin);
+                    } else {
+                        pin = WifiConfigStore.startWpsWithPinFromDevice(bssid);
+                        success = (pin != -1);
+                        mReplyChannel.replyToMessage(message, CMD_START_WPS_PIN, pin);
+                    }
+                    if (success) {
+                        mWpsStarted = true;
+                        /* Expect a disconnection from the old connection */
+                        transitionTo(mDisconnectingState);
+                    }
+                    break;
                 case SCAN_RESULTS_EVENT:
                     /* Set the scan setting back to "connect" mode */
                     WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
@@ -2484,7 +2529,7 @@
             if (!mUseStaticIp) {
                 mDhcpThread = null;
                 mModifiedBluetoothCoexistenceMode = false;
-                mPowerMode = DRIVER_POWER_MODE_AUTO;
+                mPowerMode = POWER_MODE_AUTO;
 
                 if (shouldDisableCoexistenceMode()) {
                     /*
@@ -2514,10 +2559,10 @@
                 if (mPowerMode < 0) {
                   // Handle the case where supplicant driver does not support
                   // getPowerModeCommand.
-                    mPowerMode = DRIVER_POWER_MODE_AUTO;
+                    mPowerMode = POWER_MODE_AUTO;
                 }
-                if (mPowerMode != DRIVER_POWER_MODE_ACTIVE) {
-                    WifiNative.setPowerModeCommand(DRIVER_POWER_MODE_ACTIVE);
+                if (mPowerMode != POWER_MODE_ACTIVE) {
+                    WifiNative.setPowerModeCommand(POWER_MODE_ACTIVE);
                 }
 
                 Log.d(TAG, "DHCP request started");
@@ -2618,6 +2663,10 @@
               case CMD_RECONFIGURE_IP:
                   deferMessage(message);
                   break;
+                  /* Defer any power mode changes since we must keep active power mode at DHCP */
+              case CMD_SET_HIGH_PERF_MODE:
+                  deferMessage(message);
+                  break;
               default:
                 return NOT_HANDLED;
           }
@@ -2629,7 +2678,7 @@
       public void exit() {
           /* reset power state & bluetooth coexistence if on DHCP */
           if (!mUseStaticIp) {
-              if (mPowerMode != DRIVER_POWER_MODE_ACTIVE) {
+              if (mPowerMode != POWER_MODE_ACTIVE) {
                   WifiNative.setPowerModeCommand(mPowerMode);
               }