Merge "Batch glCopyTexImage() calls to get about 15 fps back on SGX."
diff --git a/api/14.txt b/api/14.txt
index 5c4732e..050540b 100644
--- a/api/14.txt
+++ b/api/14.txt
@@ -22239,7 +22239,6 @@
   }
 
   public class AccessibilityRecord {
-    ctor protected AccessibilityRecord();
     method public int getAddedCount();
     method public java.lang.CharSequence getBeforeText();
     method public java.lang.CharSequence getClassName();
@@ -22269,17 +22268,6 @@
     method public void setParcelableData(android.os.Parcelable);
     method public void setPassword(boolean);
     method public void setRemovedCount(int);
-    field protected int mAddedCount;
-    field protected java.lang.CharSequence mBeforeText;
-    field protected int mBooleanProperties;
-    field protected java.lang.CharSequence mClassName;
-    field protected java.lang.CharSequence mContentDescription;
-    field protected int mCurrentItemIndex;
-    field protected int mFromIndex;
-    field protected int mItemCount;
-    field protected android.os.Parcelable mParcelableData;
-    field protected int mRemovedCount;
-    field protected final java.util.List mText;
   }
 }
 
diff --git a/api/current.txt b/api/current.txt
index aed11b0..acea3e7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -425,6 +425,7 @@
     field public static final int fastScrollTextColor = 16843609; // 0x1010359
     field public static final int fastScrollThumbDrawable = 16843574; // 0x1010336
     field public static final int fastScrollTrackDrawable = 16843577; // 0x1010339
+    field public static final int feedbackCount = 16843665; // 0x1010391
     field public static final int fillAfter = 16843197; // 0x10101bd
     field public static final int fillBefore = 16843196; // 0x10101bc
     field public static final int fillEnabled = 16843343; // 0x101024f
@@ -478,6 +479,7 @@
     field public static final int hand_hour = 16843011; // 0x1010103
     field public static final int hand_minute = 16843012; // 0x1010104
     field public static final int handle = 16843354; // 0x101025a
+    field public static final int handleDrawable = 16843657; // 0x1010389
     field public static final int handleProfiling = 16842786; // 0x1010022
     field public static final int hapticFeedbackEnabled = 16843358; // 0x101025e
     field public static final int hardwareAccelerated = 16843475; // 0x10102d3
@@ -486,10 +488,12 @@
     field public static final int headerDividersEnabled = 16843310; // 0x101022e
     field public static final int height = 16843093; // 0x1010155
     field public static final int hint = 16843088; // 0x1010150
+    field public static final int hitRadius = 16843662; // 0x101038e
     field public static final int homeAsUpIndicator = 16843531; // 0x101030b
     field public static final int homeLayout = 16843549; // 0x101031d
     field public static final int horizontalDivider = 16843053; // 0x101012d
     field public static final int horizontalGap = 16843327; // 0x101023f
+    field public static final int horizontalOffset = 16843667; // 0x1010393
     field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353
     field public static final int horizontalSpacing = 16843028; // 0x1010114
     field public static final int host = 16842792; // 0x1010028
@@ -610,6 +614,7 @@
     field public static final int layout_x = 16843135; // 0x101017f
     field public static final int layout_y = 16843136; // 0x1010180
     field public static final int left = 16843181; // 0x10101ad
+    field public static final int leftChevronDrawable = 16843658; // 0x101038a
     field public static final int lineSpacingExtra = 16843287; // 0x1010217
     field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
     field public static final int lines = 16843092; // 0x1010154
@@ -681,6 +686,7 @@
     field public static final int orderingFromXml = 16843239; // 0x10101e7
     field public static final int orientation = 16842948; // 0x10100c4
     field public static final int outAnimation = 16843128; // 0x1010178
+    field public static final int outerRadius = 16843661; // 0x101038d
     field public static final int overScrollFooter = 16843459; // 0x10102c3
     field public static final int overScrollHeader = 16843458; // 0x10102c2
     field public static final int overScrollMode = 16843457; // 0x10102c1
@@ -769,6 +775,7 @@
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
     field public static final int right = 16843183; // 0x10101af
+    field public static final int rightChevronDrawable = 16843659; // 0x101038b
     field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
     field public static final int ringtoneType = 16843257; // 0x10101f9
     field public static final int rotation = 16843558; // 0x1010326
@@ -844,6 +851,7 @@
     field public static final int smallIcon = 16843422; // 0x101029e
     field public static final int smallScreens = 16843396; // 0x1010284
     field public static final int smoothScrollbar = 16843313; // 0x1010231
+    field public static final int snapMargin = 16843664; // 0x1010390
     field public static final int soundEffectsEnabled = 16843285; // 0x1010215
     field public static final int spacing = 16843027; // 0x1010113
     field public static final int spinnerDropDownItemStyle = 16842887; // 0x1010087
@@ -908,6 +916,7 @@
     field public static final int tag = 16842961; // 0x10100d1
     field public static final int targetActivity = 16843266; // 0x1010202
     field public static final int targetClass = 16842799; // 0x101002f
+    field public static final int targetDrawables = 16843656; // 0x1010388
     field public static final int targetPackage = 16842785; // 0x1010021
     field public static final int targetSdkVersion = 16843376; // 0x1010270
     field public static final int taskAffinity = 16842770; // 0x1010012
@@ -1026,8 +1035,10 @@
     field public static final int verticalCorrection = 16843322; // 0x101023a
     field public static final int verticalDivider = 16843054; // 0x101012e
     field public static final int verticalGap = 16843328; // 0x1010240
+    field public static final int verticalOffset = 16843666; // 0x1010392
     field public static final int verticalScrollbarPosition = 16843572; // 0x1010334
     field public static final int verticalSpacing = 16843029; // 0x1010115
+    field public static final int vibrationDuration = 16843663; // 0x101038f
     field public static final int visibility = 16842972; // 0x10100dc
     field public static final int visible = 16843156; // 0x1010194
     field public static final int vmSafeMode = 16843448; // 0x10102b8
@@ -1044,6 +1055,7 @@
     field public static final int wallpaperIntraOpenExitAnimation = 16843416; // 0x1010298
     field public static final int wallpaperOpenEnterAnimation = 16843411; // 0x1010293
     field public static final int wallpaperOpenExitAnimation = 16843412; // 0x1010294
+    field public static final int waveDrawable = 16843660; // 0x101038c
     field public static final int webTextViewStyle = 16843449; // 0x10102b9
     field public static final int webViewStyle = 16842885; // 0x1010085
     field public static final int weekDayTextAppearance = 16843592; // 0x1010348
@@ -2912,6 +2924,7 @@
     method public static android.app.Fragment instantiate(android.content.Context, java.lang.String);
     method public static android.app.Fragment instantiate(android.content.Context, java.lang.String, android.os.Bundle);
     method public final boolean isAdded();
+    method public final boolean isDetached();
     method public final boolean isHidden();
     method public final boolean isInLayout();
     method public final boolean isRemoving();
@@ -11167,6 +11180,8 @@
     method public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
     method public static javax.net.ssl.SSLSocketFactory getInsecure(int, android.net.SSLSessionCache);
     method public java.lang.String[] getSupportedCipherSuites();
+    method public void setKeyManagers(javax.net.ssl.KeyManager[]);
+    method public void setTrustManagers(javax.net.ssl.TrustManager[]);
   }
 
   public final class SSLSessionCache {
@@ -21593,6 +21608,8 @@
     method public void buildDrawingCache();
     method public void buildDrawingCache(boolean);
     method public void buildLayer();
+    method public boolean canScrollHorizontally(int);
+    method public boolean canScrollVertically(int);
     method public void cancelLongPress();
     method public boolean checkInputConnectionProxy(android.view.View);
     method public void clearAnimation();
@@ -22706,13 +22723,11 @@
     method public void appendRecord(android.view.accessibility.AccessibilityRecord);
     method public int describeContents();
     method public static java.lang.String eventTypeToString(int);
-    method public int getAccessibilityWindowId();
     method public long getEventTime();
     method public int getEventType();
     method public java.lang.CharSequence getPackageName();
     method public android.view.accessibility.AccessibilityRecord getRecord(int);
     method public int getRecordCount();
-    method public android.view.accessibility.AccessibilityNodeInfo getSource();
     method public void initFromParcel(android.os.Parcel);
     method public static android.view.accessibility.AccessibilityEvent obtain(int);
     method public static android.view.accessibility.AccessibilityEvent obtain(android.view.accessibility.AccessibilityEvent);
@@ -22720,7 +22735,6 @@
     method public void setEventTime(long);
     method public void setEventType(int);
     method public void setPackageName(java.lang.CharSequence);
-    method public void setSource(android.view.View);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int INVALID_POSITION = -1; // 0xffffffff
@@ -22736,6 +22750,7 @@
     field public static final int TYPE_VIEW_LONG_CLICKED = 2; // 0x2
     field public static final int TYPE_VIEW_SELECTED = 4; // 0x4
     field public static final int TYPE_VIEW_TEXT_CHANGED = 16; // 0x10
+    field public static final int TYPE_WINDOW_CONTENT_CHANGED = 2048; // 0x800
     field public static final int TYPE_WINDOW_STATE_CHANGED = 32; // 0x20
   }
 
@@ -22763,9 +22778,10 @@
     method public void addAction(int);
     method public void addChild(android.view.View);
     method public int describeContents();
-    method public int getAccessibilityWindowId();
+    method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(java.lang.String);
     method public int getActions();
-    method public void getBounds(android.graphics.Rect);
+    method public void getBoundsInParent(android.graphics.Rect);
+    method public void getBoundsInScreen(android.graphics.Rect);
     method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
     method public int getChildCount();
     method public java.lang.CharSequence getClassName();
@@ -22773,6 +22789,7 @@
     method public java.lang.CharSequence getPackageName();
     method public android.view.accessibility.AccessibilityNodeInfo getParent();
     method public java.lang.CharSequence getText();
+    method public int getWindowId();
     method public boolean isCheckable();
     method public boolean isChecked();
     method public boolean isClickable();
@@ -22786,7 +22803,8 @@
     method public static android.view.accessibility.AccessibilityNodeInfo obtain();
     method public boolean performAction(int);
     method public void recycle();
-    method public void setBounds(android.graphics.Rect);
+    method public void setBoundsInParent(android.graphics.Rect);
+    method public void setBoundsInScreen(android.graphics.Rect);
     method public void setCheckable(boolean);
     method public void setChecked(boolean);
     method public void setClassName(java.lang.CharSequence);
@@ -22811,7 +22829,6 @@
   }
 
   public class AccessibilityRecord {
-    ctor protected AccessibilityRecord();
     method public int getAddedCount();
     method public java.lang.CharSequence getBeforeText();
     method public java.lang.CharSequence getClassName();
@@ -22821,7 +22838,9 @@
     method public int getItemCount();
     method public android.os.Parcelable getParcelableData();
     method public int getRemovedCount();
+    method public android.view.accessibility.AccessibilityNodeInfo getSource();
     method public java.util.List<java.lang.CharSequence> getText();
+    method public int getWindowId();
     method public boolean isChecked();
     method public boolean isEnabled();
     method public boolean isFullScreen();
@@ -22842,17 +22861,7 @@
     method public void setParcelableData(android.os.Parcelable);
     method public void setPassword(boolean);
     method public void setRemovedCount(int);
-    field protected int mAddedCount;
-    field protected java.lang.CharSequence mBeforeText;
-    field protected int mBooleanProperties;
-    field protected java.lang.CharSequence mClassName;
-    field protected java.lang.CharSequence mContentDescription;
-    field protected int mCurrentItemIndex;
-    field protected int mFromIndex;
-    field protected int mItemCount;
-    field protected android.os.Parcelable mParcelableData;
-    field protected int mRemovedCount;
-    field protected final java.util.List mText;
+    method public void setSource(android.view.View);
   }
 
 }
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 69c4597..0acba8b 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -313,9 +313,6 @@
     const GLint yc = (mHeight - mAndroid[0].h) / 2;
     const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);
 
-    // draw and update only what we need
-    mFlingerSurface->setSwapRectangle(updateRect);
-
     glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
             updateRect.height());
 
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 01262fa..ca77185 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -66,6 +66,7 @@
 static long gMaxNumFrames;  // 0 means decode all available.
 static long gReproduceBug;  // if not -1.
 static bool gPreferSoftwareCodec;
+static bool gForceToUseHardwareCodec;
 static bool gPlaybackAudio;
 static bool gWriteMP4;
 static bool gDisplayHistogram;
@@ -144,10 +145,18 @@
     if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, mime)) {
         rawSource = source;
     } else {
+        int flags = 0;
+        if (gPreferSoftwareCodec) {
+            flags |= OMXCodec::kPreferSoftwareCodecs;
+        }
+        if (gForceToUseHardwareCodec) {
+            CHECK(!gPreferSoftwareCodec);
+            flags |= OMXCodec::kHardwareCodecsOnly;
+        }
         rawSource = OMXCodec::Create(
             client->interface(), meta, false /* createEncoder */, source,
             NULL /* matchComponentName */,
-            gPreferSoftwareCodec ? OMXCodec::kPreferSoftwareCodecs : 0,
+            flags,
             gSurface);
 
         if (rawSource == NULL) {
@@ -545,6 +554,7 @@
     fprintf(stderr, "       -p(rofiles) dump decoder profiles supported\n");
     fprintf(stderr, "       -t(humbnail) extract video thumbnail or album art\n");
     fprintf(stderr, "       -s(oftware) prefer software codec\n");
+    fprintf(stderr, "       -r(hardware) force to use hardware codec\n");
     fprintf(stderr, "       -o playback audio\n");
     fprintf(stderr, "       -w(rite) filename (write to .mp4 file)\n");
     fprintf(stderr, "       -k seek test\n");
@@ -566,6 +576,7 @@
     gMaxNumFrames = 0;
     gReproduceBug = -1;
     gPreferSoftwareCodec = false;
+    gForceToUseHardwareCodec = false;
     gPlaybackAudio = false;
     gWriteMP4 = false;
     gDisplayHistogram = false;
@@ -575,7 +586,7 @@
     sp<LiveSession> liveSession;
 
     int res;
-    while ((res = getopt(argc, argv, "han:lm:b:ptsow:kxS")) >= 0) {
+    while ((res = getopt(argc, argv, "han:lm:b:ptsrow:kxS")) >= 0) {
         switch (res) {
             case 'a':
             {
@@ -636,6 +647,12 @@
                 break;
             }
 
+            case 'r':
+            {
+                gForceToUseHardwareCodec = true;
+                break;
+            }
+
             case 'o':
             {
                 gPlaybackAudio = true;
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 8bb305d..164acbc 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -190,9 +190,9 @@
      *            <li>
      *              Register for all event types with no notification timeout and keep track
      *              for the active window by calling
-     *              {@link AccessibilityEvent#getAccessibilityWindowId()} of the last received
+     *              {@link AccessibilityEvent#getWindowId()} of the last received
      *              event and compare this with the
-     *              {@link AccessibilityNodeInfo#getAccessibilityWindowId()} before calling
+     *              {@link AccessibilityNodeInfo#getWindowId()} before calling
      *              retrieval methods on the latter.
      *            </li>
      *            <li>
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 19f0bf0..8b4e7aee 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -47,7 +47,9 @@
 
     /**
      * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
-     * insensitive containment.
+     * insensitive containment. The search is performed in the window whose
+     * id is specified and starts from the View whose accessibility id is
+     * specified.
      * <p>
      *   <strong>
      *     It is a client responsibility to recycle the received infos by
@@ -57,12 +59,35 @@
      * </p>
      *
      * @param text The searched text.
+     * @param accessibilityId The id of the view from which to start searching.
+     *        Use {@link android.view.View#NO_ID} to start from the root.
      * @return A list of node info.
      */
-    List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText(String text);
+    List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText(String text,
+        int accessibilityWindowId, int accessibilityViewId);
 
     /**
-     * Finds an {@link AccessibilityNodeInfo} by View id.
+     * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
+     * insensitive containment. The search is performed in the currently
+     * active window and start from the root View in the window.
+     * <p>
+     *   <strong>
+     *     It is a client responsibility to recycle the received infos by
+     *     calling {@link AccessibilityNodeInfo#recycle()} to avoid creating
+     *     of multiple instances.
+     *   </strong>
+     * </p>
+     *
+     * @param text The searched text.
+     * @param accessibilityId The id of the view from which to start searching.
+     *        Use {@link android.view.View#NO_ID} to start from the root.
+     * @return A list of node info.
+     */
+    List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewTextInActiveWindow(String text);
+
+    /**
+     * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed
+     * in the currently active window and start from the root View in the window.
      * <p>
      *   <strong>
      *     It is a client responsibility to recycle the received info by
@@ -74,7 +99,7 @@
      * @param id The id of the node.
      * @return The node info.
      */
-    AccessibilityNodeInfo findAccessibilityNodeInfoByViewId(int viewId);
+    AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId);
 
     /**
      * Performs an accessibility action on an {@link AccessibilityNodeInfo}.
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 0481158..aeb16f4 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -723,6 +723,8 @@
     
     protected static final int[] FOCUSED_STATE_SET = {com.android.internal.R.attr.state_focused};
 
+    private final Object mInstanceTracker = StrictMode.trackActivity(this);
+
     private Thread mUiThread;
     final Handler mHandler = new Handler();
 
@@ -4417,7 +4419,9 @@
         mFragments.dispatchStart();
         if (mAllLoaderManagers != null) {
             for (int i=mAllLoaderManagers.size()-1; i>=0; i--) {
-                mAllLoaderManagers.valueAt(i).finishRetain();
+                LoaderManagerImpl lm = mAllLoaderManagers.valueAt(i);
+                lm.finishRetain();
+                lm.doReportStart();
             }
         }
     }
@@ -4552,9 +4556,6 @@
             mStopped = true;
         }
         mResumed = false;
-
-        // Check for Activity leaks, if enabled.
-        StrictMode.conditionallyCheckInstanceCounts();
     }
 
     final void performDestroy() {
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 14ffd3b..f2be9ad 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -587,11 +587,6 @@
         mWho = "android:fragment:" + mIndex;
    }
     
-    final void clearIndex() {
-        mIndex = -1;
-        mWho = null;
-    }
-    
     final boolean isInBackStack() {
         return mBackStackNesting > 0;
     }
@@ -783,6 +778,15 @@
     }
 
     /**
+     * Return true if the fragment has been explicitly detached from the UI.
+     * That is, {@link FragmentTransaction#detach(Fragment)
+     * FragmentTransaction.detach(Fragment)} has been used on it.
+     */
+    final public boolean isDetached() {
+        return mDetached;
+    }
+
+    /**
      * Return true if this fragment is currently being removed from its
      * activity.  This is  <em>not</em> whether its activity is finishing, but
      * rather whether it is in the process of being removed from its activity.
@@ -1203,6 +1207,35 @@
     }
 
     /**
+     * Called by the fragment manager once this fragment has been removed,
+     * so that we don't have any left-over state if the application decides
+     * to re-use the instance.  This only clears state that the framework
+     * internally manages, not things the application sets.
+     */
+    void initState() {
+        mIndex = -1;
+        mWho = null;
+        mAdded = false;
+        mRemoving = false;
+        mResumed = false;
+        mFromLayout = false;
+        mInLayout = false;
+        mRestored = false;
+        mBackStackNesting = 0;
+        mFragmentManager = null;
+        mActivity = mImmediateActivity = null;
+        mFragmentId = 0;
+        mContainerId = 0;
+        mTag = null;
+        mHidden = false;
+        mDetached = false;
+        mRetaining = false;
+        mLoaderManager = null;
+        mLoadersStarted = false;
+        mCheckedForLoaderManager = false;
+    }
+
+    /**
      * Called when the fragment is no longer attached to its activity.  This
      * is called after {@link #onDestroy()}.
      */
@@ -1429,6 +1462,13 @@
         }
     }
 
+    void performStart() {
+        onStart();
+        if (mLoaderManager != null) {
+            mLoaderManager.doReportStart();
+        }
+    }
+
     void performStop() {
         onStop();
         
@@ -1447,4 +1487,11 @@
             }
         }
     }
+
+    void performDestroyView() {
+        onDestroyView();
+        if (mLoaderManager != null) {
+            mLoaderManager.doReportNextStart();
+        }
+    }
 }
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 3b2e108..f05e2b3 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -803,7 +803,7 @@
                     if (newState > Fragment.STOPPED) {
                         if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
                         f.mCalled = false;
-                        f.onStart();
+                        f.performStart();
                         if (!f.mCalled) {
                             throw new SuperNotCalledException("Fragment " + f
                                     + " did not call through to super.onStart()");
@@ -856,7 +856,7 @@
                             }
                         }
                         f.mCalled = false;
-                        f.onDestroyView();
+                        f.performDestroyView();
                         if (!f.mCalled) {
                             throw new SuperNotCalledException("Fragment " + f
                                     + " did not call through to super.onDestroyView()");
@@ -1006,7 +1006,7 @@
         }
         mAvailIndices.add(f.mIndex);
         mActivity.invalidateFragmentIndex(f.mIndex);
-        f.clearIndex();
+        f.initState();
     }
     
     public void addFragment(Fragment fragment, boolean moveToStateNow) {
diff --git a/core/java/android/app/ListFragment.java b/core/java/android/app/ListFragment.java
index a5ee26c..dc8420e 100644
--- a/core/java/android/app/ListFragment.java
+++ b/core/java/android/app/ListFragment.java
@@ -167,7 +167,7 @@
     TextView mStandardEmptyView;
     View mProgressContainer;
     View mListContainer;
-    boolean mSetEmptyText;
+    CharSequence mEmptyText;
     boolean mListShown;
 
     public ListFragment() {
@@ -210,6 +210,9 @@
     public void onDestroyView() {
         mHandler.removeCallbacks(mRequestFocus);
         mList = null;
+        mListShown = false;
+        mEmptyView = mProgressContainer = mListContainer = null;
+        mStandardEmptyView = null;
         super.onDestroyView();
     }
 
@@ -289,10 +292,10 @@
             throw new IllegalStateException("Can't be used with a custom content view");
         }
         mStandardEmptyView.setText(text);
-        if (!mSetEmptyText) {
+        if (mEmptyText == null) {
             mList.setEmptyView(mStandardEmptyView);
-            mSetEmptyText = true;
         }
+        mEmptyText = text;
     }
     
     /**
@@ -346,6 +349,9 @@
                         getActivity(), android.R.anim.fade_out));
                 mListContainer.startAnimation(AnimationUtils.loadAnimation(
                         getActivity(), android.R.anim.fade_in));
+            } else {
+                mProgressContainer.clearAnimation();
+                mListContainer.clearAnimation();
             }
             mProgressContainer.setVisibility(View.GONE);
             mListContainer.setVisibility(View.VISIBLE);
@@ -355,6 +361,9 @@
                         getActivity(), android.R.anim.fade_in));
                 mListContainer.startAnimation(AnimationUtils.loadAnimation(
                         getActivity(), android.R.anim.fade_out));
+            } else {
+                mProgressContainer.clearAnimation();
+                mListContainer.clearAnimation();
             }
             mProgressContainer.setVisibility(View.VISIBLE);
             mListContainer.setVisibility(View.GONE);
@@ -383,6 +392,8 @@
                     com.android.internal.R.id.internalEmpty);
             if (mStandardEmptyView == null) {
                 mEmptyView = root.findViewById(android.R.id.empty);
+            } else {
+                mStandardEmptyView.setVisibility(View.GONE);
             }
             mProgressContainer = root.findViewById(com.android.internal.R.id.progressContainer);
             mListContainer = root.findViewById(com.android.internal.R.id.listContainer);
@@ -400,12 +411,17 @@
             }
             if (mEmptyView != null) {
                 mList.setEmptyView(mEmptyView);
+            } else if (mEmptyText != null) {
+                mStandardEmptyView.setText(mEmptyText);
+                mList.setEmptyView(mStandardEmptyView);
             }
         }
         mListShown = true;
         mList.setOnItemClickListener(mOnClickListener);
         if (mAdapter != null) {
-            setListAdapter(mAdapter);
+            ListAdapter adapter = mAdapter;
+            mAdapter = null;
+            setListAdapter(adapter);
         } else {
             // We are starting without an adapter, so assume we won't
             // have our data right away and start with the progress indicator.
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index 164141c..46a008d 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -223,6 +223,7 @@
         boolean mStarted;
         boolean mRetaining;
         boolean mRetainingStarted;
+        boolean mReportNextStart;
         boolean mDestroyed;
         boolean mListenerRegistered;
 
@@ -291,7 +292,7 @@
                 }
             }
 
-            if (mStarted && mHaveData) {
+            if (mStarted && mHaveData && !mReportNextStart) {
                 // This loader has retained its data, either completely across
                 // a configuration change or just whatever the last data set
                 // was after being restarted from a stop, and now at the point of
@@ -302,6 +303,17 @@
             }
         }
         
+        void reportStart() {
+            if (mStarted) {
+                if (mReportNextStart) {
+                    mReportNextStart = false;
+                    if (mHaveData) {
+                        callOnLoadFinished(mLoader, mData);
+                    }
+                }
+            }
+        }
+
         void stop() {
             if (DEBUG) Log.v(TAG, "  Stopping: " + this);
             mStarted = false;
@@ -449,10 +461,11 @@
                 writer.print(prefix); writer.print("mData="); writer.println(mData);
             }
             writer.print(prefix); writer.print("mStarted="); writer.print(mStarted);
-                    writer.print(" mRetaining="); writer.print(mRetaining);
+                    writer.print(" mReportNextStart="); writer.print(mReportNextStart);
                     writer.print(" mDestroyed="); writer.println(mDestroyed);
-            writer.print(prefix); writer.print("mListenerRegistered=");
-                    writer.println(mListenerRegistered);
+            writer.print(prefix); writer.print("mRetaining="); writer.print(mRetaining);
+                    writer.print(" mRetainingStarted="); writer.print(mRetainingStarted);
+                    writer.print(" mListenerRegistered="); writer.println(mListenerRegistered);
             if (mPendingLoader != null) {
                 writer.print(prefix); writer.println("Pending Loader ");
                         writer.print(mPendingLoader); writer.println(":");
@@ -740,6 +753,18 @@
         }
     }
     
+    void doReportNextStart() {
+        for (int i = mLoaders.size()-1; i >= 0; i--) {
+            mLoaders.valueAt(i).mReportNextStart = true;
+        }
+    }
+
+    void doReportStart() {
+        for (int i = mLoaders.size()-1; i >= 0; i--) {
+            mLoaders.valueAt(i).reportStart();
+        }
+    }
+
     void doDestroy() {
         if (!mRetaining) {
             if (DEBUG) Log.v(TAG, "Destroying Active in " + this);
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 113c610..7fd5a7d 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -25,6 +25,8 @@
 import android.graphics.ColorFilter;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
@@ -115,7 +117,9 @@
 
         @Override
         public void draw(Canvas canvas) {
-            canvas.drawBitmap(mBitmap, mDrawLeft, mDrawTop, null);
+            Paint paint = new Paint();
+            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+            canvas.drawBitmap(mBitmap, mDrawLeft, mDrawTop, paint);
         }
 
         @Override
@@ -245,40 +249,20 @@
                 if (fd != null) {
                     int width = params.getInt("width", 0);
                     int height = params.getInt("height", 0);
-                    
-                    if (width <= 0 || height <= 0) {
-                        // Degenerate case: no size requested, just load
-                        // bitmap as-is.
-                        Bitmap bm = null;
-                        try {
-                            bm = BitmapFactory.decodeFileDescriptor(
-                                   fd.getFileDescriptor(), null, null);
-                        } catch (OutOfMemoryError e) {
-                            Log.w(TAG, "Can't decode file", e);
-                        }
+
+                    try {
+                        BitmapFactory.Options options = new BitmapFactory.Options();
+                        Bitmap bm = BitmapFactory.decodeFileDescriptor(
+                                fd.getFileDescriptor(), null, options);
+                        return generateBitmap(context, bm, width, height);
+                    } catch (OutOfMemoryError e) {
+                        Log.w(TAG, "Can't decode file", e);
+                    } finally {
                         try {
                             fd.close();
                         } catch (IOException e) {
                         }
-                        if (bm != null) {
-                            bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
-                        }
-                        return bm;
                     }
-                    
-                    // Load the bitmap with full color depth, to preserve
-                    // quality for later processing.
-                    BitmapFactory.Options options = new BitmapFactory.Options();
-                    options.inDither = false;
-                    options.inPreferredConfig = Bitmap.Config.ARGB_8888;
-                    Bitmap bm = BitmapFactory.decodeFileDescriptor(
-                            fd.getFileDescriptor(), null, options);
-                    try {
-                        fd.close();
-                    } catch (IOException e) {
-                    }
-                    
-                    return generateBitmap(context, bm, width, height);
                 }
             } catch (RemoteException e) {
             }
@@ -292,42 +276,18 @@
                 if (is != null) {
                     int width = mService.getWidthHint();
                     int height = mService.getHeightHint();
-                    
-                    if (width <= 0 || height <= 0) {
-                        // Degenerate case: no size requested, just load
-                        // bitmap as-is.
-                        Bitmap bm = null;
-                        try {
-                            bm = BitmapFactory.decodeStream(is, null, null);
-                        } catch (OutOfMemoryError e) {
-                            Log.w(TAG, "Can't decode stream", e);
-                        }
+
+                    try {
+                        BitmapFactory.Options options = new BitmapFactory.Options();
+                        Bitmap bm = BitmapFactory.decodeStream(is, null, options);
+                        return generateBitmap(context, bm, width, height);
+                    } catch (OutOfMemoryError e) {
+                        Log.w(TAG, "Can't decode stream", e);
+                    } finally {
                         try {
                             is.close();
                         } catch (IOException e) {
                         }
-                        if (bm != null) {
-                            bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
-                        }
-                        return bm;
-                    }
-                    
-                    // Load the bitmap with full color depth, to preserve
-                    // quality for later processing.
-                    BitmapFactory.Options options = new BitmapFactory.Options();
-                    options.inDither = false;
-                    options.inPreferredConfig = Bitmap.Config.ARGB_8888;
-                    Bitmap bm = BitmapFactory.decodeStream(is, null, options);
-                    try {
-                        is.close();
-                    } catch (IOException e) {
-                    }
-                    
-                    try {
-                        return generateBitmap(context, bm, width, height);
-                    } catch (OutOfMemoryError e) {
-                        Log.w(TAG, "Can't generate default bitmap", e);
-                        return bm;
                     }
                 }
             } catch (RemoteException e) {
@@ -711,48 +671,55 @@
     
     static Bitmap generateBitmap(Context context, Bitmap bm, int width, int height) {
         if (bm == null) {
+            return null;
+        }
+
+        bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+
+        if (width <= 0 || height <= 0
+                || (bm.getWidth() == width && bm.getHeight() == height)) {
             return bm;
         }
-        bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
-        
+
         // This is the final bitmap we want to return.
-        // XXX We should get the pixel depth from the system (to match the
-        // physical display depth), when there is a way.
-        Bitmap newbm = Bitmap.createBitmap(width, height,
-                Bitmap.Config.RGB_565);
-        newbm.setDensity(DisplayMetrics.DENSITY_DEVICE);
-        Canvas c = new Canvas(newbm);
-        c.setDensity(DisplayMetrics.DENSITY_DEVICE);
-        Rect targetRect = new Rect();
-        targetRect.left = targetRect.top = 0;
-        targetRect.right = bm.getWidth();
-        targetRect.bottom = bm.getHeight();
-        
-        int deltaw = width - targetRect.right;
-        int deltah = height - targetRect.bottom;
-        
-        if (deltaw > 0 || deltah > 0) {
-            // We need to scale up so it covers the entire
-            // area.
-            float scale = 1.0f;
-            if (deltaw > deltah) {
-                scale = width / (float)targetRect.right;
-            } else {
-                scale = height / (float)targetRect.bottom;
+        try {
+            Bitmap newbm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+            newbm.setDensity(DisplayMetrics.DENSITY_DEVICE);
+
+            Canvas c = new Canvas(newbm);
+            Rect targetRect = new Rect();
+            targetRect.right = bm.getWidth();
+            targetRect.bottom = bm.getHeight();
+
+            int deltaw = width - targetRect.right;
+            int deltah = height - targetRect.bottom;
+
+            if (deltaw > 0 || deltah > 0) {
+                // We need to scale up so it covers the entire area.
+                float scale = 1.0f;
+                if (deltaw > deltah) {
+                    scale = width / (float)targetRect.right;
+                } else {
+                    scale = height / (float)targetRect.bottom;
+                }
+                targetRect.right = (int)(targetRect.right*scale);
+                targetRect.bottom = (int)(targetRect.bottom*scale);
+                deltaw = width - targetRect.right;
+                deltah = height - targetRect.bottom;
             }
-            targetRect.right = (int)(targetRect.right*scale);
-            targetRect.bottom = (int)(targetRect.bottom*scale);
-            deltaw = width - targetRect.right;
-            deltah = height - targetRect.bottom;
+
+            targetRect.offset(deltaw/2, deltah/2);
+
+            Paint paint = new Paint();
+            paint.setFilterBitmap(true);
+            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+            c.drawBitmap(bm, null, targetRect, paint);
+
+            bm.recycle();
+            return newbm;
+        } catch (OutOfMemoryError e) {
+            Log.w(TAG, "Can't generate default bitmap", e);
+            return bm;
         }
-        
-        targetRect.offset(deltaw/2, deltah/2);
-        Paint paint = new Paint();
-        paint.setFilterBitmap(true);
-        paint.setDither(true);
-        c.drawBitmap(bm, null, targetRect, paint);
-        
-        bm.recycle();
-        return newbm;
     }
 }
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 906a564..9bd45d3 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -277,24 +277,24 @@
     public int compatSmallestScreenWidthDp;
 
     /**
-     * @hide
+     * @hide Do not use. Implementation not finished.
      */
-    public static final int LAYOUT_DIRECTION_UNDEFINED = -1;
+    public static final int TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE = -1;
 
     /**
-     * @hide
+     * @hide Do not use. Implementation not finished.
      */
-    public static final int LAYOUT_DIRECTION_LTR = 0;
+    public static final int TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE = 0;
 
     /**
-     * @hide
+     * @hide Do not use. Implementation not finished.
      */
-    public static final int LAYOUT_DIRECTION_RTL = 1;
+    public static final int TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE = 1;
 
     /**
-     * @hide The layout direction associated to the current Locale
+     * @hide The text layout direction associated to the current Locale
      */
-    public int layoutDirection;
+    public int textLayoutDirection;
 
     /**
      * @hide Internal book-keeping.
@@ -322,7 +322,7 @@
         mnc = o.mnc;
         if (o.locale != null) {
             locale = (Locale) o.locale.clone();
-            layoutDirection = o.layoutDirection;
+            textLayoutDirection = o.textLayoutDirection;
         }
         userSetLocale = o.userSetLocale;
         touchscreen = o.touchscreen;
@@ -358,6 +358,11 @@
         } else {
             sb.append(" (no locale)");
         }
+        switch (textLayoutDirection) {
+            case TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE: sb.append(" ?layoutdir"); break;
+            case TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE: sb.append(" rtl"); break;
+            default: sb.append(" layoutdir="); sb.append(textLayoutDirection); break;
+        }
         if (smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
             sb.append(" sw"); sb.append(smallestScreenWidthDp); sb.append("dp");
         } else {
@@ -450,11 +455,6 @@
             case NAVIGATIONHIDDEN_YES: sb.append("/h"); break;
             default: sb.append("/"); sb.append(navigationHidden); break;
         }
-        switch (layoutDirection) {
-            case LAYOUT_DIRECTION_UNDEFINED: sb.append(" ?layoutdir"); break;
-            case LAYOUT_DIRECTION_LTR: sb.append(" ltr"); break;
-            case LAYOUT_DIRECTION_RTL: sb.append(" rtl"); break;
-        }
         if (seq != 0) {
             sb.append(" s.");
             sb.append(seq);
@@ -483,8 +483,8 @@
         screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED;
         screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED;
         smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
+        textLayoutDirection = TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE;
         seq = 0;
-        layoutDirection = LAYOUT_DIRECTION_LTR;
     }
 
     /** {@hide} */
@@ -519,7 +519,7 @@
             changed |= ActivityInfo.CONFIG_LOCALE;
             locale = delta.locale != null
                     ? (Locale) delta.locale.clone() : null;
-            layoutDirection = getLayoutDirectionFromLocale(locale);
+            textLayoutDirection = getLayoutDirectionFromLocale(locale);
         }
         if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))
         {
@@ -611,23 +611,25 @@
     /**
      * Return the layout direction for a given Locale
      * @param locale the Locale for which we want the layout direction. Can be null.
-     * @return the layout direction. This may be one of {@link #LAYOUT_DIRECTION_UNDEFINED},
-     * {@link #LAYOUT_DIRECTION_LTR} or {@link #LAYOUT_DIRECTION_RTL}.
+     * @return the layout direction. This may be one of:
+     * {@link #TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE} or
+     * {@link #TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE} or
+     * {@link #TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE}.
      *
      * @hide
      */
     public static int getLayoutDirectionFromLocale(Locale locale) {
-        if (locale == null || locale.equals(Locale.ROOT)) return LAYOUT_DIRECTION_UNDEFINED;
+        if (locale == null || locale.equals(Locale.ROOT)) return TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE;
         // Be careful: this code will need to be changed when vertical scripts will be supported
         // OR if ICU4C is updated to have the "likelySubtags" file
         switch(Character.getDirectionality(locale.getDisplayName(locale).charAt(0))) {
             case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
-                return LAYOUT_DIRECTION_LTR;
+                return TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE;
             case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
             case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
-                return LAYOUT_DIRECTION_RTL;
+                return TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE;
             default:
-                return LAYOUT_DIRECTION_UNDEFINED;
+                return TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE;
         }
     }
 
@@ -810,7 +812,7 @@
         dest.writeInt(compatScreenWidthDp);
         dest.writeInt(compatScreenHeightDp);
         dest.writeInt(compatSmallestScreenWidthDp);
-        dest.writeInt(layoutDirection);
+        dest.writeInt(textLayoutDirection);
         dest.writeInt(seq);
     }
 
@@ -838,7 +840,7 @@
         compatScreenWidthDp = source.readInt();
         compatScreenHeightDp = source.readInt();
         compatSmallestScreenWidthDp = source.readInt();
-        layoutDirection = source.readInt();
+        textLayoutDirection = source.readInt();
         seq = source.readInt();
     }
     
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index c1f3530..82495e3 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.net.INetworkPolicyListener;
+import android.net.NetworkPolicy;
 
 /**
  * Interface that creates and modifies network policy rules.
@@ -33,6 +34,7 @@
     void registerListener(INetworkPolicyListener listener);
     void unregisterListener(INetworkPolicyListener listener);
 
-    // TODO: build API to surface stats details for settings UI
+    void setNetworkPolicies(in NetworkPolicy[] policies);
+    NetworkPolicy[] getNetworkPolicies();
 
 }
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index d05c9d3..288112a 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -27,6 +27,8 @@
     /** Return historical stats for specific UID traffic that matches template. */
     NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate);
 
+    /** Return usage summary for traffic that matches template. */
+    NetworkStats getSummaryForNetwork(long start, long end, int networkTemplate, String subscriberId);
     /** Return usage summary per UID for traffic that matches template. */
     NetworkStats getSummaryForAllUid(long start, long end, int networkTemplate);
 
diff --git a/core/java/android/net/NetworkPolicy.aidl b/core/java/android/net/NetworkPolicy.aidl
new file mode 100644
index 0000000..dbabb0608
--- /dev/null
+++ b/core/java/android/net/NetworkPolicy.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable NetworkPolicy;
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
new file mode 100644
index 0000000..1899281
--- /dev/null
+++ b/core/java/android/net/NetworkPolicy.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Policy for a specific network, including usage cycle and limits to be
+ * enforced.
+ *
+ * @hide
+ */
+public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
+    public final int networkTemplate;
+    public final String subscriberId;
+    public int cycleDay;
+    public long warningBytes;
+    public long limitBytes;
+
+    public static final long WARNING_DISABLED = -1;
+    public static final long LIMIT_DISABLED = -1;
+
+    public NetworkPolicy(int networkTemplate, String subscriberId, int cycleDay, long warningBytes,
+            long limitBytes) {
+        this.networkTemplate = networkTemplate;
+        this.subscriberId = subscriberId;
+        this.cycleDay = cycleDay;
+        this.warningBytes = warningBytes;
+        this.limitBytes = limitBytes;
+    }
+
+    public NetworkPolicy(Parcel in) {
+        networkTemplate = in.readInt();
+        subscriberId = in.readString();
+        cycleDay = in.readInt();
+        warningBytes = in.readLong();
+        limitBytes = in.readLong();
+    }
+
+    /** {@inheritDoc} */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(networkTemplate);
+        dest.writeString(subscriberId);
+        dest.writeInt(cycleDay);
+        dest.writeLong(warningBytes);
+        dest.writeLong(limitBytes);
+    }
+
+    /** {@inheritDoc} */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(NetworkPolicy another) {
+        if (another == null || another.limitBytes == LIMIT_DISABLED) {
+            // other value is missing or disabled; we win
+            return -1;
+        }
+        if (limitBytes == LIMIT_DISABLED || another.limitBytes < limitBytes) {
+            // we're disabled or other limit is smaller; they win
+            return 1;
+        }
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return "NetworkPolicy: networkTemplate=" + networkTemplate + ", cycleDay=" + cycleDay
+                + ", warningBytes=" + warningBytes + ", limitBytes=" + limitBytes;
+    }
+
+    public static final Creator<NetworkPolicy> CREATOR = new Creator<NetworkPolicy>() {
+        public NetworkPolicy createFromParcel(Parcel in) {
+            return new NetworkPolicy(in);
+        }
+
+        public NetworkPolicy[] newArray(int size) {
+            return new NetworkPolicy[size];
+        }
+    };
+}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index dd7c1b0..13ece40 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -16,8 +16,11 @@
 
 package android.net;
 
+import static android.text.format.Time.MONTH_DAY;
+
 import android.content.Context;
 import android.os.RemoteException;
+import android.text.format.Time;
 
 import java.io.PrintWriter;
 
@@ -51,6 +54,23 @@
         return (NetworkPolicyManager) context.getSystemService(Context.NETWORK_POLICY_SERVICE);
     }
 
+    /** {@hide} */
+    public void setNetworkPolicies(NetworkPolicy[] policies) {
+        try {
+            mService.setNetworkPolicies(policies);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /** {@hide} */
+    public NetworkPolicy[] getNetworkPolicies() {
+        try {
+            return mService.getNetworkPolicies();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
     /**
      * Set policy flags for specific UID.
      *
@@ -71,7 +91,83 @@
             return POLICY_NONE;
         }
     }
-    
+
+    /**
+     * Compute the last cycle boundary for the given {@link NetworkPolicy}. For
+     * example, if cycle day is 20th, and today is June 15th, it will return May
+     * 20th. When cycle day doesn't exist in current month, it snaps to the 1st
+     * of following month.
+     *
+     * @hide
+     */
+    public static long computeLastCycleBoundary(long currentTime, NetworkPolicy policy) {
+        final Time now = new Time(Time.TIMEZONE_UTC);
+        now.set(currentTime);
+
+        // first, find cycle boundary for current month
+        final Time cycle = new Time(now);
+        cycle.hour = cycle.minute = cycle.second = 0;
+        snapToCycleDay(cycle, policy.cycleDay);
+
+        if (Time.compare(cycle, now) >= 0) {
+            // cycle boundary is beyond now, use last cycle boundary; start by
+            // pushing ourselves squarely into last month.
+            final Time lastMonth = new Time(now);
+            lastMonth.hour = lastMonth.minute = lastMonth.second = 0;
+            lastMonth.monthDay = 1;
+            lastMonth.month -= 1;
+            lastMonth.normalize(true);
+
+            cycle.set(lastMonth);
+            snapToCycleDay(cycle, policy.cycleDay);
+        }
+
+        return cycle.toMillis(true);
+    }
+
+    /** {@hide} */
+    public static long computeNextCycleBoundary(long currentTime, NetworkPolicy policy) {
+        final Time now = new Time(Time.TIMEZONE_UTC);
+        now.set(currentTime);
+
+        // first, find cycle boundary for current month
+        final Time cycle = new Time(now);
+        cycle.hour = cycle.minute = cycle.second = 0;
+        snapToCycleDay(cycle, policy.cycleDay);
+
+        if (Time.compare(cycle, now) <= 0) {
+            // cycle boundary is before now, use next cycle boundary; start by
+            // pushing ourselves squarely into next month.
+            final Time nextMonth = new Time(now);
+            nextMonth.hour = nextMonth.minute = nextMonth.second = 0;
+            nextMonth.monthDay = 1;
+            nextMonth.month += 1;
+            nextMonth.normalize(true);
+
+            cycle.set(nextMonth);
+            snapToCycleDay(cycle, policy.cycleDay);
+        }
+
+        return cycle.toMillis(true);
+    }
+
+    /**
+     * Snap to the cycle day for the current month given; when cycle day doesn't
+     * exist, it snaps to 1st of following month.
+     *
+     * @hide
+     */
+    public static void snapToCycleDay(Time time, int cycleDay) {
+        if (cycleDay > time.getActualMaximum(MONTH_DAY)) {
+            // cycle day isn't valid this month; snap to 1st of next month
+            time.month += 1;
+            time.monthDay = 1;
+        } else {
+            time.monthDay = cycleDay;
+        }
+        time.normalize(true);
+    }
+
     /** {@hide} */
     public static void dumpPolicy(PrintWriter fout, int policy) {
         fout.write("[");
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 6354e9a..60f740e 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -23,6 +23,7 @@
 
 import java.io.CharArrayWriter;
 import java.io.PrintWriter;
+import java.util.Arrays;
 import java.util.HashSet;
 
 /**
@@ -48,74 +49,60 @@
      * generated.
      */
     public final long elapsedRealtime;
-    public final String[] iface;
-    public final int[] uid;
-    public final long[] rx;
-    public final long[] tx;
+    public int size;
+    public String[] iface;
+    public int[] uid;
+    public long[] rx;
+    public long[] tx;
 
     // TODO: add fg/bg stats once reported by kernel
 
-    private NetworkStats(long elapsedRealtime, String[] iface, int[] uid, long[] rx, long[] tx) {
+    public NetworkStats(long elapsedRealtime, int initialSize) {
         this.elapsedRealtime = elapsedRealtime;
-        this.iface = iface;
-        this.uid = uid;
-        this.rx = rx;
-        this.tx = tx;
+        this.size = 0;
+        this.iface = new String[initialSize];
+        this.uid = new int[initialSize];
+        this.rx = new long[initialSize];
+        this.tx = new long[initialSize];
     }
 
     public NetworkStats(Parcel parcel) {
         elapsedRealtime = parcel.readLong();
+        size = parcel.readInt();
         iface = parcel.createStringArray();
         uid = parcel.createIntArray();
         rx = parcel.createLongArray();
         tx = parcel.createLongArray();
     }
 
-    public static class Builder {
-        private long mElapsedRealtime;
-        private final String[] mIface;
-        private final int[] mUid;
-        private final long[] mRx;
-        private final long[] mTx;
-
-        private int mIndex = 0;
-
-        public Builder(long elapsedRealtime, int size) {
-            mElapsedRealtime = elapsedRealtime;
-            mIface = new String[size];
-            mUid = new int[size];
-            mRx = new long[size];
-            mTx = new long[size];
+    public NetworkStats addEntry(String iface, int uid, long rx, long tx) {
+        if (size >= this.iface.length) {
+            final int newLength = Math.max(this.iface.length, 10) * 3 / 2;
+            this.iface = Arrays.copyOf(this.iface, newLength);
+            this.uid = Arrays.copyOf(this.uid, newLength);
+            this.rx = Arrays.copyOf(this.rx, newLength);
+            this.tx = Arrays.copyOf(this.tx, newLength);
         }
 
-        public Builder addEntry(String iface, int uid, long rx, long tx) {
-            mIface[mIndex] = iface;
-            mUid[mIndex] = uid;
-            mRx[mIndex] = rx;
-            mTx[mIndex] = tx;
-            mIndex++;
-            return this;
-        }
+        this.iface[size] = iface;
+        this.uid[size] = uid;
+        this.rx[size] = rx;
+        this.tx[size] = tx;
+        size++;
 
-        public NetworkStats build() {
-            if (mIndex != mIface.length) {
-                throw new IllegalArgumentException("unexpected number of entries");
-            }
-            return new NetworkStats(mElapsedRealtime, mIface, mUid, mRx, mTx);
-        }
+        return this;
     }
 
+    @Deprecated
     public int length() {
-        // length is identical for all fields
-        return iface.length;
+        return size;
     }
 
     /**
      * Find first stats index that matches the requested parameters.
      */
     public int findIndex(String iface, int uid) {
-        final int length = length();
-        for (int i = 0; i < length; i++) {
+        for (int i = 0; i < size; i++) {
             if (equal(iface, this.iface[i]) && uid == this.uid[i]) {
                 return i;
             }
@@ -195,9 +182,8 @@
         }
 
         // result will have our rows, and elapsed time between snapshots
-        final int length = length();
-        final NetworkStats.Builder result = new NetworkStats.Builder(deltaRealtime, length);
-        for (int i = 0; i < length; i++) {
+        final NetworkStats result = new NetworkStats(deltaRealtime, size);
+        for (int i = 0; i < size; i++) {
             final String iface = this.iface[i];
             final int uid = this.uid[i];
 
@@ -221,7 +207,7 @@
             }
         }
 
-        return result.build();
+        return result;
     }
 
     private static boolean equal(Object a, Object b) {
@@ -255,6 +241,7 @@
     /** {@inheritDoc} */
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeLong(elapsedRealtime);
+        dest.writeInt(size);
         dest.writeStringArray(iface);
         dest.writeIntArray(uid);
         dest.writeLongArray(rx);
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index a697e96..5fa8e21 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -53,11 +53,15 @@
     public long[] tx;
 
     public NetworkStatsHistory(long bucketDuration) {
+        this(bucketDuration, 10);
+    }
+
+    public NetworkStatsHistory(long bucketDuration, int initialSize) {
         this.bucketDuration = bucketDuration;
-        bucketStart = new long[0];
-        rx = new long[0];
-        tx = new long[0];
-        bucketCount = bucketStart.length;
+        bucketStart = new long[initialSize];
+        rx = new long[initialSize];
+        tx = new long[initialSize];
+        bucketCount = 0;
     }
 
     public NetworkStatsHistory(Parcel in) {
@@ -168,8 +172,8 @@
      */
     private void insertBucket(int index, long start) {
         // create more buckets when needed
-        if (bucketCount + 1 > bucketStart.length) {
-            final int newLength = bucketStart.length + 10;
+        if (bucketCount >= bucketStart.length) {
+            final int newLength = Math.max(bucketStart.length, 10) * 3 / 2;
             bucketStart = Arrays.copyOf(bucketStart, newLength);
             rx = Arrays.copyOf(rx, newLength);
             tx = Arrays.copyOf(tx, newLength);
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 8e50cd5..5c4b258 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -240,7 +240,6 @@
 
     /**
      * Sets the {@link TrustManager}s to be used for connections made by this factory.
-     * @hide
      */
     public void setTrustManagers(TrustManager[] trustManager) {
         mTrustManagers = trustManager;
@@ -253,7 +252,6 @@
 
     /**
      * Sets the {@link KeyManager}s to be used for connections made by this factory.
-     * @hide
      */
     public void setKeyManagers(KeyManager[] keyManagers) {
         mKeyManagers = keyManagers;
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 8a688d5..3725fa6 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -41,11 +41,9 @@
      */
     public final static int UNSUPPORTED = -1;
 
-    // TODO: find better home for these template constants
-
     /**
      * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
-     * networks together. Only uses statistics for currently active IMSI.
+     * networks together. Only uses statistics for requested IMSI.
      *
      * @hide
      */
@@ -54,7 +52,7 @@
     /**
      * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
      * networks together that roughly meet a "3G" definition, or lower. Only
-     * uses statistics for currently active IMSI.
+     * uses statistics for requested IMSI.
      *
      * @hide
      */
@@ -63,7 +61,7 @@
     /**
      * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
      * networks together that meet a "4G" definition. Only uses statistics for
-     * currently active IMSI.
+     * requested IMSI.
      *
      * @hide
      */
@@ -184,6 +182,17 @@
         }
     }
 
+    /** {@hide} */
+    public static boolean isNetworkTemplateMobile(int networkTemplate) {
+        switch (networkTemplate) {
+            case TEMPLATE_MOBILE_3G_LOWER:
+            case TEMPLATE_MOBILE_4G:
+            case TEMPLATE_MOBILE_ALL:
+                return true;
+        }
+        return false;
+    }
+
     /**
      * Get the total number of packets transmitted through the mobile interface.
      *
diff --git a/core/java/android/nfc/INfcTag.aidl b/core/java/android/nfc/INfcTag.aidl
index b66035f..aa5937e 100644
--- a/core/java/android/nfc/INfcTag.aidl
+++ b/core/java/android/nfc/INfcTag.aidl
@@ -43,7 +43,6 @@
     int formatNdef(int nativeHandle, in byte[] key);
     Tag rediscover(int nativehandle);
 
-    void setIsoDepTimeout(int timeout);
-    void setFelicaTimeout(int timeout);
+    int setTimeout(int technology, int timeout);
     void resetTimeouts();
 }
diff --git a/core/java/android/nfc/tech/IsoDep.java b/core/java/android/nfc/tech/IsoDep.java
index 38b2bbd..d02086f 100644
--- a/core/java/android/nfc/tech/IsoDep.java
+++ b/core/java/android/nfc/tech/IsoDep.java
@@ -16,6 +16,7 @@
 
 package android.nfc.tech;
 
+import android.nfc.ErrorCodes;
 import android.nfc.Tag;
 import android.os.Bundle;
 import android.os.RemoteException;
@@ -90,7 +91,10 @@
      */
     public void setTimeout(int timeout) {
         try {
-            mTag.getTagService().setIsoDepTimeout(timeout);
+            int err = mTag.getTagService().setTimeout(TagTechnology.ISO_DEP, timeout);
+            if (err != ErrorCodes.SUCCESS) {
+                throw new IllegalArgumentException("The supplied timeout is not valid");
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "NFC service dead", e);
         }
diff --git a/core/java/android/nfc/tech/MifareClassic.java b/core/java/android/nfc/tech/MifareClassic.java
index c4b7718..5cafe5b 100644
--- a/core/java/android/nfc/tech/MifareClassic.java
+++ b/core/java/android/nfc/tech/MifareClassic.java
@@ -16,9 +16,11 @@
 
 package android.nfc.tech;
 
+import android.nfc.ErrorCodes;
 import android.nfc.Tag;
 import android.nfc.TagLostException;
 import android.os.RemoteException;
+import android.util.Log;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
@@ -69,6 +71,8 @@
  * require the {@link android.Manifest.permission#NFC} permission.
  */
 public final class MifareClassic extends BasicTagTechnology {
+    private static final String TAG = "NFC";
+
     /**
      * The default factory key.
      */
@@ -568,6 +572,31 @@
         return transceive(data, true);
     }
 
+    /**
+     * Set the timeout of {@link #transceive} in milliseconds.
+     * <p>The timeout only applies to MifareUltralight {@link #transceive},
+     * and is reset to a default value when {@link #close} is called.
+     * <p>Setting a longer timeout may be useful when performing
+     * transactions that require a long processing time on the tag
+     * such as key generation.
+     *
+     * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
+     *
+     * @param timeout timeout value in milliseconds
+     * @hide
+     */
+    // TODO Unhide for ICS
+    public void setTimeout(int timeout) {
+        try {
+            int err = mTag.getTagService().setTimeout(TagTechnology.MIFARE_CLASSIC, timeout);
+            if (err != ErrorCodes.SUCCESS) {
+                throw new IllegalArgumentException("The supplied timeout is not valid");
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "NFC service dead", e);
+        }
+    }
+
     private static void validateSector(int sector) {
         // Do not be too strict on upper bounds checking, since some cards
         // have more addressable memory than they report. For example,
diff --git a/core/java/android/nfc/tech/MifareUltralight.java b/core/java/android/nfc/tech/MifareUltralight.java
index 6c2754b..3d4cdd1 100644
--- a/core/java/android/nfc/tech/MifareUltralight.java
+++ b/core/java/android/nfc/tech/MifareUltralight.java
@@ -16,10 +16,12 @@
 
 package android.nfc.tech;
 
+import android.nfc.ErrorCodes;
 import android.nfc.Tag;
 import android.nfc.TagLostException;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.util.Log;
 
 import java.io.IOException;
 
@@ -57,6 +59,8 @@
  * require the {@link android.Manifest.permission#NFC} permission.
  */
 public final class MifareUltralight extends BasicTagTechnology {
+    private static final String TAG = "NFC";
+
     /** A MIFARE Ultralight compatible tag of unknown type */
     public static final int TYPE_UNKNOWN = -1;
     /** A MIFARE Ultralight tag */
@@ -208,6 +212,32 @@
         return transceive(data, true);
     }
 
+    /**
+     * Set the timeout of {@link #transceive} in milliseconds.
+     * <p>The timeout only applies to MifareUltralight {@link #transceive},
+     * and is reset to a default value when {@link #close} is called.
+     * <p>Setting a longer timeout may be useful when performing
+     * transactions that require a long processing time on the tag
+     * such as key generation.
+     *
+     * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
+     *
+     * @param timeout timeout value in milliseconds
+     * @hide
+     */
+    // TODO Unhide for ICS
+    public void setTimeout(int timeout) {
+        try {
+            int err = mTag.getTagService().setTimeout(
+                    TagTechnology.MIFARE_ULTRALIGHT, timeout);
+            if (err != ErrorCodes.SUCCESS) {
+                throw new IllegalArgumentException("The supplied timeout is not valid");
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "NFC service dead", e);
+        }
+    }
+
     private static void validatePageIndex(int pageIndex) {
         // Do not be too strict on upper bounds checking, since some cards
         // may have more addressable memory than they report.
diff --git a/core/java/android/nfc/tech/NfcA.java b/core/java/android/nfc/tech/NfcA.java
index 1843eae..08095e6 100644
--- a/core/java/android/nfc/tech/NfcA.java
+++ b/core/java/android/nfc/tech/NfcA.java
@@ -16,9 +16,11 @@
 
 package android.nfc.tech;
 
+import android.nfc.ErrorCodes;
 import android.nfc.Tag;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.util.Log;
 
 import java.io.IOException;
 
@@ -33,6 +35,8 @@
  * require the {@link android.Manifest.permission#NFC} permission.
  */
 public final class NfcA extends BasicTagTechnology {
+    private static final String TAG = "NFC";
+
     /** @hide */
     public static final String EXTRA_SAK = "sak";
     /** @hide */
@@ -112,4 +116,29 @@
     public byte[] transceive(byte[] data) throws IOException {
         return transceive(data, true);
     }
+
+    /**
+     * Set the timeout of {@link #transceive} in milliseconds.
+     * <p>The timeout only applies to NfcA {@link #transceive}, and is
+     * reset to a default value when {@link #close} is called.
+     * <p>Setting a longer timeout may be useful when performing
+     * transactions that require a long processing time on the tag
+     * such as key generation.
+     *
+     * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
+     *
+     * @param timeout timeout value in milliseconds
+     * @hide
+     */
+    // TODO Unhide for ICS
+    public void setTimeout(int timeout) {
+        try {
+            int err = mTag.getTagService().setTimeout(TagTechnology.NFC_A, timeout);
+            if (err != ErrorCodes.SUCCESS) {
+                throw new IllegalArgumentException("The supplied timeout is not valid");
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "NFC service dead", e);
+        }
+    }
 }
diff --git a/core/java/android/nfc/tech/NfcF.java b/core/java/android/nfc/tech/NfcF.java
index 250c9b3..85abf89 100644
--- a/core/java/android/nfc/tech/NfcF.java
+++ b/core/java/android/nfc/tech/NfcF.java
@@ -16,6 +16,7 @@
 
 package android.nfc.tech;
 
+import android.nfc.ErrorCodes;
 import android.nfc.Tag;
 import android.os.Bundle;
 import android.os.RemoteException;
@@ -131,7 +132,10 @@
     // TODO Unhide for ICS
     public void setTimeout(int timeout) {
         try {
-            mTag.getTagService().setFelicaTimeout(timeout);
+            int err = mTag.getTagService().setTimeout(TagTechnology.NFC_F, timeout);
+            if (err != ErrorCodes.SUCCESS) {
+                throw new IllegalArgumentException("The supplied timeout is not valid");
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "NFC service dead", e);
         }
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 557e53f..844ed6a 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -249,9 +249,10 @@
      * freed.
      */
     public void recycle() {
+        clearForRecycle();
+
         synchronized (sPoolSync) {
             if (sPoolSize < MAX_POOL_SIZE) {
-                clearForRecycle();
                 next = sPool;
                 sPool = this;
                 sPoolSize++;
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 01c640a..68385b4 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1827,19 +1827,30 @@
             new HashMap<Class, Integer>();
 
     /**
+     * Returns an object that is used to track instances of activites.
+     * The activity should store a reference to the tracker object in one of its fields.
+     * @hide
+     */
+    public static Object trackActivity(Object instance) {
+        return new InstanceTracker(instance);
+    }
+
+    /**
      * @hide
      */
     public static void incrementExpectedActivityCount(Class klass) {
-        if (klass == null || (sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) {
+        if (klass == null) {
             return;
         }
+
         synchronized (StrictMode.class) {
+            if ((sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) {
+                return;
+            }
+
             Integer expected = sExpectedActivityInstanceCount.get(klass);
             Integer newExpected = expected == null ? 1 : expected + 1;
             sExpectedActivityInstanceCount.put(klass, newExpected);
-            // Note: adding 1 here to give some breathing room during
-            // orientation changes.  (shouldn't be necessary, though?)
-            setExpectedClassInstanceCount(klass, newExpected + 1);
         }
     }
 
@@ -1847,31 +1858,48 @@
      * @hide
      */
     public static void decrementExpectedActivityCount(Class klass) {
-        if (klass == null || (sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) {
+        if (klass == null) {
             return;
         }
+
+        final int limit;
         synchronized (StrictMode.class) {
+            if ((sVmPolicy.mask & DETECT_VM_ACTIVITY_LEAKS) == 0) {
+                return;
+            }
+
             Integer expected = sExpectedActivityInstanceCount.get(klass);
-            Integer newExpected = (expected == null || expected == 0) ? 0 : expected - 1;
+            int newExpected = (expected == null || expected == 0) ? 0 : expected - 1;
             if (newExpected == 0) {
                 sExpectedActivityInstanceCount.remove(klass);
             } else {
                 sExpectedActivityInstanceCount.put(klass, newExpected);
             }
+
             // Note: adding 1 here to give some breathing room during
             // orientation changes.  (shouldn't be necessary, though?)
-            setExpectedClassInstanceCount(klass, newExpected + 1);
+            limit = newExpected + 1;
         }
-    }
 
-    /**
-     * @hide
-     */
-    public static void setExpectedClassInstanceCount(Class klass, int count) {
-        synchronized (StrictMode.class) {
-            setVmPolicy(new VmPolicy.Builder(sVmPolicy)
-                        .setClassInstanceLimit(klass, count)
-                        .build());
+        // Quick check.
+        int actual = InstanceTracker.getInstanceCount(klass);
+        if (actual <= limit) {
+            return;
+        }
+
+        // Do a GC and explicit count to double-check.
+        // This is the work that we are trying to avoid by tracking the object instances
+        // explicity.  Running an explicit GC can be expensive (80ms) and so can walking
+        // the heap to count instance (30ms).  This extra work can make the system feel
+        // noticeably less responsive during orientation changes when activities are
+        // being restarted.  Granted, it is only a problem when StrictMode is enabled
+        // but it is annoying.
+        Runtime.getRuntime().gc();
+
+        long instances = VMDebug.countInstancesOfClass(klass, false);
+        if (instances > limit) {
+            Throwable tr = new InstanceCountViolation(klass, instances, limit);
+            onVmPolicyViolation(tr.getMessage(), tr);
         }
     }
 
@@ -2095,4 +2123,47 @@
             mLimit = limit;
         }
     }
+
+    private static final class InstanceTracker {
+        private static final HashMap<Class<?>, Integer> sInstanceCounts =
+                new HashMap<Class<?>, Integer>();
+
+        private final Class<?> mKlass;
+
+        public InstanceTracker(Object instance) {
+            mKlass = instance.getClass();
+
+            synchronized (sInstanceCounts) {
+                final Integer value = sInstanceCounts.get(mKlass);
+                final int newValue = value != null ? value + 1 : 1;
+                sInstanceCounts.put(mKlass, newValue);
+            }
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            try {
+                synchronized (sInstanceCounts) {
+                    final Integer value = sInstanceCounts.get(mKlass);
+                    if (value != null) {
+                        final int newValue = value - 1;
+                        if (newValue > 0) {
+                            sInstanceCounts.put(mKlass, newValue);
+                        } else {
+                            sInstanceCounts.remove(mKlass);
+                        }
+                    }
+                }
+            } finally {
+                super.finalize();
+            }
+        }
+
+        public static int getInstanceCount(Class<?> klass) {
+            synchronized (sInstanceCounts) {
+                final Integer value = sInstanceCounts.get(klass);
+                return value != null ? value : 0;
+            }
+        }
+    }
 }
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index bb6ed9c..3b2e6b6 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -178,9 +178,8 @@
      * have specific uses which are expected to be consistent by the app and
      * sync adapter.
      *
-     * @hide
      */
-    public interface SyncColumns extends CalendarSyncColumns {
+    protected interface SyncColumns extends CalendarSyncColumns {
         /**
          * The account that was used to sync the entry to the device. If the
          * account_type is not {@link #ACCOUNT_TYPE_LOCAL} then the name and
@@ -223,7 +222,7 @@
 
         /**
          * If set to 1 this causes events on this calendar to be duplicated with
-         * {@link EventsColumns#LAST_SYNCED} set to 1 whenever the event
+         * {@link Events#LAST_SYNCED} set to 1 whenever the event
          * transitions from non-dirty to dirty. The duplicated event will not be
          * expanded in the instances table and will only show up in sync adapter
          * queries of the events table. It will also be deleted when the
@@ -236,7 +235,7 @@
     /**
      * Columns specific to the Calendars Uri that other Uris can query.
      */
-    private interface CalendarsColumns {
+    protected interface CalendarsColumns {
         /**
          * The color of the calendar
          * <P>Type: INTEGER (color value)</P>
@@ -549,7 +548,7 @@
     /**
      * Columns from the Attendees table that other tables join into themselves.
      */
-    private interface AttendeesColumns {
+    protected interface AttendeesColumns {
 
         /**
          * The id of the event. Column name.
@@ -639,7 +638,7 @@
     /**
      * Columns from the Events table that other tables join into themselves.
      */
-    private interface EventsColumns {
+    protected interface EventsColumns {
 
         /**
          * The {@link Calendars#_ID} of the calendar the event belongs to.
@@ -1525,7 +1524,7 @@
      * time zone for the instaces. These settings are stored using a key/value
      * scheme.
      */
-    private interface CalendarCacheColumns {
+    protected interface CalendarCacheColumns {
         /**
          * The key for the setting. Keys are defined in {@link CalendarCache}.
          */
@@ -1597,7 +1596,7 @@
      * the Instances table and these are all stored in the first (and only)
      * row of the CalendarMetaData table.
      */
-    private interface CalendarMetaDataColumns {
+    protected interface CalendarMetaDataColumns {
         /**
          * The local timezone that was used for precomputing the fields
          * in the Instances table.
@@ -1637,7 +1636,7 @@
     public static final class CalendarMetaData implements CalendarMetaDataColumns, BaseColumns {
     }
 
-    private interface EventDaysColumns {
+    protected interface EventDaysColumns {
         /**
          * The Julian starting day number. Column name.
          * <P>Type: INTEGER (int)</P>
@@ -1655,7 +1654,7 @@
      * Fields and helpers for querying for a list of days that contain events.
      */
     public static final class EventDays implements EventDaysColumns {
-        private static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
+        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
                 + "/instances/groupbyday");
 
         /**
@@ -1690,7 +1689,7 @@
         }
     }
 
-    private interface RemindersColumns {
+    protected interface RemindersColumns {
         /**
          * The event the reminder belongs to. Column name.
          * <P>Type: INTEGER (foreign key to the Events table)</P>
@@ -1755,7 +1754,7 @@
         }
     }
 
-    private interface CalendarAlertsColumns {
+    protected interface CalendarAlertsColumns {
         /**
          * The event that the alert belongs to. Column name.
          * <P>Type: INTEGER (foreign key to the Events table)</P>
@@ -2069,7 +2068,7 @@
         }
     }
 
-    private interface ExtendedPropertiesColumns {
+    protected interface ExtendedPropertiesColumns {
         /**
          * The event the extended property belongs to. Column name.
          * <P>Type: INTEGER (foreign key to the Events table)</P>
@@ -2128,7 +2127,7 @@
     /**
      * Columns from the EventsRawTimes table
      */
-    private interface EventsRawTimesColumns {
+    protected interface EventsRawTimesColumns {
         /**
          * The corresponding event id. Column name.
          * <P>Type: INTEGER (long)</P>
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6ab7738..1025b20 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3800,13 +3800,13 @@
         /** {@hide} */
         public static final String NETSTATS_PERSIST_THRESHOLD = "netstats_persist_threshold";
         /** {@hide} */
-        public static final String NETSTATS_SUMMARY_BUCKET_DURATION = "netstats_summary_bucket_duration";
+        public static final String NETSTATS_NETWORK_BUCKET_DURATION = "netstats_network_bucket_duration";
         /** {@hide} */
-        public static final String NETSTATS_SUMMARY_MAX_HISTORY = "netstats_summary_max_history";
+        public static final String NETSTATS_NETWORK_MAX_HISTORY = "netstats_network_max_history";
         /** {@hide} */
-        public static final String NETSTATS_DETAIL_BUCKET_DURATION = "netstats_detail_bucket_duration";
+        public static final String NETSTATS_UID_BUCKET_DURATION = "netstats_uid_bucket_duration";
         /** {@hide} */
-        public static final String NETSTATS_DETAIL_MAX_HISTORY = "netstats_detail_max_history";
+        public static final String NETSTATS_UID_MAX_HISTORY = "netstats_uid_max_history";
 
         /**
          * @hide
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index c397af9..376e0bb 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -19,6 +19,7 @@
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.provider.CallLog.Calls;
+
 /**
  * The contract between the voicemail provider and applications. Contains
  * definitions for the supported URIs and columns.
@@ -45,13 +46,17 @@
  */
 // TODO: unhide when the API is approved by android-api-council
 public class VoicemailContract {
+    /** Not instantiable. */
+    private VoicemailContract() {
+    }
+
     /** The authority used by the voicemail provider. */
     public static final String AUTHORITY = "com.android.voicemail";
 
     /** URI to insert/retrieve all voicemails. */
     public static final Uri CONTENT_URI =
             Uri.parse("content://" + AUTHORITY + "/voicemail");
-    /** URI to insert/retrieve voicemails by a given voicemai source. */
+    /** URI to insert/retrieve voicemails by a given voicemail source. */
     public static final Uri CONTENT_URI_SOURCE =
             Uri.parse("content://" + AUTHORITY + "/voicemail/source/");
 
@@ -72,6 +77,10 @@
             "vnd.android.cursor.dir/voicemails";
 
     public static final class Voicemails implements BaseColumns {
+        /** Not instantiable. */
+        private Voicemails() {
+        }
+
         /**
          * Phone number of the voicemail sender.
          * <P>Type: TEXT</P>
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index eae7574..8fc8b9d 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -181,7 +181,7 @@
         
         final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
             {
-                mRequestedFormat = PixelFormat.RGB_565;
+                mRequestedFormat = PixelFormat.RGBX_8888;
             }
 
             @Override
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 441cdc1..071905c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3704,7 +3704,8 @@
      * The base implementation sets:
      * <ul>
      *   <li>{@link AccessibilityNodeInfo#setParent(View)},</li>
-     *   <li>{@link AccessibilityNodeInfo#setBounds(Rect)},</li>
+     *   <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li>
+     *   <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li>
      *   <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li>
      *   <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li>
      *   <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li>
@@ -3724,7 +3725,12 @@
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         Rect bounds = mAttachInfo.mTmpInvalRect;
         getDrawingRect(bounds);
-        info.setBounds(bounds);
+        info.setBoundsInParent(bounds);
+
+        int[] locationOnScreen = mAttachInfo.mInvalidateChildLocation;
+        getLocationOnScreen(locationOnScreen);
+        bounds.offset(locationOnScreen[0], locationOnScreen[1]);
+        info.setBoundsInScreen(bounds);
 
         ViewParent parent = getParent();
         if (parent instanceof View) {
@@ -8451,6 +8457,40 @@
     }
 
     /**
+     * Check if this view can be scrolled horizontally in a certain direction.
+     *
+     * @param direction Negative to check scrolling left, positive to check scrolling right.
+     * @return true if this view can be scrolled in the specified direction, false otherwise.
+     */
+    public boolean canScrollHorizontally(int direction) {
+        final int offset = computeHorizontalScrollOffset();
+        final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent();
+        if (range == 0) return false;
+        if (direction < 0) {
+            return offset > 0;
+        } else {
+            return offset < range - 1;
+        }
+    }
+
+    /**
+     * Check if this view can be scrolled vertically in a certain direction.
+     *
+     * @param direction Negative to check scrolling up, positive to check scrolling down.
+     * @return true if this view can be scrolled in the specified direction, false otherwise.
+     */
+    public boolean canScrollVertically(int direction) {
+        final int offset = computeVerticalScrollOffset();
+        final int range = computeVerticalScrollRange() - computeVerticalScrollExtent();
+        if (range == 0) return false;
+        if (direction < 0) {
+            return offset > 0;
+        } else {
+            return offset < range - 1;
+        }
+    }
+
+    /**
      * <p>Request the drawing of the horizontal and the vertical scrollbar. The
      * scrollbars are painted only if they have been awakened first.</p>
      *
diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewAncestor.java
index 17d7454..914973e 100644
--- a/core/java/android/view/ViewAncestor.java
+++ b/core/java/android/view/ViewAncestor.java
@@ -136,6 +136,13 @@
     static final ArrayList<ComponentCallbacks> sConfigCallbacks
             = new ArrayList<ComponentCallbacks>();
 
+    /**
+     * Delay before dispatching an accessibility event that the window
+     * content has changed. The window content is considered changed
+     * after a layout pass.
+     */
+    private static final long SEND_WINDOW_CONTENT_CHANGED_DELAY_MILLIS = 500;
+
     long mLastTrackballTime = 0;
     final TrackballAxis mTrackballAxisX = new TrackballAxis();
     final TrackballAxis mTrackballAxisY = new TrackballAxis();
@@ -277,6 +284,8 @@
 
     AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
 
+    SendWindowContentChanged mSendWindowContentChanged;
+
     private final int mDensity;
 
     /**
@@ -1427,6 +1436,10 @@
         if (triggerGlobalLayoutListener) {
             attachInfo.mRecomputeGlobalAttributes = false;
             attachInfo.mTreeObserver.dispatchOnGlobalLayout();
+
+            if (AccessibilityManager.getInstance(host.mContext).isEnabled()) {
+                postSendWindowContentChangedCallback();
+            }
         }
 
         if (computesInternalInsets) {
@@ -2086,6 +2099,7 @@
         mAccessibilityInteractionConnectionManager.ensureNoConnection();
         mAccessibilityManager.removeAccessibilityStateChangeListener(
                 mAccessibilityInteractionConnectionManager);
+        removeSendWindowContentChangedCallback();
 
         mView = null;
         mAttachInfo.mRootView = null;
@@ -3671,6 +3685,29 @@
         }
     }
 
+    /**
+     * Post a callback to send a
+     * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
+     */
+    private void postSendWindowContentChangedCallback() {
+        if (mSendWindowContentChanged == null) {
+            mSendWindowContentChanged = new SendWindowContentChanged();
+        } else {
+            removeCallbacks(mSendWindowContentChanged);
+        }
+        postDelayed(mSendWindowContentChanged, SEND_WINDOW_CONTENT_CHANGED_DELAY_MILLIS);
+    }
+
+    /**
+     * Remove a posted callback to send a
+     * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event.
+     */
+    private void removeSendWindowContentChangedCallback() {
+        if (mSendWindowContentChanged != null) {
+            removeCallbacks(mSendWindowContentChanged);
+        }
+    }
+
     public boolean showContextMenuForChild(View originalView) {
         return false;
     }
@@ -4268,12 +4305,12 @@
             }
         }
 
-        public void findAccessibilityNodeInfosByViewText(String text, int interactionId,
-                IAccessibilityInteractionConnectionCallback callback) {
+        public void findAccessibilityNodeInfosByViewText(String text, int accessibilityId,
+                int interactionId, IAccessibilityInteractionConnectionCallback callback) {
             if (mViewAncestor.get() != null) {
                 getAccessibilityInteractionController()
-                    .findAccessibilityNodeInfosByViewTextClientThread(text, interactionId,
-                            callback);
+                    .findAccessibilityNodeInfosByViewTextClientThread(text, accessibilityId,
+                            interactionId, callback);
             }
         }
     }
@@ -4414,13 +4451,15 @@
             }
         }
 
-        public void findAccessibilityNodeInfosByViewTextClientThread(String text, int interactionId,
+        public void findAccessibilityNodeInfosByViewTextClientThread(String text,
+                int accessibilityViewId, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback) {
             Message message = Message.obtain();
             message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT;
             SomeArgs args = mPool.acquire();
             args.arg1 = text;
-            args.argi1 = interactionId;
+            args.argi1 = accessibilityViewId;
+            args.argi2 = interactionId;
             args.arg2 = callback;
             message.obj = args;
             sendMessage(message);
@@ -4429,18 +4468,28 @@
         public void findAccessibilityNodeInfosByViewTextUiThread(Message message) {
             SomeArgs args = (SomeArgs) message.obj;
             final String text = (String) args.arg1;
-            final int interactionId = args.argi1;
+            final int accessibilityViewId = args.argi1;
+            final int interactionId = args.argi2;
             final IAccessibilityInteractionConnectionCallback callback =
                 (IAccessibilityInteractionConnectionCallback) args.arg2;
             mPool.release(args);
 
             List<AccessibilityNodeInfo> infos = null;
             try {
-                View root = ViewAncestor.this.mView;
-
                 ArrayList<View> foundViews = mAttachInfo.mFocusablesTempList;
                 foundViews.clear();
 
+                View root = null;
+                if (accessibilityViewId != View.NO_ID) {
+                    root = findViewByAccessibilityId(accessibilityViewId);
+                } else {
+                    root = ViewAncestor.this.mView;
+                }
+
+                if (root == null) {
+                    return;
+                }
+
                 root.findViewsWithText(foundViews, text);
                 if (foundViews.isEmpty()) {
                     return;
@@ -4577,4 +4626,12 @@
             }
         }
     }
+
+    private class SendWindowContentChanged implements Runnable {
+        public void run() {
+            if (mView != null) {
+                mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+            }
+        }
+    }
 }
diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java
index d128b57..5d4fbbe 100755
--- a/core/java/android/view/WindowOrientationListener.java
+++ b/core/java/android/view/WindowOrientationListener.java
@@ -321,18 +321,18 @@
         private static final float ORIENTATION_ANGLE_CONFIDENCE_SCALE =
                 confidenceScaleFromDelta(30);
 
-        // Transition takes 2x longer when tilt is 45 degrees from vertical.
-        private static final float TILT_ANGLE_CONFIDENCE_SCALE = confidenceScaleFromDelta(45);
+        // Transition takes 2x longer when tilt is 60 degrees from vertical.
+        private static final float TILT_ANGLE_CONFIDENCE_SCALE = confidenceScaleFromDelta(60);
 
-        // Transition takes 2x longer when acceleration is 0.25 Gs.
+        // Transition takes 2x longer when acceleration is 0.5 Gs.
         private static final float MAGNITUDE_CONFIDENCE_SCALE = confidenceScaleFromDelta(
-                SensorManager.STANDARD_GRAVITY * 0.25f);
+                SensorManager.STANDARD_GRAVITY * 0.5f);
 
         // The number of milliseconds for which a new orientation must be stable before
         // we perform an orientation change under ideal conditions.  It will take
         // proportionally longer than this to effect an orientation change when
         // the proposed orientation confidence is low.
-        private static final float ORIENTATION_SETTLE_TIME_MS = 250;
+        private static final float ORIENTATION_SETTLE_TIME_MS = 100;
 
         // The confidence that we have abount effecting each orientation change.
         // When one of these values exceeds 1.0, we have determined our new orientation!
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 06e4827..5ef7763 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -19,11 +19,10 @@
 import android.accessibilityservice.IAccessibilityServiceConnection;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.RemoteException;
 import android.text.TextUtils;
-import android.view.View;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * This class represents accessibility events that are sent by the system when
@@ -130,7 +129,7 @@
  * <p>
  * <b>TRANSITION TYPES</b> <br>
  * <p>
- * <b>Window state changed</b> - represents the event of opening/closing a
+ * <b>Window state changed</b> - represents the event of opening a
  * {@link android.widget.PopupWindow}, {@link android.view.Menu},
  * {@link android.app.Dialog}, etc. <br>
  * Type: {@link #TYPE_WINDOW_STATE_CHANGED} <br>
@@ -140,6 +139,16 @@
  * {@link #getEventTime()},
  * {@link #getText()}
  * <p>
+ * <b>Window content changed</b> - represents the event of change in the
+ * content of a window. This change can be adding/removing view, changing
+ * a view size, etc.<br>
+ * Type: {@link #TYPE_WINDOW_CONTENT_CHANGED} <br>
+ * Properties:
+ * {@link #getClassName()},
+ * {@link #getPackageName()},
+ * {@link #getEventTime()},
+ * {@link #getText()}
+ * <p>
  * <b>NOTIFICATION TYPES</b> <br>
  * <p>
  * <b>Notification state changed</b> - represents the event showing/hiding
@@ -244,6 +253,11 @@
     public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 0x00000400;
 
     /**
+     * Represents the event of changing the content of a window.
+     */
+    public static final int TYPE_WINDOW_CONTENT_CHANGED = 0x00000800;
+
+    /**
      * Mask for {@link AccessibilityEvent} all types.
      *
      * @see #TYPE_VIEW_CLICKED
@@ -264,15 +278,11 @@
     private boolean mIsInPool;
 
     private int mEventType;
-    private int mSourceAccessibilityViewId = View.NO_ID;
-    private int mSourceAccessibilityWindowId = View.NO_ID;
     private CharSequence mPackageName;
     private long mEventTime;
 
     private final ArrayList<AccessibilityRecord> mRecords = new ArrayList<AccessibilityRecord>();
 
-    private IAccessibilityServiceConnection mConnection;
-
     /*
      * Hide constructor from clients.
      */
@@ -288,10 +298,43 @@
         super.init(event);
         mEventType = event.mEventType;
         mEventTime = event.mEventTime;
-        mSourceAccessibilityWindowId = event.mSourceAccessibilityWindowId;
-        mSourceAccessibilityViewId = event.mSourceAccessibilityViewId;
         mPackageName = event.mPackageName;
-        mConnection = event.mConnection;
+    }
+
+    /**
+     * Sets the connection for interacting with the AccessibilityManagerService.
+     *
+     * @param connection The connection.
+     *
+     * @hide
+     */
+    @Override
+    public void setConnection(IAccessibilityServiceConnection connection) {
+        super.setConnection(connection);
+        List<AccessibilityRecord> records = mRecords;
+        final int recordCount = records.size();
+        for (int i = 0; i < recordCount; i++) {
+            AccessibilityRecord record = records.get(i);
+            record.setConnection(connection);
+        }
+    }
+
+    /**
+     * Sets if this instance is sealed.
+     *
+     * @param sealed Whether is sealed.
+     *
+     * @hide
+     */
+    @Override
+    public void setSealed(boolean sealed) {
+        super.setSealed(sealed);
+        List<AccessibilityRecord> records = mRecords;
+        final int recordCount = records.size();
+        for (int i = 0; i < recordCount; i++) {
+            AccessibilityRecord record = records.get(i);
+            record.setSealed(sealed);
+        }
     }
 
     /**
@@ -335,81 +378,6 @@
     }
 
     /**
-     * Sets the event source.
-     *
-     * @param source The source.
-     *
-     * @throws IllegalStateException If called from an AccessibilityService.
-     */
-    public void setSource(View source) {
-        enforceNotSealed();
-        if (source != null) {
-            mSourceAccessibilityWindowId = source.getAccessibilityWindowId();
-            mSourceAccessibilityViewId = source.getAccessibilityViewId();
-        } else {
-            mSourceAccessibilityWindowId = View.NO_ID;
-            mSourceAccessibilityViewId = View.NO_ID;
-        }
-    }
-
-    /**
-     * Gets the {@link AccessibilityNodeInfo} of the event source.
-     * <p>
-     *   <strong>
-     *     It is a client responsibility to recycle the received info by
-     *     calling {@link AccessibilityNodeInfo#recycle()} to avoid creating
-     *     of multiple instances.
-     *   </strong>
-     * </p>
-     * @return The info.
-     */
-    public AccessibilityNodeInfo getSource() {
-        enforceSealed();
-        if (mSourceAccessibilityWindowId == View.NO_ID
-                || mSourceAccessibilityViewId == View.NO_ID) {
-            return null;
-        }
-        try {
-            return mConnection.findAccessibilityNodeInfoByAccessibilityId(
-                    mSourceAccessibilityWindowId, mSourceAccessibilityViewId);
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-
-    /**
-     * Gets the id of the window from which the event comes from.
-     *
-     * @return The window id.
-     */
-    public int getAccessibilityWindowId() {
-        return mSourceAccessibilityWindowId;
-    }
-
-    /**
-     * Sets the client token for the accessibility service that
-     * provided this node info.
-     *
-     * @param connection The connection.
-     *
-     * @hide
-     */
-    public final void setConnection(IAccessibilityServiceConnection connection) {
-        mConnection = connection;
-    }
-
-    /**
-     * Gets the accessibility window id of the source window.
-     *
-     * @return The id.
-     *
-     * @hide
-     */
-    public int getSourceAccessibilityWindowId() {
-        return mSourceAccessibilityWindowId;
-    }
-
-    /**
      * Sets the event type.
      *
      * @param eventType The event type.
@@ -548,10 +516,7 @@
     @Override
     protected void clear() {
         super.clear();
-        mConnection = null;
         mEventType = 0;
-        mSourceAccessibilityViewId = View.NO_ID;
-        mSourceAccessibilityWindowId = View.NO_ID;
         mPackageName = null;
         mEventTime = 0;
         while (!mRecords.isEmpty()) {
@@ -572,8 +537,6 @@
         }
         setSealed(parcel.readInt() == 1);
         mEventType = parcel.readInt();
-        mSourceAccessibilityWindowId = parcel.readInt();
-        mSourceAccessibilityViewId = parcel.readInt();
         mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
         mEventTime = parcel.readLong();
         readAccessibilityRecordFromParcel(this, parcel);
@@ -583,6 +546,8 @@
         for (int i = 0; i < recordCount; i++) {
             AccessibilityRecord record = AccessibilityRecord.obtain();
             readAccessibilityRecordFromParcel(record, parcel);
+            // Do this to write the connection only once.
+            record.setConnection(mConnection);
             mRecords.add(record);
         }
     }
@@ -606,6 +571,9 @@
         record.mBeforeText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
         record.mParcelableData = parcel.readParcelable(null);
         parcel.readList(record.mText, null);
+        record.mSourceWindowId = parcel.readInt();
+        record.mSourceViewId = parcel.readInt();
+        record.mSealed = (parcel.readInt() == 1);
     }
 
     /**
@@ -620,8 +588,6 @@
         }
         parcel.writeInt(isSealed() ? 1 : 0);
         parcel.writeInt(mEventType);
-        parcel.writeInt(mSourceAccessibilityWindowId);
-        parcel.writeInt(mSourceAccessibilityViewId);
         TextUtils.writeToParcel(mPackageName, parcel, 0);
         parcel.writeLong(mEventTime);
         writeAccessibilityRecordToParcel(this, parcel, flags);
@@ -654,6 +620,9 @@
         TextUtils.writeToParcel(record.mBeforeText, parcel, flags);
         parcel.writeParcelable(record.mParcelableData, flags);
         parcel.writeList(record.mText);
+        parcel.writeInt(record.mSourceWindowId);
+        parcel.writeInt(record.mSourceViewId);
+        parcel.writeInt(record.mSealed ? 1 : 0);
     }
 
     /**
@@ -672,8 +641,8 @@
         builder.append(super.toString());
         if (DEBUG) {
             builder.append("\n");
-            builder.append("; sourceAccessibilityWindowId: ").append(mSourceAccessibilityWindowId);
-            builder.append("; sourceAccessibilityViewId: ").append(mSourceAccessibilityViewId);
+            builder.append("; sourceWindowId: ").append(mSourceWindowId);
+            builder.append("; sourceViewId: ").append(mSourceViewId);
             for (int i = 0; i < mRecords.size(); i++) {
                 AccessibilityRecord record = mRecords.get(i);
                 builder.append("  Record ");
@@ -733,6 +702,8 @@
                 return "TYPE_TOUCH_EXPLORATION_GESTURE_START";
             case TYPE_TOUCH_EXPLORATION_GESTURE_END:
                 return "TYPE_TOUCH_EXPLORATION_GESTURE_END";
+            case TYPE_WINDOW_CONTENT_CHANGED:
+                return "TYPE_WINDOW_CONTENT_CHANGED";
             default:
                 return null;
         }
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 5fa65b4..18ef38a 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -26,6 +26,9 @@
 import android.util.SparseIntArray;
 import android.view.View;
 
+import java.util.Collections;
+import java.util.List;
+
 /**
  * This class represents a node of the screen content. From the point of
  * view of an accessibility service the screen content is presented as tree
@@ -97,7 +100,8 @@
     private int mAccessibilityWindowId = View.NO_ID;
     private int mParentAccessibilityViewId = View.NO_ID;
     private int mBooleanProperties;
-    private final Rect mBounds = new Rect();
+    private final Rect mBoundsInParent = new Rect();
+    private final Rect mBoundsInScreen = new Rect();
 
     private CharSequence mPackageName;
     private CharSequence mClassName;
@@ -132,7 +136,7 @@
      *
      * @return The window id.
      */
-    public int getAccessibilityWindowId() {
+    public int getWindowId() {
         return mAccessibilityWindowId;
     }
 
@@ -163,12 +167,16 @@
     public AccessibilityNodeInfo getChild(int index) {
         enforceSealed();
         final int childAccessibilityViewId = mChildAccessibilityIds.get(index);
+        if (!canPerformRequestOverConnection(childAccessibilityViewId)) {
+            return null;
+        }
         try {
             return mConnection.findAccessibilityNodeInfoByAccessibilityId(mAccessibilityWindowId,
                     childAccessibilityViewId);
-        } catch (RemoteException e) {
-             return null;
+        } catch (RemoteException re) {
+             /* ignore*/
         }
+        return null;
     }
 
     /**
@@ -230,12 +238,37 @@
      */
     public boolean performAction(int action) {
         enforceSealed();
+        if (!canPerformRequestOverConnection(mAccessibilityViewId)) {
+            return false;
+        }
         try {
             return mConnection.performAccessibilityAction(mAccessibilityWindowId,
                     mAccessibilityViewId, action);
         } catch (RemoteException e) {
-            return false;
+            /* ignore */
         }
+        return false;
+    }
+
+    /**
+     * Finds {@link AccessibilityNodeInfo}s by text. The match is case
+     * insensitive containment.
+     *
+     * @param text The searched text.
+     * @return A list of node info.
+     */
+    public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text) {
+        enforceSealed();
+        if (!canPerformRequestOverConnection(mAccessibilityViewId)) {
+            return null;
+        }
+        try {
+            return mConnection.findAccessibilityNodeInfosByViewText(text, mAccessibilityWindowId,
+                    mAccessibilityViewId);
+        } catch (RemoteException e) {
+            /* ignore */
+        }
+        return Collections.emptyList();
     }
 
     /**
@@ -251,12 +284,16 @@
      */
     public AccessibilityNodeInfo getParent() {
         enforceSealed();
-        try {
-            return mConnection.findAccessibilityNodeInfoByAccessibilityId(mAccessibilityWindowId,
-                    mParentAccessibilityViewId);
-        } catch (RemoteException e) {
+        if (!canPerformRequestOverConnection(mAccessibilityViewId)) {
             return null;
         }
+        try {
+            return mConnection.findAccessibilityNodeInfoByAccessibilityId(
+                    mAccessibilityWindowId, mParentAccessibilityViewId);
+        } catch (RemoteException e) {
+            /* ignore */
+        }
+        return null;
     }
 
     /**
@@ -279,8 +316,9 @@
      *
      * @param outBounds The output node bounds.
      */
-    public void getBounds(Rect outBounds) {
-        outBounds.set(mBounds.left, mBounds.top, mBounds.right, mBounds.bottom);
+    public void getBoundsInParent(Rect outBounds) {
+        outBounds.set(mBoundsInParent.left, mBoundsInParent.top,
+                mBoundsInParent.right, mBoundsInParent.bottom);
     }
 
     /**
@@ -293,9 +331,34 @@
      *
      * @throws IllegalStateException If called from an AccessibilityService.
      */
-    public void setBounds(Rect bounds) {
+    public void setBoundsInParent(Rect bounds) {
         enforceNotSealed();
-        mBounds.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
+        mBoundsInParent.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
+    }
+
+    /**
+     * Gets the node bounds in screen coordinates.
+     *
+     * @param outBounds The output node bounds.
+     */
+    public void getBoundsInScreen(Rect outBounds) {
+        outBounds.set(mBoundsInScreen.left, mBoundsInScreen.top,
+                mBoundsInScreen.right, mBoundsInScreen.bottom);
+    }
+
+    /**
+     * Sets the node bounds in screen coordinates.
+     * <p>
+     *   Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     * @param bounds The node bounds.
+     *
+     * @throws IllegalStateException If called from an AccessibilityService.
+     */
+    public void setBoundsInScreen(Rect bounds) {
+        enforceNotSealed();
+        mBoundsInScreen.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
     }
 
     /**
@@ -636,6 +699,7 @@
      * @hide
      */
     public final void setConnection(IAccessibilityServiceConnection connection) {
+        enforceNotSealed();
         mConnection = connection;
     }
 
@@ -777,10 +841,15 @@
             parcel.writeInt(childIds.valueAt(i));
         }
 
-        parcel.writeInt(mBounds.top);
-        parcel.writeInt(mBounds.bottom);
-        parcel.writeInt(mBounds.left);
-        parcel.writeInt(mBounds.right);
+        parcel.writeInt(mBoundsInParent.top);
+        parcel.writeInt(mBoundsInParent.bottom);
+        parcel.writeInt(mBoundsInParent.left);
+        parcel.writeInt(mBoundsInParent.right);
+
+        parcel.writeInt(mBoundsInScreen.top);
+        parcel.writeInt(mBoundsInScreen.bottom);
+        parcel.writeInt(mBoundsInScreen.left);
+        parcel.writeInt(mBoundsInScreen.right);
 
         parcel.writeInt(mActions);
 
@@ -818,10 +887,15 @@
             childIds.put(i, childId);
         }
 
-        mBounds.top = parcel.readInt();
-        mBounds.bottom = parcel.readInt();
-        mBounds.left = parcel.readInt();
-        mBounds.right = parcel.readInt();
+        mBoundsInParent.top = parcel.readInt();
+        mBoundsInParent.bottom = parcel.readInt();
+        mBoundsInParent.left = parcel.readInt();
+        mBoundsInParent.right = parcel.readInt();
+
+        mBoundsInScreen.top = parcel.readInt();
+        mBoundsInScreen.bottom = parcel.readInt();
+        mBoundsInScreen.left = parcel.readInt();
+        mBoundsInScreen.right = parcel.readInt();
 
         mActions = parcel.readInt();
 
@@ -842,7 +916,8 @@
         mAccessibilityViewId = View.NO_ID;
         mParentAccessibilityViewId = View.NO_ID;
         mChildAccessibilityIds.clear();
-        mBounds.set(0, 0, 0, 0);
+        mBoundsInParent.set(0, 0, 0, 0);
+        mBoundsInScreen.set(0, 0, 0, 0);
         mBooleanProperties = 0;
         mPackageName = null;
         mClassName = null;
@@ -869,6 +944,12 @@
         return actionSymbolicNames.get(action);
     }
 
+    private boolean canPerformRequestOverConnection(int accessibilityViewId) {
+        return (mAccessibilityWindowId != View.NO_ID
+                && accessibilityViewId != View.NO_ID
+                && mConnection != null);
+    }
+
     @Override
     public boolean equals(Object object) {
         if (this == object) {
@@ -918,7 +999,8 @@
            builder.append("]");
         }
 
-        builder.append("; bounds: " + mBounds);
+        builder.append("; boundsInParent: " + mBoundsInParent);
+        builder.append("; boundsInScreen: " + mBoundsInScreen);
 
         builder.append("; packageName: ").append(mPackageName);
         builder.append("; className: ").append(mClassName);
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index 4bf03a7..9c495e21 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -16,7 +16,10 @@
 
 package android.view.accessibility;
 
+import android.accessibilityservice.IAccessibilityServiceConnection;
 import android.os.Parcelable;
+import android.os.RemoteException;
+import android.view.View;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -45,26 +48,29 @@
     private static int sPoolSize;
     private AccessibilityRecord mNext;
     private boolean mIsInPool;
-    private boolean mSealed;
 
-    protected int mBooleanProperties;
-    protected int mCurrentItemIndex;
-    protected int mItemCount;
-    protected int mFromIndex;
-    protected int mAddedCount;
-    protected int mRemovedCount;
+    boolean mSealed;
+    int mBooleanProperties;
+    int mCurrentItemIndex;
+    int mItemCount;
+    int mFromIndex;
+    int mAddedCount;
+    int mRemovedCount;
+    int mSourceViewId = View.NO_ID;
+    int mSourceWindowId = View.NO_ID;
 
-    protected CharSequence mClassName;
-    protected CharSequence mContentDescription;
-    protected CharSequence mBeforeText;
-    protected Parcelable mParcelableData;
+    CharSequence mClassName;
+    CharSequence mContentDescription;
+    CharSequence mBeforeText;
+    Parcelable mParcelableData;
 
-    protected final List<CharSequence> mText = new ArrayList<CharSequence>();
+    final List<CharSequence> mText = new ArrayList<CharSequence>();
+    IAccessibilityServiceConnection mConnection;
 
     /*
      * Hide constructor.
      */
-    protected AccessibilityRecord() {
+    AccessibilityRecord() {
 
     }
 
@@ -74,7 +80,7 @@
      * @param record The to initialize from.
      */
     void init(AccessibilityRecord record) {
-        mSealed = record.isSealed();
+        mSealed = record.mSealed;
         mBooleanProperties = record.mBooleanProperties;
         mCurrentItemIndex = record.mCurrentItemIndex;
         mItemCount = record.mItemCount;
@@ -86,6 +92,73 @@
         mBeforeText = record.mBeforeText;
         mParcelableData = record.mParcelableData;
         mText.addAll(record.mText);
+        mSourceWindowId = record.mSourceWindowId;
+        mSourceViewId = record.mSourceViewId;
+        mConnection = record.mConnection;
+    }
+
+    /**
+     * Sets the event source.
+     *
+     * @param source The source.
+     *
+     * @throws IllegalStateException If called from an AccessibilityService.
+     */
+    public void setSource(View source) {
+        enforceNotSealed();
+        if (source != null) {
+            mSourceWindowId = source.getAccessibilityWindowId();
+            mSourceViewId = source.getAccessibilityViewId();
+        } else {
+            mSourceWindowId = View.NO_ID;
+            mSourceViewId = View.NO_ID;
+        }
+    }
+
+    /**
+     * Gets the {@link AccessibilityNodeInfo} of the event source.
+     * <p>
+     *   <strong>
+     *     It is a client responsibility to recycle the received info by
+     *     calling {@link AccessibilityNodeInfo#recycle()} to avoid creating
+     *     of multiple instances.
+     *   </strong>
+     * </p>
+     * @return The info.
+     */
+    public AccessibilityNodeInfo getSource() {
+        enforceSealed();
+        if (mSourceWindowId == View.NO_ID || mSourceViewId == View.NO_ID || mConnection == null) {
+            return null;
+        }
+        try {
+            return mConnection.findAccessibilityNodeInfoByAccessibilityId(mSourceWindowId,
+                    mSourceViewId);
+        } catch (RemoteException e) {
+           /* ignore */
+        }
+        return null;
+    }
+
+    /**
+     * Sets the connection for interacting with the AccessibilityManagerService.
+     *
+     * @param connection The connection.
+     *
+     * @hide
+     */
+    public void setConnection(IAccessibilityServiceConnection connection) {
+        enforceNotSealed();
+        mConnection = connection;
+    }
+
+    /**
+     * Gets the id of the window from which the event comes from.
+     *
+     * @return The window id.
+     */
+    public int getWindowId() {
+        return mSourceWindowId;
     }
 
     /**
@@ -386,10 +459,8 @@
      * Gets if this instance is sealed.
      *
      * @return Whether is sealed.
-     *
-     * @hide
      */
-    public boolean isSealed() {
+    boolean isSealed() {
         return mSealed;
     }
 
@@ -397,10 +468,8 @@
      * Enforces that this instance is sealed.
      *
      * @throws IllegalStateException If this instance is not sealed.
-     *
-     * @hide
      */
-    protected void enforceSealed() {
+    void enforceSealed() {
         if (!isSealed()) {
             throw new IllegalStateException("Cannot perform this "
                     + "action on a not sealed instance.");
@@ -411,10 +480,8 @@
      * Enforces that this instance is not sealed.
      *
      * @throws IllegalStateException If this instance is sealed.
-     *
-     * @hide
      */
-    protected void enforceNotSealed() {
+    void enforceNotSealed() {
         if (isSealed()) {
             throw new IllegalStateException("Cannot perform this "
                     + "action on an sealed instance.");
@@ -502,10 +569,8 @@
 
     /**
      * Clears the state of this instance.
-     *
-     * @hide
      */
-    protected void clear() {
+    void clear() {
         mSealed = false;
         mBooleanProperties = 0;
         mCurrentItemIndex = INVALID_POSITION;
@@ -518,6 +583,8 @@
         mBeforeText = null;
         mParcelableData = null;
         mText.clear();
+        mSourceViewId = View.NO_ID;
+        mSourceWindowId = View.NO_ID;
     }
 
     @Override
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
index 77dcd07..d35186b 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
@@ -33,8 +33,8 @@
     void findAccessibilityNodeInfoByViewId(int id, int interactionId,
         IAccessibilityInteractionConnectionCallback callback);
 
-    void findAccessibilityNodeInfosByViewText(String text, int interactionId,
-        IAccessibilityInteractionConnectionCallback callback);
+    void findAccessibilityNodeInfosByViewText(String text, int accessibilityViewId,
+        int interactionId, IAccessibilityInteractionConnectionCallback callback);
 
     void performAccessibilityAction(int accessibilityId, int action, int interactionId,
         IAccessibilityInteractionConnectionCallback callback);
diff --git a/core/java/android/webkit/HTML5VideoFullScreen.java b/core/java/android/webkit/HTML5VideoFullScreen.java
index 44229a4..4cae9d8 100644
--- a/core/java/android/webkit/HTML5VideoFullScreen.java
+++ b/core/java/android/webkit/HTML5VideoFullScreen.java
@@ -253,18 +253,19 @@
         mLayout.setVisibility(View.VISIBLE);
 
         WebChromeClient client = webView.getWebChromeClient();
-        client.onShowCustomView(mLayout, mCallback);
-        // Plugins like Flash will draw over the video so hide
-        // them while we're playing.
-        if (webView.getViewManager() != null)
-            webView.getViewManager().hideAll();
+        if (client != null) {
+            client.onShowCustomView(mLayout, mCallback);
+            // Plugins like Flash will draw over the video so hide
+            // them while we're playing.
+            if (webView.getViewManager() != null)
+                webView.getViewManager().hideAll();
 
-        mProgressView = client.getVideoLoadingProgressView();
-        if (mProgressView != null) {
-            mLayout.addView(mProgressView, layoutParams);
-            mProgressView.setVisibility(View.VISIBLE);
+            mProgressView = client.getVideoLoadingProgressView();
+            if (mProgressView != null) {
+                mLayout.addView(mProgressView, layoutParams);
+                mProgressView.setVisibility(View.VISIBLE);
+            }
         }
-
     }
 
     /**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 95e4880..bfab8a9 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1395,6 +1395,10 @@
      */
     public int getVisibleTitleHeight() {
         checkThread();
+        return getVisibleTitleHeightImpl();
+    }
+
+    private int getVisibleTitleHeightImpl() {
         // need to restrict mScrollY due to over scroll
         return Math.max(getTitleHeight() - Math.max(0, mScrollY), 0);
     }
@@ -1405,7 +1409,7 @@
      * Note: this can be called from WebCoreThread.
      */
     /* package */ int getViewHeight() {
-        return getViewHeightWithTitle() - getVisibleTitleHeight();
+        return getViewHeightWithTitle() - getVisibleTitleHeightImpl();
     }
 
     int getViewHeightWithTitle() {
@@ -2768,7 +2772,7 @@
         // the visible height back in to account for the fact that if the title
         // bar is partially visible, the part of the visible rect which is
         // displaying our content is displaced by that amount.
-        r.top = viewToContentY(r.top + getVisibleTitleHeight());
+        r.top = viewToContentY(r.top + getVisibleTitleHeightImpl());
         r.right = viewToContentX(r.right);
         r.bottom = viewToContentY(r.bottom);
     }
@@ -2785,7 +2789,7 @@
         // the visible height back in to account for the fact that if the title
         // bar is partially visible, the part of the visible rect which is
         // displaying our content is displaced by that amount.
-        r.top = viewToContentYf(ri.top + getVisibleTitleHeight());
+        r.top = viewToContentYf(ri.top + getVisibleTitleHeightImpl());
         r.right = viewToContentXf(ri.right);
         r.bottom = viewToContentYf(ri.bottom);
     }
@@ -2934,7 +2938,7 @@
         if (mScrollY < 0) {
             t -= mScrollY;
         }
-        scrollBar.setBounds(l, t + getVisibleTitleHeight(), r, b);
+        scrollBar.setBounds(l, t + getVisibleTitleHeightImpl(), r, b);
         scrollBar.draw(canvas);
     }
 
@@ -5179,7 +5183,7 @@
             Rect rect = nativeCursorNodeBounds();
             mSelectX = contentToViewX(rect.left);
             mSelectY = contentToViewY(rect.top);
-        } else if (mLastTouchY > getVisibleTitleHeight()) {
+        } else if (mLastTouchY > getVisibleTitleHeightImpl()) {
             mSelectX = mScrollX + mLastTouchX;
             mSelectY = mScrollY + mLastTouchY;
         } else {
@@ -5497,7 +5501,7 @@
             int rootViewHeight = rootView.getHeight();
             mViewRectViewport.set(mGLRectViewport);
             int savedWebViewBottom = mGLRectViewport.bottom;
-            mGLRectViewport.bottom = rootViewHeight - mGLRectViewport.top - getVisibleTitleHeight();
+            mGLRectViewport.bottom = rootViewHeight - mGLRectViewport.top - getVisibleTitleHeightImpl();
             mGLRectViewport.top = rootViewHeight - savedWebViewBottom;
             mGLViewportEmpty = false;
         } else {
@@ -5554,7 +5558,7 @@
         if (!mInOverScrollMode) {
             sendOurVisibleRect();
             // update WebKit if visible title bar height changed. The logic is same
-            // as getVisibleTitleHeight.
+            // as getVisibleTitleHeightImpl.
             int titleHeight = getTitleHeight();
             if (Math.max(titleHeight - t, 0) != Math.max(titleHeight - oldt, 0)) {
                 sendViewSizeZoom(false);
@@ -5605,8 +5609,8 @@
      * Adjustable parameters. Angle is the radians on a unit circle, limited
      * to quadrant 1. Values range from 0f (horizontal) to PI/2 (vertical)
      */
-    private static final float HSLOPE_TO_START_SNAP = .1f;
-    private static final float HSLOPE_TO_BREAK_SNAP = .2f;
+    private static final float HSLOPE_TO_START_SNAP = .25f;
+    private static final float HSLOPE_TO_BREAK_SNAP = .4f;
     private static final float VSLOPE_TO_START_SNAP = 1.25f;
     private static final float VSLOPE_TO_BREAK_SNAP = .95f;
     /*
@@ -5617,6 +5621,11 @@
      */
     private static final float ANGLE_VERT = 2f;
     private static final float ANGLE_HORIZ = 0f;
+    /*
+     *  The modified moving average weight.
+     *  Formula: MAV[t]=MAV[t-1] + (P[t]-MAV[t-1])/n
+     */
+    private static final float MMA_WEIGHT_N = 5;
 
     private boolean hitFocusedPlugin(int contentX, int contentY) {
         if (DebugFlags.WEB_VIEW) {
@@ -6003,8 +6012,9 @@
                 if (deltaX == 0 && deltaY == 0) {
                     keepScrollBarsVisible = done = true;
                 } else {
-                    mAverageAngle = (mAverageAngle +
-                            calculateDragAngle(deltaX, deltaY)) / 2;
+                    mAverageAngle +=
+                        (calculateDragAngle(deltaX, deltaY) - mAverageAngle)
+                        / MMA_WEIGHT_N;
                     if (mSnapScrollMode != SNAP_NONE) {
                         if (mSnapScrollMode == SNAP_Y) {
                             // radical change means getting out of snap mode
@@ -8318,7 +8328,7 @@
                             (Math.min(maxHeight, y + viewHeight) - viewHeight));
                     // We need to take into account the visible title height
                     // when scrolling since y is an absolute view position.
-                    y = Math.max(0, y - getVisibleTitleHeight());
+                    y = Math.max(0, y - getVisibleTitleHeightImpl());
                     scrollTo(x, y);
                     }
                     break;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 82dd5db..3fe8149 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -55,7 +55,6 @@
 import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
-import android.view.accessibility.AccessibilityEvent;
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index c4d05e9..755d4e0 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -904,8 +904,10 @@
     public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
         // Add a record for ourselves as well.
         AccessibilityEvent record = AccessibilityEvent.obtain();
+        record.setSource(this);
         // Set the class since it is not populated in #dispatchPopulateAccessibilityEvent
         record.setClassName(getClass().getName());
+        child.onInitializeAccessibilityEvent(record);
         child.dispatchPopulateAccessibilityEvent(record);
         event.appendRecord(record);
         return true;
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index bda82a3..092c2f7 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -494,6 +494,14 @@
         requestLayout();
     }
 
+    private static int max2(int[] a, int valueIfEmpty) {
+        int result = valueIfEmpty;
+        for (int i = 0, N = a.length; i < N; i++) {
+            result = Math.max(result, a[i]);
+        }
+        return result;
+    }
+
     private static int sum(float[] a) {
         int result = 0;
         for (int i = 0, length = a.length; i < length; i++) {
@@ -1409,7 +1417,7 @@
         // External entry points
 
         private int size(int[] locations) {
-            return locations[locations.length - 1] - locations[0];
+            return max2(locations, 0) - locations[0];
         }
 
         private int getMin() {
@@ -1878,21 +1886,13 @@
             return result;
         }
 
-        private static int max(int[] a, int valueIfEmpty) {
-            int result = valueIfEmpty;
-            for (int i = 0, length = a.length; i < length; i++) {
-                result = Math.max(result, a[i]);
-            }
-            return result;
-        }
-
         /*
         Create a compact array of keys or values using the supplied index.
          */
         private static <K> K[] compact(K[] a, int[] index) {
             int size = a.length;
             Class<?> componentType = a.getClass().getComponentType();
-            K[] result = (K[]) Array.newInstance(componentType, max(index, -1) + 1);
+            K[] result = (K[]) Array.newInstance(componentType, max2(index, -1) + 1);
 
             // this overwrite duplicates, retaining the last equivalent entry
             for (int i = 0; i < size; i++) {
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 40b0a9c..4c47d37 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -711,6 +711,17 @@
         requestBindService();
     }
 
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            if (mWorkerThread != null) {
+                mWorkerThread.quit();
+            }
+        } finally {
+            super.finalize();
+        }
+    }
+
     private void loadNextIndexInBackground() {
         mWorkerQueue.post(new Runnable() {
             @Override
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 5c6a26f..b7565f3 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -387,7 +387,7 @@
             case MotionEvent.ACTION_DOWN: {
                 final float x = ev.getX();
                 final float y = ev.getY();
-                if (hitThumb(x, y)) {
+                if (isEnabled() && hitThumb(x, y)) {
                     mTouchMode = TOUCH_MODE_DOWN;
                     mTouchX = x;
                     mTouchY = y;
@@ -460,7 +460,8 @@
      */
     private void stopDrag(MotionEvent ev) {
         mTouchMode = TOUCH_MODE_IDLE;
-        boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP;
+        // Up and not canceled, also checks the switch has not been disabled during the drag
+        boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP && isEnabled();
 
         cancelSuperTouch(ev);
 
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 1fe1f79..3d1dedc 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -514,6 +514,12 @@
     }
 
     @Override
+    public void removeAllViews() {
+        super.removeAllViews();
+        mSelectedTab = -1;
+    }
+
+    @Override
     public void sendAccessibilityEventUnchecked(AccessibilityEvent event) {
         // this class fires events only when tabs are focused or selected
         if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED && isFocused()) {
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index 18d6caa..860a08c 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -54,6 +54,8 @@
      */
     public static void main(String[] args) {
         try {
+            // Tell the Zygote what our actual PID is (since it only knows about the
+            // wrapper that it directly forked).
             int fdNum = Integer.parseInt(args[0], 10);
             if (fdNum != 0) {
                 try {
@@ -67,6 +69,10 @@
                 }
             }
 
+            // Mimic Zygote preloading.
+            ZygoteInit.preload();
+
+            // Launch the application.
             String[] runtimeArgs = new String[args.length - 1];
             System.arraycopy(args, 1, runtimeArgs, 0, runtimeArgs.length);
             RuntimeInit.wrapperInit(runtimeArgs);
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 157c0bf..b4a7e52 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -228,6 +228,11 @@
         }
     }
 
+    static void preload() {
+        preloadClasses();
+        preloadResources();
+    }
+
     /**
      * Performs Zygote process initialization. Loads and initializes
      * commonly used classes.
@@ -509,8 +514,7 @@
             registerZygoteSocket();
             EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                 SystemClock.uptimeMillis());
-            preloadClasses();
-            preloadResources();
+            preload();
             EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                 SystemClock.uptimeMillis());
 
diff --git a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
index 85095cf..45f3bc1 100644
--- a/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
+++ b/core/java/com/android/internal/service/wallpaper/ImageWallpaper.java
@@ -25,6 +25,7 @@
 import android.graphics.Rect;
 import android.graphics.Region.Op;
 import android.graphics.drawable.Drawable;
+import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Process;
@@ -46,19 +47,20 @@
 
     WallpaperManager mWallpaperManager;
     private HandlerThread mThread;
+    private Handler mHandler;
 
     @Override
     public void onCreate() {
         super.onCreate();
         mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
         Looper looper = WindowManagerPolicyThread.getLooper();
-        if (looper != null) {
-            setCallbackLooper(looper);
-        } else {
+        if (looper == null) {
             mThread = new HandlerThread("Wallpaper", Process.THREAD_PRIORITY_FOREGROUND);
             mThread.start();
-            setCallbackLooper(mThread.getLooper());
+            looper = mThread.getLooper();
         }
+        setCallbackLooper(looper);
+        mHandler = new Handler(looper);
     }
 
     public Engine onCreateEngine() {
@@ -96,10 +98,6 @@
                     updateWallpaperLocked();
                     drawFrameLocked();
                 }
-
-                // Assume we are the only one using the wallpaper in this
-                // process, and force a GC now to release the old wallpaper.
-                System.gc();
             }
         }
 
@@ -112,7 +110,7 @@
             super.onCreate(surfaceHolder);
             IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
             mReceiver = new WallpaperObserver();
-            registerReceiver(mReceiver, filter);
+            registerReceiver(mReceiver, filter, null, mHandler);
 
             updateSurfaceSize(surfaceHolder);
 
diff --git a/core/java/com/android/internal/widget/multiwaveview/Ease.java b/core/java/com/android/internal/widget/multiwaveview/Ease.java
new file mode 100644
index 0000000..7f90c44
--- /dev/null
+++ b/core/java/com/android/internal/widget/multiwaveview/Ease.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget.multiwaveview;
+
+import android.animation.TimeInterpolator;
+
+class Ease {
+    private static final float DOMAIN = 1.0f;
+    private static final float DURATION = 1.0f;
+    private static final float START = 0.0f;
+
+    static class Linear {
+        public static final TimeInterpolator easeNone = new TimeInterpolator() {
+            public float getInterpolation(float input) {
+                return input;
+            }
+        };
+    }
+
+    static class Cubic {
+        public static final TimeInterpolator easeIn = new TimeInterpolator() {
+            public float getInterpolation(float input) {
+                return DOMAIN*(input/=DURATION)*input*input + START;
+            }
+        };
+        public static final TimeInterpolator easeOut = new TimeInterpolator() {
+            public float getInterpolation(float input) {
+                return DOMAIN*((input=input/DURATION-1)*input*input + 1) + START;
+            }
+        };
+        public static final TimeInterpolator easeInOut = new TimeInterpolator() {
+            public float getInterpolation(float input) {
+                return ((input/=DURATION/2) < 1.0f) ?
+                        (DOMAIN/2*input*input*input + START)
+                            : (DOMAIN/2*((input-=2)*input*input + 2) + START);
+            }
+        };
+    }
+
+    static class Quad {
+        public static final TimeInterpolator easeIn = new TimeInterpolator() {
+            public float getInterpolation (float input) {
+                return DOMAIN*(input/=DURATION)*input + START;
+            }
+        };
+        public static final TimeInterpolator easeOut = new TimeInterpolator() {
+            public float getInterpolation(float input) {
+                return -DOMAIN *(input/=DURATION)*(input-2) + START;
+            }
+        };
+        public static final TimeInterpolator easeInOut = new TimeInterpolator() {
+            public float getInterpolation(float input) {
+                return ((input/=DURATION/2) < 1) ?
+                        (DOMAIN/2*input*input + START)
+                            : (-DOMAIN/2 * ((--input)*(input-2) - 1) + START);
+            }
+        };
+    }
+
+    static class Quart {
+        public static final TimeInterpolator easeIn = new TimeInterpolator() {
+            public float getInterpolation(float input) {
+                return DOMAIN*(input/=DURATION)*input*input*input + START;
+            }
+        };
+        public static final TimeInterpolator easeOut = new TimeInterpolator() {
+            public float getInterpolation(float input) {
+                return -DOMAIN * ((input=input/DURATION-1)*input*input*input - 1) + START;
+            }
+        };
+        public static final TimeInterpolator easeInOut = new TimeInterpolator() {
+            public float getInterpolation(float input) {
+                return ((input/=DURATION/2) < 1) ?
+                        (DOMAIN/2*input*input*input*input + START)
+                            : (-DOMAIN/2 * ((input-=2)*input*input*input - 2) + START);
+            }
+        };
+    }
+
+    static class Quint {
+        public static final TimeInterpolator easeIn = new TimeInterpolator() {
+            public float getInterpolation(float input) {
+                return DOMAIN*(input/=DURATION)*input*input*input*input + START;
+            }
+        };
+        public static final TimeInterpolator easeOut = new TimeInterpolator() {
+            public float getInterpolation(float input) {
+                return DOMAIN*((input=input/DURATION-1)*input*input*input*input + 1) + START;
+            }
+        };
+        public static final TimeInterpolator easeInOut = new TimeInterpolator() {
+            public float getInterpolation(float input) {
+                return ((input/=DURATION/2) < 1) ?
+                        (DOMAIN/2*input*input*input*input*input + START)
+                            : (DOMAIN/2*((input-=2)*input*input*input*input + 2) + START);
+            }
+        };
+    }
+
+    static class Sine {
+        public static final TimeInterpolator easeIn = new TimeInterpolator() {
+            public float getInterpolation(float input) {
+                return -DOMAIN * (float) Math.cos(input/DURATION * (Math.PI/2)) + DOMAIN + START;
+            }
+        };
+        public static final TimeInterpolator easeOut = new TimeInterpolator() {
+            public float getInterpolation(float input) {
+                return DOMAIN * (float) Math.sin(input/DURATION * (Math.PI/2)) + START;
+            }
+        };
+        public static final TimeInterpolator easeInOut = new TimeInterpolator() {
+            public float getInterpolation(float input) {
+                return -DOMAIN/2 * ((float)Math.cos(Math.PI*input/DURATION) - 1.0f) + START;
+            }
+        };
+    }
+
+}
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
new file mode 100644
index 0000000..026ad27
--- /dev/null
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -0,0 +1,645 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget.multiwaveview;
+
+import java.util.ArrayList;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.os.Vibrator;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.internal.R;
+
+/**
+ * A special widget containing a center and outer ring. Moving the center ring to the outer ring
+ * causes an event that can be caught by implementing OnTriggerListener.
+ */
+public class MultiWaveView extends View implements AnimatorUpdateListener {
+    private static final String TAG = "MultiWaveView";
+    private static final boolean DEBUG = false;
+
+    // Wave state machine
+    private static final int STATE_IDLE = 0;
+    private static final int STATE_FIRST_TOUCH = 1;
+    private static final int STATE_TRACKING = 2;
+    private static final int STATE_SNAP = 3;
+    private static final int STATE_FINISH = 4;
+
+    // Animation properties.
+    private static final float SNAP_MARGIN_DEFAULT = 20.0f; // distance to ring before we snap to it
+
+    public interface OnTriggerListener {
+        int NO_HANDLE = 0;
+        int CENTER_HANDLE = 1;
+        public void onGrabbed(View v, int handle);
+        public void onReleased(View v, int handle);
+        public void onTrigger(View v, int target);
+        public void onGrabbedStateChange(View v, int handle);
+    }
+
+    // Tune-able parameters
+    private static final int CHEVRON_INCREMENTAL_DELAY = 50;
+    private static final int CHEVRON_ANIMATION_DURATION = 1000;
+    private static final int RETURN_TO_HOME_DURATION = 150;
+    private static final int HIDE_ANIMATION_DELAY = 500;
+    private static final int HIDE_ANIMATION_DURACTION = 2000;
+    private static final int SHOW_ANIMATION_DURATION = 0;
+    private static final int SHOW_ANIMATION_DELAY = 0;
+    private TimeInterpolator mChevronAnimationInterpolator = Ease.Quint.easeOut;
+
+    private ArrayList<TargetDrawable> mTargetDrawables = new ArrayList<TargetDrawable>();
+    private ArrayList<TargetDrawable> mChevronDrawables = new ArrayList<TargetDrawable>();
+    private ArrayList<Tweener> mChevronAnimations = new ArrayList<Tweener>();
+    private ArrayList<Tweener> mTargetAnimations = new ArrayList<Tweener>();
+    private Tweener mHandleAnimation;
+    private OnTriggerListener mOnTriggerListener;
+    private TargetDrawable mHandleDrawable;
+    private TargetDrawable mOuterRing;
+    private Vibrator mVibrator;
+
+    private int mFeedbackCount = 3;
+    private int mVibrationDuration = 0;
+    private int mGrabbedState;
+    private int mActiveTarget = -1;
+    private float mTapRadius;
+    private float mWaveCenterX;
+    private float mWaveCenterY;
+    private float mVerticalOffset;
+    private float mHorizontalOffset;
+    private float mOuterRadius = 0.0f;
+    private float mHitRadius = 0.0f;
+    private float mSnapMargin = 0.0f;
+    private boolean mDragging;
+
+    private AnimatorListener mResetListener = new Animator.AnimatorListener() {
+        public void onAnimationStart(Animator animation) { }
+        public void onAnimationRepeat(Animator animation) { }
+        public void onAnimationEnd(Animator animation) {
+            switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY);
+        }
+        public void onAnimationCancel(Animator animation) { }
+    };
+
+    public MultiWaveView(Context context) {
+        this(context, null);
+    }
+
+    public MultiWaveView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        Resources res = context.getResources();
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MultiWaveView);
+        mOuterRadius = a.getDimension(R.styleable.MultiWaveView_outerRadius, mOuterRadius);
+        mHorizontalOffset = a.getDimension(R.styleable.MultiWaveView_horizontalOffset,
+                mHorizontalOffset);
+        mVerticalOffset = a.getDimension(R.styleable.MultiWaveView_verticalOffset,
+                mVerticalOffset);
+        mHitRadius = a.getDimension(R.styleable.MultiWaveView_hitRadius, mHitRadius);
+        mSnapMargin = a.getDimension(R.styleable.MultiWaveView_snapMargin, mSnapMargin);
+        mVibrationDuration = a.getInt(R.styleable.MultiWaveView_vibrationDuration,
+                mVibrationDuration);
+        mFeedbackCount = a.getInt(R.styleable.MultiWaveView_feedbackCount,
+                mFeedbackCount);
+        mHandleDrawable = new TargetDrawable(res,
+                a.getDrawable(R.styleable.MultiWaveView_handleDrawable));
+        mTapRadius = mHandleDrawable.getWidth()/2;
+        mOuterRing = new TargetDrawable(res, a.getDrawable(R.styleable.MultiWaveView_waveDrawable));
+
+        // Read animation drawables
+        Drawable leftChevron = a.getDrawable(R.styleable.MultiWaveView_leftChevronDrawable);
+        if (leftChevron != null) {
+            for (int i = 0; i < mFeedbackCount; i++) {
+                mChevronDrawables.add(new TargetDrawable(res, leftChevron));
+            }
+        }
+        Drawable rightChevron = a.getDrawable(R.styleable.MultiWaveView_rightChevronDrawable);
+        if (rightChevron != null) {
+            for (int i = 0; i < mFeedbackCount; i++) {
+                mChevronDrawables.add(new TargetDrawable(res, rightChevron));
+            }
+        }
+
+        // Read array of target drawables
+        TypedValue outValue = new TypedValue();
+        if (a.getValue(R.styleable.MultiWaveView_targetDrawables, outValue)) {
+            setTargetResources(outValue.resourceId);
+        }
+        if (mTargetDrawables == null || mTargetDrawables.size() == 0) {
+            throw new IllegalStateException("Must specify at least one target drawable");
+        }
+
+        setVibrateEnabled(mVibrationDuration > 0);
+    }
+
+    private void dump() {
+        Log.v(TAG, "Outer Radius = " + mOuterRadius);
+        Log.v(TAG, "HitRadius = " + mHitRadius);
+        Log.v(TAG, "SnapMargin = " + mSnapMargin);
+        Log.v(TAG, "FeedbackCount = " + mFeedbackCount);
+        Log.v(TAG, "VibrationDuration = " + mVibrationDuration);
+        Log.v(TAG, "TapRadius = " + mTapRadius);
+        Log.v(TAG, "WaveCenterX = " + mWaveCenterX);
+        Log.v(TAG, "WaveCenterY = " + mWaveCenterY);
+        Log.v(TAG, "HorizontalOffset = " + mHorizontalOffset);
+        Log.v(TAG, "VerticalOffset = " + mVerticalOffset);
+    }
+
+    @Override
+    protected int getSuggestedMinimumWidth() {
+        // View should be large enough to contain the background + target drawable on either edge
+        return mOuterRing.getWidth()
+                + (mTargetDrawables.size() > 0 ? (mTargetDrawables.get(0).getWidth()) : 0);
+    }
+
+    @Override
+    protected int getSuggestedMinimumHeight() {
+        // View should be large enough to contain the unlock ring + target drawable on either edge
+        return mOuterRing.getHeight()
+                + (mTargetDrawables.size() > 0 ? (mTargetDrawables.get(0).getHeight()) : 0);
+    }
+
+    private void switchToState(int state, float x, float y) {
+        switch (state) {
+            case STATE_IDLE:
+                stopChevronAnimation();
+                deactivateTargets();
+                mHandleDrawable.setState(TargetDrawable.STATE_INACTIVE);
+                break;
+
+            case STATE_FIRST_TOUCH:
+                stopHandleAnimation();
+                deactivateTargets();
+                showTargets();
+                mHandleDrawable.setState(TargetDrawable.STATE_ACTIVE);
+                setGrabbedState(OnTriggerListener.CENTER_HANDLE);
+                break;
+
+            case STATE_TRACKING:
+                break;
+
+            case STATE_SNAP:
+                break;
+
+            case STATE_FINISH:
+                doFinish();
+                break;
+        }
+    }
+
+    /**
+     * Animation used to attract user's attention to the target button.
+     * Assumes mChevronDrawables is an a list with an even number of chevrons filled with left
+     * followed by right chevrons.
+     */
+    private void startChevronAnimation() {
+        final int icons = mChevronDrawables.size();
+        for (Tweener tween : mChevronAnimations) {
+            tween.animator.cancel();
+        }
+        for (int i = 0; i < icons; i++) {
+            TargetDrawable icon = mChevronDrawables.get(i);
+            icon.setY(mWaveCenterY);
+            icon.setAlpha(1.0f);
+            mChevronAnimations.clear();
+            int delay = (int) (Math.abs(0.5f + i - icons / 2) * CHEVRON_INCREMENTAL_DELAY);
+            if (i < icons/2) {
+                // Left chevrons
+                icon.setX(mWaveCenterX - mHandleDrawable.getWidth() / 2);
+                mChevronAnimations.add(Tweener.to(icon, CHEVRON_ANIMATION_DURATION,
+                        "ease", mChevronAnimationInterpolator,
+                        "delay", delay,
+                        "x", mWaveCenterX - mOuterRadius,
+                        "alpha", 0.0f,
+                        "onUpdate", this));
+            } else {
+                // Right chevrons
+                icon.setX(mWaveCenterX + mHandleDrawable.getWidth() / 2);
+                mChevronAnimations.add(Tweener.to(icon, CHEVRON_ANIMATION_DURATION,
+                        "ease", mChevronAnimationInterpolator,
+                        "delay", delay,
+                        "x", mWaveCenterX + mOuterRadius,
+                        "alpha", 0.0f,
+                        "onUpdate", this));
+            }
+        }
+    }
+
+    private void stopChevronAnimation() {
+        for (Tweener anim : mChevronAnimations) {
+            anim.animator.end();
+        }
+        mChevronAnimations.clear();
+    }
+
+    private void stopHandleAnimation() {
+        if (mHandleAnimation != null) {
+            mHandleAnimation.animator.end();
+            mHandleAnimation = null;
+        }
+    }
+
+    private void deactivateTargets() {
+        for (TargetDrawable target : mTargetDrawables) {
+            target.setState(TargetDrawable.STATE_INACTIVE);
+        }
+        mActiveTarget = -1;
+    }
+
+    void invalidateGlobalRegion(TargetDrawable drawable) {
+        int width = drawable.getWidth();
+        int height = drawable.getHeight();
+        RectF childBounds = new RectF(0, 0, width, height);
+        childBounds.offset(drawable.getX() - width/2, drawable.getY() - height/2);
+        View view = this;
+        while (view.getParent() != null && view.getParent() instanceof View) {
+            view = (View) view.getParent();
+            view.getMatrix().mapRect(childBounds);
+            view.invalidate((int) Math.floor(childBounds.left),
+                    (int) Math.floor(childBounds.top),
+                    (int) Math.ceil(childBounds.right),
+                    (int) Math.ceil(childBounds.bottom));
+        }
+    }
+
+    /**
+     * Dispatches a trigger event to listener. Ignored if a listener is not set.
+     * @param whichHandle the handle that triggered the event.
+     */
+    private void dispatchTriggerEvent(int whichHandle) {
+        vibrate();
+        if (mOnTriggerListener != null) {
+            mOnTriggerListener.onTrigger(this, whichHandle);
+        }
+    }
+
+    private void doFinish() {
+        // Inform listener of any active targets.  Typically only one will be active.
+        final int activeTarget = mActiveTarget;
+        boolean targetHit =  activeTarget != -1;
+        if (targetHit) {
+            Log.v(TAG, "Finish with target hit = " + targetHit);
+            dispatchTriggerEvent(mActiveTarget);
+        }
+
+        setGrabbedState(OnTriggerListener.NO_HANDLE);
+
+        // Animate finger outline back to home position
+        mHandleDrawable.setAlpha(targetHit ? 0.0f : 1.0f);
+        mHandleAnimation = Tweener.to(mHandleDrawable, RETURN_TO_HOME_DURATION,
+                "ease", Ease.Quart.easeOut,
+                "delay", targetHit ? HIDE_ANIMATION_DELAY : 0,
+                "alpha", 1.0f,
+                "x", mWaveCenterX,
+                "y", mWaveCenterY,
+                "onUpdate", this,
+                "onComplete", mResetListener);
+
+        // Hide unselected targets
+        hideTargets(true);
+
+        // Highlight the selected one
+        if (targetHit) {
+            mTargetDrawables.get(activeTarget).setState(TargetDrawable.STATE_ACTIVE);
+        }
+
+        stopChevronAnimation();
+    }
+
+    private void hideTargets(boolean animate) {
+        if (mTargetAnimations.size() > 0) {
+            stopTargetAnimation();
+        }
+        for (TargetDrawable target : mTargetDrawables) {
+            target.setState(TargetDrawable.STATE_INACTIVE);
+            mTargetAnimations.add(Tweener.to(target,
+                    animate ? HIDE_ANIMATION_DURACTION : 0,
+                    "alpha", 0.0f,
+                    "delay", HIDE_ANIMATION_DELAY,
+                    "onUpdate", this));
+        }
+        mTargetAnimations.add(Tweener.to(mOuterRing,
+                animate ? HIDE_ANIMATION_DURACTION : 0,
+                "alpha", 0.0f,
+                "delay", HIDE_ANIMATION_DELAY,
+                "onUpdate", this));
+    }
+
+    private void showTargets() {
+        if (mTargetAnimations.size() > 0) {
+            stopTargetAnimation();
+        }
+        for (TargetDrawable target : mTargetDrawables) {
+            target.setState(TargetDrawable.STATE_INACTIVE);
+            mTargetAnimations.add(Tweener.to(target, SHOW_ANIMATION_DURATION,
+                    "alpha", 1.0f,
+                    "delay", SHOW_ANIMATION_DELAY,
+                    "onUpdate", this));
+        }
+        mTargetAnimations.add(Tweener.to(mOuterRing, SHOW_ANIMATION_DURATION,
+                "alpha", 1.0f,
+                "delay", SHOW_ANIMATION_DELAY,
+                "onUpdate", this));
+    }
+
+    private void stopTargetAnimation() {
+        for (Tweener anim : mTargetAnimations) {
+            anim.animator.end();
+        }
+        mTargetAnimations.clear();
+    }
+
+    private void vibrate() {
+        if (mVibrator != null) {
+            mVibrator.vibrate(mVibrationDuration);
+        }
+    }
+
+    /**
+     * Loads an array of drawables from the given resourceId.
+     *
+     * @param resourceId
+     */
+    public void setTargetResources(int resourceId) {
+        Resources res = getContext().getResources();
+        TypedArray array = res.obtainTypedArray(resourceId);
+        int count = array.length();
+        mTargetDrawables = new ArrayList<TargetDrawable>(count);
+        for (int i = 0; i < count; i++) {
+            Drawable drawable = array.getDrawable(i);
+            mTargetDrawables.add(new TargetDrawable(res, drawable));
+        }
+    }
+
+    /**
+     * Enable or disable vibrate on touch.
+     *
+     * @param enabled
+     */
+    public void setVibrateEnabled(boolean enabled) {
+        if (enabled && mVibrator == null) {
+            mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
+        } else {
+            mVibrator = null;
+        }
+    }
+
+    /**
+     * Starts chevron animation. Example use case: show chevron animation whenever the phone rings
+     * or the user touches the screen.
+     *
+     */
+    public void ping() {
+        stopChevronAnimation();
+        startChevronAnimation();
+    }
+
+    /**
+     * Resets the widget to default state and cancels all animation. If animate is 'true', will
+     * animate objects into place. Otherwise, objects will snap back to place.
+     *
+     * @param animate
+     */
+    public void reset(boolean animate) {
+        stopChevronAnimation();
+        stopHandleAnimation();
+        stopTargetAnimation();
+        hideChevrons();
+        hideTargets(animate);
+        mHandleDrawable.setX(mWaveCenterX);
+        mHandleDrawable.setY(mWaveCenterY);
+        mHandleDrawable.setState(TargetDrawable.STATE_INACTIVE);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        final int action = event.getAction();
+
+        boolean handled = false;
+        float x = event.getX();
+        float y = event.getY();
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                handleDown(x, y);
+                handled = true;
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                handleMove(x, y);
+                handled = true;
+                break;
+
+            case MotionEvent.ACTION_UP:
+                handleUp(x, y);
+                handleMove(x, y);
+                handled = true;
+                break;
+
+            case MotionEvent.ACTION_CANCEL:
+                handleMove(x, y);
+                handled = true;
+                break;
+        }
+        invalidate();
+        return handled ? true : super.onTouchEvent(event);
+    }
+
+    private void handleDown(float x, float y) {
+        final float dx = x - mWaveCenterX;
+        final float dy = y - mWaveCenterY;
+        if (dist2(dx,dy) <= square(mTapRadius)) {
+            if (DEBUG) Log.v(TAG, "** Handle HIT");
+            switchToState(STATE_FIRST_TOUCH, x, y);
+            mDragging = true;
+        } else {
+            mDragging = false;
+            stopTargetAnimation();
+            ping();
+        }
+    }
+
+    private void handleUp(float x, float y) {
+        if (DEBUG && mDragging) Log.v(TAG, "** Handle RELEASE");
+        switchToState(STATE_FINISH, x, y);
+    }
+
+    private void handleMove(float x, float y) {
+        if (!mDragging) {
+            return;
+        }
+
+        float tx = x - mWaveCenterX;
+        float ty = y - mWaveCenterY;
+        float touchRadius = (float) Math.sqrt(dist2(tx, ty));
+        final float scale = touchRadius > mOuterRadius ? mOuterRadius / touchRadius : 1.0f;
+        float limitX = mWaveCenterX + tx * scale;
+        float limitY = mWaveCenterY + ty * scale;
+
+        int activeTarget = -1;
+        boolean singleTarget = mTargetDrawables.size() == 1;
+        if (singleTarget) {
+            // Snap to outer ring if there's only one target
+            float snapRadius = mOuterRadius - mSnapMargin;
+            if (touchRadius > snapRadius) {
+                activeTarget = 0;
+                x = limitX;
+                y = limitY;
+            }
+        } else {
+            // If there's more than one target, snap to the closest one less than hitRadius away.
+            float best = Float.MAX_VALUE;
+            final float hitRadius2 = mHitRadius * mHitRadius;
+            for (int i = 0; i < mTargetDrawables.size(); i++) {
+                // Snap to the first target in range
+                TargetDrawable target = mTargetDrawables.get(i);
+                float dx = limitX - target.getX();
+                float dy = limitY - target.getY();
+                float dist2 = dx*dx + dy*dy;
+                if (target.isValid() && dist2 < hitRadius2 && dist2 < best) {
+                    activeTarget = i;
+                    best = dist2;
+                }
+            }
+        }
+        if (activeTarget != -1) {
+            switchToState(STATE_SNAP, x,y);
+            mHandleDrawable.setX(singleTarget ? limitX : mTargetDrawables.get(activeTarget).getX());
+            mHandleDrawable.setY(singleTarget ? limitY : mTargetDrawables.get(activeTarget).getY());
+            TargetDrawable currentTarget = mTargetDrawables.get(activeTarget);
+            if (currentTarget.hasState(TargetDrawable.STATE_FOCUSED)) {
+                currentTarget.setState(TargetDrawable.STATE_FOCUSED);
+                mHandleDrawable.setAlpha(0.0f);
+            }
+        } else {
+            switchToState(STATE_TRACKING, x, y);
+            mHandleDrawable.setX(x);
+            mHandleDrawable.setY(y);
+            mHandleDrawable.setAlpha(1.0f);
+        }
+        // Draw handle outside parent's bounds
+        invalidateGlobalRegion(mHandleDrawable);
+
+        if (mActiveTarget != activeTarget && activeTarget != -1) {
+            vibrate();
+        }
+        mActiveTarget = activeTarget;
+    }
+
+    /**
+     * Sets the current grabbed state, and dispatches a grabbed state change
+     * event to our listener.
+     */
+    private void setGrabbedState(int newState) {
+        if (newState != mGrabbedState) {
+            if (newState != OnTriggerListener.NO_HANDLE) {
+                vibrate();
+            }
+            mGrabbedState = newState;
+            if (mOnTriggerListener != null) {
+                mOnTriggerListener.onGrabbedStateChange(this, mGrabbedState);
+            }
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        final int width = right - left;
+        final int height = bottom - top;
+
+        mWaveCenterX = mHorizontalOffset + Math.max(width, mOuterRing.getWidth() ) / 2;
+        mWaveCenterY = mVerticalOffset + Math.max(height, mOuterRing.getHeight()) / 2;
+        mHandleDrawable.setX(mWaveCenterX);
+        mHandleDrawable.setY(mWaveCenterY);
+        mOuterRing.setX(mWaveCenterX);
+        mOuterRing.setY(Math.max(mWaveCenterY, mWaveCenterY));
+        mOuterRing.setAlpha(0.0f);
+        if (mOuterRadius == 0.0f) {
+            mOuterRadius = 0.5f*(float) Math.sqrt(dist2(mWaveCenterX, mWaveCenterY));
+        }
+        if (mHitRadius == 0.0f) {
+            // Use the radius of inscribed circle of the first target.
+            mHitRadius = mTargetDrawables.get(0).getWidth() / 2.0f;
+        }
+        if (mSnapMargin == 0.0f) {
+            mSnapMargin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                    SNAP_MARGIN_DEFAULT, getContext().getResources().getDisplayMetrics());
+        }
+        for (int i = 0; i < mTargetDrawables.size(); i++) {
+            final TargetDrawable targetIcon = mTargetDrawables.get(i);
+            double angle = -2.0f * Math.PI * i / mTargetDrawables.size();
+            float xPosition = mWaveCenterX + mOuterRadius * (float) Math.cos(angle);
+            float yPosition = mWaveCenterY + mOuterRadius * (float) Math.sin(angle);
+            targetIcon.setX(xPosition);
+            targetIcon.setY(yPosition);
+            targetIcon.setAlpha(0.0f);
+        }
+        hideChevrons();
+        hideTargets(false);
+        if (DEBUG) dump();
+    }
+
+    private void hideChevrons() {
+        for (TargetDrawable chevron : mChevronDrawables) {
+            chevron.setAlpha(0.0f);
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        mOuterRing.draw(canvas);
+        for (TargetDrawable target : mTargetDrawables) {
+            target.draw(canvas);
+        }
+        for (TargetDrawable target : mChevronDrawables) {
+            target.draw(canvas);
+        }
+        mHandleDrawable.draw(canvas);
+    }
+
+    public void setOnTriggerListener(OnTriggerListener listener) {
+        mOnTriggerListener = listener;
+    }
+
+    public void onAnimationUpdate(ValueAnimator animation) {
+        invalidateGlobalRegion(mHandleDrawable);
+        invalidate();
+    }
+
+    private float square(float d) {
+        return d * d;
+    }
+
+    private float dist2(float dx, float dy) {
+        return dx*dx + dy*dy;
+    }
+
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java b/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java
new file mode 100644
index 0000000..d3baa2b
--- /dev/null
+++ b/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget.multiwaveview;
+
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
+import android.util.Log;
+
+public class TargetDrawable {
+    private static final String TAG = "TargetDrawable";
+    public static final int[] STATE_ACTIVE =
+            { android.R.attr.state_enabled, android.R.attr.state_active };
+    public static final int[] STATE_INACTIVE =
+            { android.R.attr.state_enabled, -android.R.attr.state_active };
+    public static final int[] STATE_FOCUSED =
+            { android.R.attr.state_enabled, android.R.attr.state_focused };
+
+    private float mTranslationX = 0.0f;
+    private float mTranslationY = 0.0f;
+    private float mScaleX = 1.0f;
+    private float mScaleY = 1.0f;
+    private float mAlpha = 1.0f;
+    private Drawable mDrawable;
+
+    /* package */ static class DrawableWithAlpha extends Drawable {
+        private float mAlpha = 1.0f;
+        private Drawable mRealDrawable;
+        public DrawableWithAlpha(Drawable realDrawable) {
+            mRealDrawable = realDrawable;
+        }
+        public void setAlpha(float alpha) {
+            mAlpha = alpha;
+        }
+        public float getAlpha() {
+            return mAlpha;
+        }
+        public void draw(Canvas canvas) {
+            mRealDrawable.setAlpha((int) Math.round(mAlpha * 255f));
+            mRealDrawable.draw(canvas);
+        }
+        @Override
+        public void setAlpha(int alpha) {
+            mRealDrawable.setAlpha(alpha);
+        }
+        @Override
+        public void setColorFilter(ColorFilter cf) {
+            mRealDrawable.setColorFilter(cf);
+        }
+        @Override
+        public int getOpacity() {
+            return mRealDrawable.getOpacity();
+        }
+    }
+
+    public TargetDrawable(Resources res, int resId) {
+        this(res, resId == 0 ? null : res.getDrawable(resId));
+    }
+
+    public TargetDrawable(Resources res, Drawable drawable) {
+        // Mutate the drawable so we can animate shared drawable properties.
+        mDrawable = drawable != null ? drawable.mutate() : null;
+        resizeDrawables();
+        setState(STATE_INACTIVE);
+    }
+
+    public void setState(int [] state) {
+        if (mDrawable instanceof StateListDrawable) {
+            StateListDrawable d = (StateListDrawable) mDrawable;
+            d.setState(state);
+        }
+    }
+
+    public boolean hasState(int [] state) {
+        if (mDrawable instanceof StateListDrawable) {
+            StateListDrawable d = (StateListDrawable) mDrawable;
+            // TODO: this doesn't seem to work
+            return d.getStateDrawableIndex(state) != -1;
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if the drawable is a StateListDrawable and is in the focused state.
+     *
+     * @return
+     */
+    public boolean isActive() {
+        if (mDrawable instanceof StateListDrawable) {
+            StateListDrawable d = (StateListDrawable) mDrawable;
+            int[] states = d.getState();
+            for (int i = 0; i < states.length; i++) {
+                if (states[i] == android.R.attr.state_focused) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if this target is enabled. Typically an enabled target contains a valid
+     * drawable in a valid state. Currently all targets with valid drawables are valid.
+     *
+     * @return
+     */
+    public boolean isValid() {
+        return mDrawable != null;
+    }
+
+    /**
+     * Makes drawables in a StateListDrawable all the same dimensions.
+     * If not a StateListDrawable, then justs sets the bounds to the intrinsic size of the
+     * drawable.
+     */
+    private void resizeDrawables() {
+        if (mDrawable instanceof StateListDrawable) {
+            StateListDrawable d = (StateListDrawable) mDrawable;
+            int maxWidth = 0;
+            int maxHeight = 0;
+            for (int i = 0; i < d.getStateCount(); i++) {
+                Drawable childDrawable = d.getStateDrawable(i);
+                maxWidth = Math.max(maxWidth, childDrawable.getIntrinsicWidth());
+                maxHeight = Math.max(maxHeight, childDrawable.getIntrinsicHeight());
+            }
+            Log.v(TAG, "union of childDrawable rects " + d + " to: " + maxWidth + "x" + maxHeight);
+            d.setBounds(0, 0, maxWidth, maxHeight);
+            for (int i = 0; i < d.getStateCount(); i++) {
+                Drawable childDrawable = d.getStateDrawable(i);
+                Log.v(TAG, "sizing drawable " + childDrawable + " to: " + maxWidth + "x" + maxHeight);
+                childDrawable.setBounds(0, 0, maxWidth, maxHeight);
+            }
+        } else if (mDrawable != null) {
+            mDrawable.setBounds(0, 0,
+                    mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight());
+        }
+    }
+
+    public void setX(float x) {
+        mTranslationX = x;
+    }
+
+    public void setY(float y) {
+        mTranslationY = y;
+    }
+
+    public void setScaleX(float x) {
+        mScaleX = x;
+    }
+
+    public void setScaleY(float y) {
+        mScaleY = y;
+    }
+
+    public void setAlpha(float alpha) {
+        mAlpha = alpha;
+    }
+
+    public float getX() {
+        return mTranslationX;
+    }
+
+    public float getY() {
+        return mTranslationY;
+    }
+
+    public float getScaleX() {
+        return mScaleX;
+    }
+
+    public float getScaleY() {
+        return mScaleY;
+    }
+
+    public float getAlpha() {
+        return mAlpha;
+    }
+
+    public int getWidth() {
+        return mDrawable != null ? mDrawable.getIntrinsicWidth() : 0;
+    }
+
+    public int getHeight() {
+        return mDrawable != null ? mDrawable.getIntrinsicHeight() : 0;
+    }
+
+    public void draw(Canvas canvas) {
+        if (mDrawable == null) {
+            return;
+        }
+        canvas.save(Canvas.MATRIX_SAVE_FLAG);
+        canvas.translate(mTranslationX, mTranslationY);
+        canvas.scale(mScaleX, mScaleY);
+        canvas.translate(-0.5f * getWidth(), -0.5f * getHeight());
+        mDrawable.setAlpha((int) Math.round(mAlpha * 255f));
+        mDrawable.draw(canvas);
+        canvas.restore();
+    }
+}
diff --git a/core/java/com/android/internal/widget/multiwaveview/Tweener.java b/core/java/com/android/internal/widget/multiwaveview/Tweener.java
new file mode 100644
index 0000000..c2746d9
--- /dev/null
+++ b/core/java/com/android/internal/widget/multiwaveview/Tweener.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget.multiwaveview;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import android.animation.Animator.AnimatorListener;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+
+class Tweener {
+    private static final String TAG = "Tweener";
+
+    private Object object;
+    ObjectAnimator animator;
+    private static HashMap<Object, Tweener> sTweens = new HashMap<Object, Tweener>();
+
+    public Tweener(Object obj, ObjectAnimator anim) {
+        object = obj;
+        animator = anim;
+    }
+
+    public static Tweener to(Object object, long duration, Object... vars) {
+        long delay = 0;
+        AnimatorUpdateListener updateListener = null;
+        AnimatorListener listener = null;
+        TimeInterpolator interpolator = null;
+
+        // Iterate through arguments and discover properties to animate
+        ArrayList<PropertyValuesHolder> props = new ArrayList<PropertyValuesHolder>(vars.length/2);
+        for (int i = 0; i < vars.length; i+=2) {
+            if (!(vars[i] instanceof String)) {
+                throw new IllegalArgumentException("Key must be a string: " + vars[i]);
+            }
+            String key = (String) vars[i];
+            Object value = vars[i+1];
+            if ("simultaneousTween".equals(key)) {
+                // TODO
+            } else if ("ease".equals(key)) {
+                interpolator = (TimeInterpolator) value; // TODO: multiple interpolators?
+            } else if ("onUpdate".equals(key) || "onUpdateListener".equals(key)) {
+                updateListener = (AnimatorUpdateListener) value;
+            } else if ("onComplete".equals(key) || "onCompleteListener".equals(key)) {
+                listener = (AnimatorListener) value;
+            } else if ("delay".equals(key)) {
+                delay = ((Number) value).longValue();
+            } else if ("syncWith".equals(key)) {
+                // TODO
+            } else if (value instanceof Number[]) {
+                // TODO: support Tween.from()
+            } else if (value instanceof Number) {
+                float floatValue = ((Number)value).floatValue();
+                props.add(PropertyValuesHolder.ofFloat(key, floatValue));
+            } else {
+                throw new IllegalArgumentException(
+                        "Bad argument for key \"" + key + "with value" + value);
+            }
+        }
+
+        // Re-use existing tween, if present
+        Tweener tween = sTweens.get(object);
+        if (tween == null) {
+            ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(object,
+                    props.toArray(new PropertyValuesHolder[props.size()]));
+            tween = new Tweener(object, anim);
+            sTweens.put(object, tween);
+        } else {
+            tween.animator.cancel();
+            replace(props, object);
+        }
+
+        if (interpolator != null) {
+            tween.animator.setInterpolator(interpolator);
+        }
+
+        // Update animation with properties discovered in loop above
+        tween.animator.setStartDelay(delay);
+        tween.animator.setDuration(duration);
+        if (updateListener != null) {
+            tween.animator.removeAllUpdateListeners(); // There should be only one
+            tween.animator.addUpdateListener(updateListener);
+        }
+        if (listener != null) {
+            tween.animator.removeAllListeners(); // There should be only one.
+            tween.animator.addListener(listener);
+        }
+        tween.animator.start();
+
+        return tween;
+    }
+
+    Tweener from(Object object, long duration, Object... vars) {
+        // TODO:  for v of vars
+        //            toVars[v] = object[v]
+        //            object[v] = vars[v]
+        return Tweener.to(object, duration, vars);
+    }
+
+    static void replace(ArrayList<PropertyValuesHolder> props, Object... args) {
+        for (final Object killobject : args) {
+            Tweener tween = sTweens.get(killobject);
+            if (tween != null) {
+                if (killobject == tween.object) {
+                    tween.animator.cancel();
+                    if (props != null) {
+                        tween.animator.setValues(
+                                props.toArray(new PropertyValuesHolder[props.size()]));
+                    } else {
+                        sTweens.remove(tween);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b2606c1..a8aff37 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1377,6 +1377,19 @@
     <permission android:name="android.permission.CRYPT_KEEPER"
         android:protectionLevel="signatureOrSystem" />
 
+    <!-- Allows an application to read historical network usage for
+         specific networks and applications. @hide -->
+    <permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY"
+        android:label="@string/permlab_readNetworkUsageHistory"
+        android:description="@string/permdesc_readNetworkUsageHistory"
+        android:protectionLevel="signature" />
+
+    <!-- Allows an application to manage network policies (such as warning and disable
+         limits) and to define application-specific rules. @hide -->
+    <permission android:name="android.permission.MANAGE_NETWORK_POLICY"
+        android:label="@string/permlab_manageNetworkPolicy"
+        android:description="@string/permdesc_manageNetworkPolicy"
+        android:protectionLevel="signature" />
 
     <!-- C2DM permission. 
          @hide Used internally.
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_answer_active.png b/core/res/res/drawable-hdpi/ic_lockscreen_answer_active.png
new file mode 100644
index 0000000..8089912
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_answer_active.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_answer_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_answer_focused.png
new file mode 100644
index 0000000..e4ba8fd
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_answer_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_answer_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_answer_normal.png
new file mode 100644
index 0000000..c9197c8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_answer_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_chevron_left.png b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_left.png
new file mode 100644
index 0000000..d008afa
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_left.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_chevron_right.png b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_right.png
new file mode 100644
index 0000000..e508900
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_chevron_right.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_decline_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_decline_activated.png
new file mode 100644
index 0000000..9866769
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_decline_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_decline_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_decline_focused.png
new file mode 100644
index 0000000..f5dfacc4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_decline_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_decline_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_decline_normal.png
new file mode 100644
index 0000000..b4d399d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_decline_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_handle_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_handle_normal.png
new file mode 100644
index 0000000..e21a87c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_handle_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_handle_pressed.png b/core/res/res/drawable-hdpi/ic_lockscreen_handle_pressed.png
new file mode 100644
index 0000000..3283f99
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_handle_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_lock_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_lock_normal.png
new file mode 100644
index 0000000..732133c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_lock_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_lock_pressed.png b/core/res/res/drawable-hdpi/ic_lockscreen_lock_pressed.png
new file mode 100644
index 0000000..0bbf62f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_lock_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_outerring.png b/core/res/res/drawable-hdpi/ic_lockscreen_outerring.png
new file mode 100644
index 0000000..5294bc5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_outerring.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.png
new file mode 100644
index 0000000..fce4980
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_silent_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_silent_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_silent_focused.png
new file mode 100644
index 0000000..ecafbea
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_silent_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_silent_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_silent_normal.png
new file mode 100644
index 0000000..1f527b7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_silent_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.png
new file mode 100644
index 0000000..73f01c9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_soundon_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_focused.png
new file mode 100644
index 0000000..d4e558d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_soundon_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_normal.png
new file mode 100644
index 0000000..5d999a6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_soundon_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png
new file mode 100644
index 0000000..d01bdb2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_text_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_text_focusde.png b/core/res/res/drawable-hdpi/ic_lockscreen_text_focusde.png
new file mode 100644
index 0000000..72b8f0a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_text_focusde.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_text_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_text_normal.png
new file mode 100644
index 0000000..bf73a26
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_text_normal.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.png b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.png
new file mode 100644
index 0000000..d333946
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_activated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_unlock_focused.png b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_focused.png
new file mode 100644
index 0000000..e053222
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_focused.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lockscreen_unlock_normal.png b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_normal.png
new file mode 100644
index 0000000..7db46c1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lockscreen_unlock_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_answer_active.png b/core/res/res/drawable-mdpi/ic_lockscreen_answer_active.png
new file mode 100644
index 0000000..0ad03c0
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_answer_active.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_answer_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_answer_focused.png
new file mode 100644
index 0000000..f46e8bd
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_answer_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_answer_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_answer_normal.png
new file mode 100644
index 0000000..ddeeb18
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_answer_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_chevron_left.png b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_left.png
new file mode 100644
index 0000000..e5ef113
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_left.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_chevron_right.png b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_right.png
new file mode 100644
index 0000000..ab723b7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_chevron_right.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_decline_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_decline_activated.png
new file mode 100644
index 0000000..d1aae18
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_decline_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_decline_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_decline_focused.png
new file mode 100644
index 0000000..b52c844
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_decline_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_decline_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_decline_normal.png
new file mode 100644
index 0000000..722027e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_decline_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_handle_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_handle_normal.png
new file mode 100644
index 0000000..c10344f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_handle_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_handle_pressed.png b/core/res/res/drawable-mdpi/ic_lockscreen_handle_pressed.png
new file mode 100644
index 0000000..08c6cfe
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_handle_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_lock_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_lock_normal.png
new file mode 100644
index 0000000..30eb974
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_lock_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_lock_pressed.png b/core/res/res/drawable-mdpi/ic_lockscreen_lock_pressed.png
new file mode 100644
index 0000000..aab2f6b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_lock_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_outerring.png b/core/res/res/drawable-mdpi/ic_lockscreen_outerring.png
new file mode 100644
index 0000000..4151f73
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_outerring.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.png
new file mode 100644
index 0000000..3b2f3fc
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_silent_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_silent_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_silent_focused.png
new file mode 100644
index 0000000..6a5af9d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_silent_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_silent_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_silent_normal.png
new file mode 100644
index 0000000..c288ce4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_silent_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.png
new file mode 100644
index 0000000..03f524d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_soundon_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_focused.png
new file mode 100644
index 0000000..db59b5f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_soundon_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_normal.png
new file mode 100644
index 0000000..eb6ceed
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_soundon_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png
new file mode 100644
index 0000000..dbfc5ba
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_text_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_text_focusde.png b/core/res/res/drawable-mdpi/ic_lockscreen_text_focusde.png
new file mode 100644
index 0000000..1de7586
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_text_focusde.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_text_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_text_normal.png
new file mode 100644
index 0000000..e007322
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_text_normal.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.png b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.png
new file mode 100644
index 0000000..df47993
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_activated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_unlock_focused.png b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_focused.png
new file mode 100644
index 0000000..6f51447
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_focused.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lockscreen_unlock_normal.png b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_normal.png
new file mode 100644
index 0000000..dd255f5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lockscreen_unlock_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_answer_active.png b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_active.png
new file mode 100644
index 0000000..8edf62d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_active.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_answer_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_focused.png
new file mode 100644
index 0000000..2a47e9b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_answer_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_normal.png
new file mode 100644
index 0000000..f049dc9
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_answer_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_left.png b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_left.png
new file mode 100644
index 0000000..75173cb
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_left.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_right.png b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_right.png
new file mode 100644
index 0000000..9f6da72
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_chevron_right.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_decline_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_activated.png
new file mode 100644
index 0000000..4244ca0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_decline_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_focused.png
new file mode 100644
index 0000000..a98a379
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_decline_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_normal.png
new file mode 100644
index 0000000..fa2a0f4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_decline_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_lock_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_lock_normal.png
new file mode 100644
index 0000000..c44a330
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_lock_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png b/core/res/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png
new file mode 100644
index 0000000..2264dc3
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_lock_pressed.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_outerring.png b/core/res/res/drawable-xhdpi/ic_lockscreen_outerring.png
new file mode 100644
index 0000000..0b4b260
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_outerring.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.png
new file mode 100644
index 0000000..fd81211
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_silent_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_focused.png
new file mode 100644
index 0000000..5a93472
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_silent_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_normal.png
new file mode 100644
index 0000000..73f6a2e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_silent_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png
new file mode 100644
index 0000000..9edc70b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png
new file mode 100644
index 0000000..0485af0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png
new file mode 100644
index 0000000..6af5375
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_soundon_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png
new file mode 100644
index 0000000..29c4572
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_text_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_text_focusde.png b/core/res/res/drawable-xhdpi/ic_lockscreen_text_focusde.png
new file mode 100644
index 0000000..42c8ad2
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_text_focusde.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_text_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_text_normal.png
new file mode 100644
index 0000000..ff65f20
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_text_normal.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png
new file mode 100644
index 0000000..fa0be96
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_activated.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_focused.png b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_focused.png
new file mode 100644
index 0000000..d067ab8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_focused.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png
new file mode 100644
index 0000000..1a53c63
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_lockscreen_unlock_normal.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lockscreen_answer.xml b/core/res/res/drawable/ic_lockscreen_answer.xml
new file mode 100644
index 0000000..b42fc2a
--- /dev/null
+++ b/core/res/res/drawable/ic_lockscreen_answer.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:state_enabled="true"
+        android:state_active="false"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_lockscreen_answer_normal" />
+
+    <item
+        android:state_enabled="true"
+        android:state_active="true"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_lockscreen_answer_active" />
+
+</selector>
diff --git a/core/res/res/drawable/ic_lockscreen_decline.xml b/core/res/res/drawable/ic_lockscreen_decline.xml
new file mode 100644
index 0000000..65128a1
--- /dev/null
+++ b/core/res/res/drawable/ic_lockscreen_decline.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:state_enabled="true"
+        android:state_active="false"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_lockscreen_decline_normal" />
+
+    <item
+        android:state_enabled="true"
+        android:state_active="true"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_lockscreen_decline_activated" />
+
+</selector>
diff --git a/core/res/res/drawable/ic_lockscreen_handle.xml b/core/res/res/drawable/ic_lockscreen_handle.xml
new file mode 100644
index 0000000..e7b4a6e
--- /dev/null
+++ b/core/res/res/drawable/ic_lockscreen_handle.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:state_enabled="true"
+        android:state_active="false"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_lockscreen_handle_normal" />
+
+    <item
+        android:state_enabled="true"
+        android:state_active="true"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_lockscreen_handle_pressed" />
+
+</selector>
diff --git a/core/res/res/drawable/ic_lockscreen_send_sms.xml b/core/res/res/drawable/ic_lockscreen_send_sms.xml
new file mode 100644
index 0000000..2503a5c
--- /dev/null
+++ b/core/res/res/drawable/ic_lockscreen_send_sms.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:state_enabled="true"
+        android:state_active="false"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_lockscreen_text_normal" />
+
+    <item
+        android:state_enabled="true"
+        android:state_active="true"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_lockscreen_text_activated" />
+
+</selector>
diff --git a/core/res/res/drawable/ic_lockscreen_silent.xml b/core/res/res/drawable/ic_lockscreen_silent.xml
new file mode 100644
index 0000000..2521eb7
--- /dev/null
+++ b/core/res/res/drawable/ic_lockscreen_silent.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:state_enabled="true"
+        android:state_active="false"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_lockscreen_silent_normal" />
+
+    <item
+        android:state_enabled="true"
+        android:state_active="true"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_lockscreen_silent_activated" />
+
+</selector>
diff --git a/core/res/res/drawable/ic_lockscreen_soundon.xml b/core/res/res/drawable/ic_lockscreen_soundon.xml
new file mode 100644
index 0000000..2b306a5
--- /dev/null
+++ b/core/res/res/drawable/ic_lockscreen_soundon.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:state_enabled="true"
+        android:state_active="false"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_lockscreen_soundon_normal" />
+
+    <item
+        android:state_enabled="true"
+        android:state_active="true"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_lockscreen_soundon_activated" />
+
+</selector>
diff --git a/core/res/res/drawable/ic_lockscreen_unlock.xml b/core/res/res/drawable/ic_lockscreen_unlock.xml
new file mode 100644
index 0000000..0a49c18
--- /dev/null
+++ b/core/res/res/drawable/ic_lockscreen_unlock.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:state_enabled="true"
+        android:state_active="false"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_lockscreen_unlock_normal" />
+
+    <item
+        android:state_enabled="true"
+        android:state_active="true"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_lockscreen_unlock_activated" />
+
+</selector>
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
index c9c1692..543747f 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock.xml
@@ -59,7 +59,7 @@
             />
 
         <com.android.internal.widget.WaveView
-            android:id="@+id/wave_view"
+            android:id="@+id/unlock_widget"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center"
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
index 3bb7821..37bb522 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_tab_unlock_land.xml
@@ -50,7 +50,8 @@
         android:layout_width="0dip"
         android:gravity="center_horizontal|center_vertical">
 
-        <TextView android:id="@+id/screenLocked"
+        <TextView
+            android:id="@+id/screenLocked"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:textAppearance="?android:attr/textAppearanceMedium"
@@ -74,7 +75,7 @@
 
 
         <com.android.internal.widget.WaveView
-            android:id="@+id/wave_view"
+            android:id="@+id/unlock_widget"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
             android:layout_gravity="center_vertical|center_horizontal"
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml
index 5fe38d5..24891dc 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml
@@ -22,11 +22,11 @@
   depending on the state of the device.  It is the same for landscape
   and portrait.-->
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tabunlock="http://schemas.android.com/apk/res/com.android.tabunlock"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="center_horizontal"
-    android:id="@+id/root">
+    android:id="@+id/root"
+    android:clipChildren="false">
 
     <TextView
         android:id="@+id/carrier"
@@ -162,13 +162,25 @@
         android:drawablePadding="4dip"
         />
 
-    <com.android.internal.widget.SlidingTab
-        android:id="@+id/tab_selector"
+    <com.android.internal.widget.multiwaveview.MultiWaveView
+        android:id="@+id/unlock_widget"
         android:orientation="horizontal"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
+        android:layout_height="300dip"
         android:layout_alignParentBottom="true"
-        android:layout_marginBottom="80dip"
+
+        android:targetDrawables="@array/lockscreen_targets_when_silent"
+        android:handleDrawable="@drawable/ic_lockscreen_handle"
+        android:waveDrawable="@drawable/ic_lockscreen_outerring"
+        android:outerRadius="@*android:dimen/multiwaveview_target_placement_radius"
+        android:snapMargin="@*android:dimen/multiwaveview_snap_margin"
+        android:hitRadius="@*android:dimen/multiwaveview_hit_radius"
+        android:vibrationDuration="20"
+        android:leftChevronDrawable="@drawable/ic_lockscreen_chevron_left"
+        android:rightChevronDrawable="@drawable/ic_lockscreen_chevron_right"
+        android:feedbackCount="3"
+        android:horizontalOffset="0dip"
+        android:verticalOffset="60dip"
         />
 
     <!-- emergency call button shown when sim is PUKd and tab_selector is
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
index 3c2ad9a..02994a9 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
@@ -21,11 +21,11 @@
   state of the device, as well as instructions on how to get past it
   depending on the state of the device.-->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tabunlock="http://schemas.android.com/apk/res/com.android.tabunlock"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="horizontal"
-    android:id="@+id/root">
+    android:id="@+id/root"
+    android:clipChildren="false">
 
     <!-- left side -->
     <RelativeLayout
@@ -164,12 +164,23 @@
     </RelativeLayout>
 
     <!-- right side -->
-    <com.android.internal.widget.SlidingTab
-        android:id="@+id/tab_selector"
-        android:orientation="vertical"
-        android:layout_width="wrap_content"
+    <com.android.internal.widget.multiwaveview.MultiWaveView
+        android:id="@+id/unlock_widget"
+        android:layout_width="300dip"
         android:layout_height="match_parent"
-        android:layout_marginRight="80dip"
+
+        android:targetDrawables="@array/lockscreen_targets_when_silent"
+        android:handleDrawable="@drawable/ic_lockscreen_handle"
+        android:waveDrawable="@drawable/ic_lockscreen_outerring"
+        android:outerRadius="@*android:dimen/multiwaveview_target_placement_radius"
+        android:snapMargin="@*android:dimen/multiwaveview_snap_margin"
+        android:hitRadius="@*android:dimen/multiwaveview_hit_radius"
+        android:vibrationDuration="20"
+        android:leftChevronDrawable="@drawable/ic_lockscreen_chevron_left"
+        android:rightChevronDrawable="@drawable/ic_lockscreen_chevron_right"
+        android:feedbackCount="3"
+        android:horizontalOffset="60dip"
+        android:verticalOffset="0dip"
         />
 
     <!-- emergency call button shown when sim is PUKd and tab_selector is
diff --git a/core/res/res/values-land/arrays.xml b/core/res/res/values-land/arrays.xml
new file mode 100644
index 0000000..85130ba1
--- /dev/null
+++ b/core/res/res/values-land/arrays.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Resources for MultiWaveView in LockScreen -->
+    <array name="ic_lockscreen_targets_when_silent">
+        <item>@null</item>"
+        <item>@drawable/ic_lockscreen_unlock</item>
+        <item>@null</item>
+        <item>@drawable/ic_lockscreen_soundon</item>
+    </array>
+
+    <array name="ic_lockscreen_targets_when_soundon">
+        <item>@null</item>"
+        <item>@drawable/ic_lockscreen_unlock</item>
+        <item>@null</item>
+        <item>@drawable/ic_lockscreen_silent</item>
+    </array>
+
+</resources>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 810c3b2..0f04a67 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -333,4 +333,19 @@
         <item>中文 (繁體)</item>
     </string-array>
 
+    <!-- Resources for MultiWaveView in LockScreen -->
+    <array name="lockscreen_targets_when_silent">
+        <item>@drawable/ic_lockscreen_unlock</item>
+        <item>@null</item>
+        <item>@drawable/ic_lockscreen_soundon</item>
+        <item>@null</item>
+    </array>
+
+    <array name="lockscreen_targets_when_soundon">
+        <item>@drawable/ic_lockscreen_unlock</item>
+        <item>@null</item>
+        <item>@drawable/ic_lockscreen_silent</item>
+        <item>@null</item>"
+    </array>
+
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d5da592..acfdfc9 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5009,6 +5009,48 @@
     </declare-styleable>
 
     <!-- =============================== -->
+    <!-- MultiWaveView class attributes -->
+    <!-- =============================== -->
+    <eat-comment />
+    <declare-styleable name="MultiWaveView">
+        <!-- Reference to an array resource that be shown as targets around a circle. -->
+        <attr name="targetDrawables" format="reference"/>
+
+        <!-- Sets a drawable as the drag center. -->
+        <attr name="handleDrawable" format="reference" />
+
+        <!-- Drawable to use for chevron animation on the left. -->
+        <attr name="leftChevronDrawable" format="reference" />
+
+        <!-- Drawable to use for chevron animation on the right. -->
+        <attr name="rightChevronDrawable" format="reference" />
+
+        <!-- Drawable to use for wave ripple animation. -->
+        <attr name="waveDrawable" format="reference" />
+
+        <!-- Outer radius of target circle. Icons will be drawn on this circle. -->
+        <attr name="outerRadius" format="dimension" />
+
+        <!-- Size of target radius. Points within this distance of target center is a "hit". -->
+        <attr name="hitRadius" format="dimension" />
+
+        <!-- Tactile feedback duration for actions. Set to '0' for no vibration. -->
+        <attr name="vibrationDuration" format="integer"/>
+
+        <!-- How close we need to be before snapping to a target. -->
+        <attr name="snapMargin" format="dimension" />
+
+        <!-- Number of waves/chevrons to show in animation. -->
+        <attr name="feedbackCount" format="integer" />
+
+        <!-- Used to shift center of pattern vertically. -->
+        <attr name="verticalOffset" format="dimension" />
+
+        <!-- Used to shift center of pattern horizontally. -->
+        <attr name="horizontalOffset" format="dimension" />
+    </declare-styleable>
+
+    <!-- =============================== -->
     <!-- LockPatternView class attributes -->
     <!-- =============================== -->
     <eat-comment />
@@ -5145,7 +5187,7 @@
     </declare-styleable>
 
     <declare-styleable name="Storage">
-        <!-- path to mount point for the storage --> 
+        <!-- path to mount point for the storage -->
         <attr name="mountPoint" format="string" />
         <!-- user visible description of the storage -->
         <attr name="storageDescription" format="string" />
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 724c528..df22f15 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -57,6 +57,15 @@
     <!-- Default correction for the space key in the password keyboard -->
     <dimen name="password_keyboard_spacebar_vertical_correction">4dip</dimen>
 
+    <!-- Default target placement radius for MultiWaveView -->
+    <dimen name="multiwaveview_target_placement_radius">135dip</dimen>
+
+    <!-- Default distance beyond which MultiWaveView snaps to the target radius -->
+    <dimen name="multiwaveview_snap_margin">20dip</dimen>
+
+    <!-- Default distance from each snap target that MultiWaveView considers a "hit" -->
+    <dimen name="multiwaveview_hit_radius">60dip</dimen>
+
     <!-- Preference activity side margins -->
     <dimen name="preference_screen_side_margin">0dp</dimen>
     <!-- Preference activity side margins negative-->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 82a3b8a..4108c1b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1752,4 +1752,17 @@
   <public type="attr" name="accessibilityFlags" />
   <public type="attr" name="canRetrieveWindowContent" />
 
+  <public type="attr" name="targetDrawables" />
+  <public type="attr" name="handleDrawable" />
+  <public type="attr" name="leftChevronDrawable" />
+  <public type="attr" name="rightChevronDrawable" />
+  <public type="attr" name="waveDrawable" />
+  <public type="attr" name="outerRadius" />
+  <public type="attr" name="hitRadius" />
+  <public type="attr" name="vibrationDuration" />
+  <public type="attr" name="snapMargin" />
+  <public type="attr" name="feedbackCount" />
+  <public type="attr" name="verticalOffset" />
+  <public type="attr" name="horizontalOffset" />
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3736157..b264b41 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1431,6 +1431,16 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_use_sip">Allows an application to use the SIP service to make/receive Internet calls.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_readNetworkUsageHistory">read historical network usage</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_readNetworkUsageHistory">Allows an application to read historical network usage for specific networks and applications.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_manageNetworkPolicy">manage network policy</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_manageNetworkPolicy">Allows an application to manage network policies and define application-specific rules.</string>
+
     <!-- Policy administration -->
 
     <!-- Title of policy access to limiting the user's password choices -->
diff --git a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
index 3260616..99d534c 100644
--- a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
+++ b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
@@ -29,6 +29,7 @@
 import android.provider.Settings;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -49,6 +50,9 @@
  */
 public class InterrogationActivityTest
         extends ActivityInstrumentationTestCase2<InterrogationActivity> {
+    private static final boolean DEBUG = true;
+
+    private static String LOG_TAG = "InterrogationActivityTest";
 
     // Timeout before give up wait for the system to process an accessibility setting change.
     private static final int TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING = 2000;
@@ -62,7 +66,7 @@
     private static IAccessibilityServiceConnection sConnection;
 
     // The last received accessibility event
-    private static volatile AccessibilityEvent sLastAccessibilityEvent;
+    private static volatile AccessibilityEvent sLastFocusAccessibilityEvent;
 
     public InterrogationActivityTest() {
         super(InterrogationActivity.class);
@@ -72,18 +76,19 @@
     @LargeTest
     public void testFindAccessibilityNodeInfoByViewId() throws Exception {
         beforeClassIfNeeded();
+        final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // bring up the activity
             getActivity();
 
-            AccessibilityNodeInfo button = getConnection().findAccessibilityNodeInfoByViewId(
-                    R.id.button5);
+            AccessibilityNodeInfo button =
+                getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertNotNull(button);
             assertEquals(0, button.getChildCount());
 
             // bounds
             Rect bounds = new Rect();
-            button.getBounds(bounds);
+            button.getBoundsInParent(bounds);
             assertEquals(0, bounds.left);
             assertEquals(0, bounds.top);
             assertEquals(73, bounds.right);
@@ -111,28 +116,40 @@
                 button.getActions());
         } finally {
             afterClassIfNeeded();
+            if (DEBUG) {
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                Log.i(LOG_TAG, "testFindAccessibilityNodeInfoByViewId: "
+                        + elapsedTimeMillis + "ms");
+            }
         }
     }
 
     @LargeTest
     public void testFindAccessibilityNodeInfoByViewText() throws Exception {
         beforeClassIfNeeded();
+        final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // bring up the activity
             getActivity();
 
             // find a view by text
             List<AccessibilityNodeInfo> buttons =
-                getConnection().findAccessibilityNodeInfosByViewText("butto");
+                getConnection().findAccessibilityNodeInfosByViewTextInActiveWindow("butto");
             assertEquals(9, buttons.size());
         } finally {
             afterClassIfNeeded();
+            if (DEBUG) {
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                Log.i(LOG_TAG, "testFindAccessibilityNodeInfoByViewText: "
+                        + elapsedTimeMillis + "ms");
+            }
         }
     }
 
     @LargeTest
     public void testTraverseAllViews() throws Exception {
         beforeClassIfNeeded();
+        final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // bring up the activity
             getActivity();
@@ -153,8 +170,8 @@
             classNameAndTextList.add("android.widget.ButtonButton8");
             classNameAndTextList.add("android.widget.ButtonButton9");
 
-            AccessibilityNodeInfo root =  getConnection().findAccessibilityNodeInfoByViewId(
-                    R.id.root);
+            AccessibilityNodeInfo root =
+                getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.root);
             assertNotNull("We must find the existing root.", root);
 
             Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
@@ -181,125 +198,152 @@
             }
         } finally {
             afterClassIfNeeded();
+            if (DEBUG) {
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                Log.i(LOG_TAG, "testTraverseAllViews: " + elapsedTimeMillis + "ms");
+            }
         }
     }
 
     @LargeTest
     public void testPerformAccessibilityActionFocus() throws Exception {
         beforeClassIfNeeded();
+        final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // bring up the activity
             getActivity();
 
             // find a view and make sure it is not focused
-            AccessibilityNodeInfo button = getConnection().findAccessibilityNodeInfoByViewId(
-                    R.id.button5);
+            AccessibilityNodeInfo button =
+                getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isFocused());
 
             // focus the view
             assertTrue(button.performAction(ACTION_FOCUS));
 
             // find the view again and make sure it is focused
-            button = getConnection().findAccessibilityNodeInfoByViewId(R.id.button5);
+            button = getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertTrue(button.isFocused());
         } finally {
             afterClassIfNeeded();
+            if (DEBUG) {
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                Log.i(LOG_TAG, "testPerformAccessibilityActionFocus: " + elapsedTimeMillis + "ms");
+            }
         }
     }
 
     @LargeTest
     public void testPerformAccessibilityActionClearFocus() throws Exception {
         beforeClassIfNeeded();
+        final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // bring up the activity
             getActivity();
 
             // find a view and make sure it is not focused
-            AccessibilityNodeInfo button =  getConnection().findAccessibilityNodeInfoByViewId(
-                    R.id.button5);
+            AccessibilityNodeInfo button =
+                getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isFocused());
 
             // focus the view
             assertTrue(button.performAction(ACTION_FOCUS));
 
             // find the view again and make sure it is focused
-            button =  getConnection().findAccessibilityNodeInfoByViewId(R.id.button5);
+            button =  getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertTrue(button.isFocused());
 
             // unfocus the view
             assertTrue(button.performAction(ACTION_CLEAR_FOCUS));
 
             // find the view again and make sure it is not focused
-            button =  getConnection().findAccessibilityNodeInfoByViewId(R.id.button5);
+            button =  getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isFocused());
         } finally {
             afterClassIfNeeded();
+            if (DEBUG) {
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                Log.i(LOG_TAG, "testPerformAccessibilityActionClearFocus: "
+                        + elapsedTimeMillis + "ms");
+            }
         }
     }
 
     @LargeTest
     public void testPerformAccessibilityActionSelect() throws Exception {
         beforeClassIfNeeded();
+        final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // bring up the activity
             getActivity();
 
             // find a view and make sure it is not selected
-            AccessibilityNodeInfo button = getConnection().findAccessibilityNodeInfoByViewId(
-                    R.id.button5);
+            AccessibilityNodeInfo button =
+                getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isSelected());
 
             // select the view
             assertTrue(button.performAction(ACTION_SELECT));
 
             // find the view again and make sure it is selected
-            button = getConnection().findAccessibilityNodeInfoByViewId(R.id.button5);
+            button = getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertTrue(button.isSelected());
         } finally {
             afterClassIfNeeded();
+            if (DEBUG) {
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                Log.i(LOG_TAG, "testPerformAccessibilityActionSelect: " + elapsedTimeMillis + "ms");
+            }
         }
     }
 
     @LargeTest
     public void testPerformAccessibilityActionClearSelection() throws Exception {
         beforeClassIfNeeded();
+        final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // bring up the activity
             getActivity();
 
             // find a view and make sure it is not selected
-            AccessibilityNodeInfo button = getConnection().findAccessibilityNodeInfoByViewId(
-                    R.id.button5);
+            AccessibilityNodeInfo button =
+                getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isSelected());
 
             // select the view
             assertTrue(button.performAction(ACTION_SELECT));
 
             // find the view again and make sure it is selected
-            button = getConnection().findAccessibilityNodeInfoByViewId(R.id.button5);
+            button = getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertTrue(button.isSelected());
 
             // unselect the view
             assertTrue(button.performAction(ACTION_CLEAR_SELECTION));
 
             // find the view again and make sure it is not selected
-            button = getConnection().findAccessibilityNodeInfoByViewId(R.id.button5);
+            button = getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isSelected());
         } finally {
             afterClassIfNeeded();
+            if (DEBUG) {
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                Log.i(LOG_TAG, "testPerformAccessibilityActionClearSelection: "
+                        + elapsedTimeMillis + "ms");
+            }
         }
     }
 
     @LargeTest
     public void testAccessibilityEventGetSource() throws Exception {
         beforeClassIfNeeded();
+        final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // bring up the activity
             getActivity();
 
             // find a view and make sure it is not focused
-            AccessibilityNodeInfo button = getConnection().findAccessibilityNodeInfoByViewId(
-                    R.id.button5);
+            AccessibilityNodeInfo button =
+                getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isSelected());
 
             // focus the view
@@ -314,14 +358,14 @@
             }
 
             // check that last event source
-            AccessibilityNodeInfo source = sLastAccessibilityEvent.getSource();
+            AccessibilityNodeInfo source = sLastFocusAccessibilityEvent.getSource();
             assertNotNull(source);
 
             // bounds
             Rect buttonBounds = new Rect();
-            button.getBounds(buttonBounds);
+            button.getBoundsInParent(buttonBounds);
             Rect sourceBounds = new Rect();
-            source.getBounds(sourceBounds);
+            source.getBoundsInParent(sourceBounds);
 
             assertEquals(buttonBounds.left, sourceBounds.left);
             assertEquals(buttonBounds.right, sourceBounds.right);
@@ -346,6 +390,42 @@
             assertSame(button.isChecked(), source.isChecked());
         } finally {
             afterClassIfNeeded();
+            if (DEBUG) {
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                Log.i(LOG_TAG, "testAccessibilityEventGetSource: " + elapsedTimeMillis + "ms");
+            }
+        }
+    }
+
+    @LargeTest
+    public void testObjectContract() throws Exception {
+        beforeClassIfNeeded();
+        final long startTimeMillis = SystemClock.uptimeMillis();
+        try {
+            // bring up the activity
+            getActivity();
+
+            // find a view and make sure it is not focused
+            AccessibilityNodeInfo button =
+                getConnection().findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
+            AccessibilityNodeInfo parent = button.getParent();
+            final int childCount = parent.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                AccessibilityNodeInfo child = parent.getChild(i);
+                assertNotNull(child);
+                if (child.equals(button)) {
+                    assertEquals("Equal objects must have same hasCode.", button.hashCode(),
+                            child.hashCode());
+                    return;
+                }
+            }
+            fail("Parent's children do not have the info whose parent is the parent.");
+        } finally {
+            afterClassIfNeeded();
+            if (DEBUG) {
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                Log.i(LOG_TAG, "testObjectContract: " + elapsedTimeMillis + "ms");
+            }
         }
     }
 
@@ -442,7 +522,9 @@
                 public void onInterrupt() {}
 
                 public void onAccessibilityEvent(AccessibilityEvent event) {
-                    sLastAccessibilityEvent = AccessibilityEvent.obtain(event);
+                    if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED) {
+                        sLastFocusAccessibilityEvent = AccessibilityEvent.obtain(event);
+                    }
                     synchronized (sConnection) {
                         sConnection.notifyAll();
                     }
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationTest.java b/core/tests/coretests/src/android/content/res/ConfigurationTest.java
index f1f745e..54a5e4e 100644
--- a/core/tests/coretests/src/android/content/res/ConfigurationTest.java
+++ b/core/tests/coretests/src/android/content/res/ConfigurationTest.java
@@ -30,169 +30,169 @@
         args = {Locale.class}
     )
     public void testGetLayoutDirectionFromLocale() {
-        assertEquals(Configuration.LAYOUT_DIRECTION_UNDEFINED,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(null));
 
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.ENGLISH));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.CANADA));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.CANADA_FRENCH));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.FRANCE));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.FRENCH));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.GERMAN));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.GERMANY));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.ITALIAN));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.ITALY));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.UK));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.US));
 
-        assertEquals(Configuration.LAYOUT_DIRECTION_UNDEFINED,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_UNDEFINED_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.ROOT));
 
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.CHINA));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.CHINESE));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.JAPAN));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.JAPANESE));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.KOREA));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.KOREAN));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.PRC));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.SIMPLIFIED_CHINESE));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.TAIWAN));
-        assertEquals(Configuration.LAYOUT_DIRECTION_LTR,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(Locale.TRADITIONAL_CHINESE));
 
         Locale locale = new Locale("ar");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("ar", "AE");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("ar", "BH");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("ar", "DZ");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("ar", "EG");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("ar", "IQ");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("ar", "JO");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("ar", "KW");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("ar", "LB");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("ar", "LY");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("ar", "MA");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("ar", "OM");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("ar", "QA");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("ar", "SA");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("ar", "SD");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("ar", "SY");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("ar", "TN");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("ar", "YE");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
 
         locale = new Locale("fa");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("fa", "AF");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("fa", "IR");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
 
         locale = new Locale("iw");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("iw", "IL");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("he");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("he", "IL");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
 
         // The following test will not pass until we are able to take care about the scrip subtag
         // thru having the "likelySubTags" file into ICU4C
 //        locale = new Locale("pa_Arab");
-//        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
 //            Configuration.getLayoutDirectionFromLocale(locale));
 //        locale = new Locale("pa_Arab", "PK");
-//        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
 //            Configuration.getLayoutDirectionFromLocale(locale));
 
         locale = new Locale("ps");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
         locale = new Locale("ps", "AF");
-        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
             Configuration.getLayoutDirectionFromLocale(locale));
 
         // The following test will not work as the localized display name would be "Urdu" with ICU 4.4
         // We will need ICU 4.6 to get the correct localized display name
 //        locale = new Locale("ur");
-//        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
 //            Configuration.getLayoutDirectionFromLocale(locale));
 //        locale = new Locale("ur", "IN");
-//        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
 //            Configuration.getLayoutDirectionFromLocale(locale));
 //        locale = new Locale("ur", "PK");
-//        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
 //            Configuration.getLayoutDirectionFromLocale(locale));
 
         // The following test will not pass until we are able to take care about the scrip subtag
         // thru having the "likelySubTags" file into ICU4C
 //        locale = new Locale("uz_Arab");
-//        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
 //            Configuration.getLayoutDirectionFromLocale(locale));
 //        locale = new Locale("uz_Arab", "AF");
-//        assertEquals(Configuration.LAYOUT_DIRECTION_RTL,
+//        assertEquals(Configuration.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE,
 //            Configuration.getLayoutDirectionFromLocale(locale));
     }
 }
diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java
index 8a3e871..5250a7c 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java
@@ -16,7 +16,6 @@
 
 package android.net;
 
-import android.os.SystemClock;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import junit.framework.TestCase;
@@ -25,12 +24,14 @@
 public class NetworkStatsTest extends TestCase {
 
     private static final String TEST_IFACE = "test0";
+    private static final int TEST_UID = 1001;
+    private static final long TEST_START = 1194220800000L;
 
     public void testFindIndex() throws Exception {
-        final NetworkStats stats = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 3)
+        final NetworkStats stats = new NetworkStats(TEST_START, 3)
                 .addEntry(TEST_IFACE, 100, 1024, 0)
                 .addEntry(TEST_IFACE, 101, 0, 1024)
-                .addEntry(TEST_IFACE, 102, 1024, 1024).build();
+                .addEntry(TEST_IFACE, 102, 1024, 1024);
 
         assertEquals(2, stats.findIndex(TEST_IFACE, 102));
         assertEquals(2, stats.findIndex(TEST_IFACE, 102));
@@ -38,14 +39,40 @@
         assertEquals(-1, stats.findIndex(TEST_IFACE, 6));
     }
 
-    public void testSubtractIdenticalData() throws Exception {
-        final NetworkStats before = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2)
-                .addEntry(TEST_IFACE, 100, 1024, 0)
-                .addEntry(TEST_IFACE, 101, 0, 1024).build();
+    public void testAddEntryGrow() throws Exception {
+        final NetworkStats stats = new NetworkStats(TEST_START, 2);
 
-        final NetworkStats after = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2)
+        assertEquals(0, stats.size);
+        assertEquals(2, stats.iface.length);
+
+        stats.addEntry(TEST_IFACE, TEST_UID, 1L, 2L);
+        stats.addEntry(TEST_IFACE, TEST_UID, 2L, 2L);
+
+        assertEquals(2, stats.size);
+        assertEquals(2, stats.iface.length);
+
+        stats.addEntry(TEST_IFACE, TEST_UID, 3L, 4L);
+        stats.addEntry(TEST_IFACE, TEST_UID, 4L, 4L);
+        stats.addEntry(TEST_IFACE, TEST_UID, 5L, 5L);
+
+        assertEquals(5, stats.size);
+        assertTrue(stats.iface.length >= 5);
+
+        assertEquals(1L, stats.rx[0]);
+        assertEquals(2L, stats.rx[1]);
+        assertEquals(3L, stats.rx[2]);
+        assertEquals(4L, stats.rx[3]);
+        assertEquals(5L, stats.rx[4]);
+    }
+
+    public void testSubtractIdenticalData() throws Exception {
+        final NetworkStats before = new NetworkStats(TEST_START, 2)
                 .addEntry(TEST_IFACE, 100, 1024, 0)
-                .addEntry(TEST_IFACE, 101, 0, 1024).build();
+                .addEntry(TEST_IFACE, 101, 0, 1024);
+
+        final NetworkStats after = new NetworkStats(TEST_START, 2)
+                .addEntry(TEST_IFACE, 100, 1024, 0)
+                .addEntry(TEST_IFACE, 101, 0, 1024);
 
         final NetworkStats result = after.subtract(before);
 
@@ -57,13 +84,13 @@
     }
 
     public void testSubtractIdenticalRows() throws Exception {
-        final NetworkStats before = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2)
+        final NetworkStats before = new NetworkStats(TEST_START, 2)
                 .addEntry(TEST_IFACE, 100, 1024, 0)
-                .addEntry(TEST_IFACE, 101, 0, 1024).build();
+                .addEntry(TEST_IFACE, 101, 0, 1024);
 
-        final NetworkStats after = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2)
+        final NetworkStats after = new NetworkStats(TEST_START, 2)
                 .addEntry(TEST_IFACE, 100, 1025, 2)
-                .addEntry(TEST_IFACE, 101, 3, 1028).build();
+                .addEntry(TEST_IFACE, 101, 3, 1028);
 
         final NetworkStats result = after.subtract(before);
 
@@ -75,14 +102,14 @@
     }
 
     public void testSubtractNewRows() throws Exception {
-        final NetworkStats before = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 2)
+        final NetworkStats before = new NetworkStats(TEST_START, 2)
                 .addEntry(TEST_IFACE, 100, 1024, 0)
-                .addEntry(TEST_IFACE, 101, 0, 1024).build();
+                .addEntry(TEST_IFACE, 101, 0, 1024);
 
-        final NetworkStats after = new NetworkStats.Builder(SystemClock.elapsedRealtime(), 3)
+        final NetworkStats after = new NetworkStats(TEST_START, 3)
                 .addEntry(TEST_IFACE, 100, 1024, 0)
                 .addEntry(TEST_IFACE, 101, 0, 1024)
-                .addEntry(TEST_IFACE, 102, 1024, 1024).build();
+                .addEntry(TEST_IFACE, 102, 1024, 1024);
 
         final NetworkStats result = after.subtract(before);
 
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 2b31462..9294df6 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -188,6 +188,11 @@
 
     status_t setBufferCountServerLocked(int bufferCount);
 
+    // computeCurrentTransformMatrix computes the transform matrix for the
+    // current texture.  It uses mCurrentTransform and the current GraphicBuffer
+    // to compute this matrix and stores it in mCurrentTransformMatrix.
+    void computeCurrentTransformMatrix();
+
     enum { INVALID_BUFFER_SLOT = -1 };
 
     struct BufferSlot {
@@ -288,9 +293,9 @@
     // by calling setBufferCount or setBufferCountServer
     int mBufferCount;
 
-    // mRequestedBufferCount is the number of buffer slots requested by the
-    // client. The default is zero, which means the client doesn't care how
-    // many buffers there is.
+    // mClientBufferCount is the number of buffer slots requested by the client.
+    // The default is zero, which means the client doesn't care how many buffers
+    // there is.
     int mClientBufferCount;
 
     // mServerBufferCount buffer count requested by the server-side
@@ -322,6 +327,11 @@
     // gets set to mLastQueuedTransform each time updateTexImage is called.
     uint32_t mCurrentTransform;
 
+    // mCurrentTransformMatrix is the transform matrix for the current texture.
+    // It gets computed by computeTransformMatrix each time updateTexImage is
+    // called.
+    float mCurrentTransformMatrix[16];
+
     // mCurrentTimestamp is the timestamp for the current texture. It
     // gets set to mLastQueuedTimestamp each time updateTexImage is called.
     int64_t mCurrentTimestamp;
@@ -362,6 +372,7 @@
     // variables of SurfaceTexture objects. It must be locked whenever the
     // member variables are accessed.
     mutable Mutex mMutex;
+
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 4044c5d..deade5e 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -55,6 +55,7 @@
     kKeyIsSyncFrame       = 'sync',  // int32_t (bool)
     kKeyIsCodecConfig     = 'conf',  // int32_t (bool)
     kKeyTime              = 'time',  // int64_t (usecs)
+    kKeyDecodingTime      = 'decT',  // int64_t (decoding timestamp in usecs)
     kKeyNTPTime           = 'ntpT',  // uint64_t (ntp-timestamp)
     kKeyTargetTime        = 'tarT',  // int64_t (usecs)
     kKeyDriftTime         = 'dftT',  // int64_t (usecs)
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 70daafa..589cefd 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -202,6 +202,10 @@
     bool mOnlySubmitOneBufferAtOneTime;
     bool mEnableGrallocUsageProtected;
 
+    // Used to record the decoding time for an output picture from
+    // a video encoder.
+    List<int64_t> mDecodingTimeList;
+
     OMXCodec(const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
              bool isEncoder, const char *mime, const char *componentName,
              const sp<MediaSource> &source,
@@ -317,6 +321,8 @@
 
     status_t applyRotation();
 
+    int64_t retrieveDecodingTimeUs(bool isCodecSpecific);
+
     OMXCodec(const OMXCodec &);
     OMXCodec &operator=(const OMXCodec &);
 };
diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h
index 717f837..0da03d1 100644
--- a/include/private/surfaceflinger/SharedBufferStack.h
+++ b/include/private/surfaceflinger/SharedBufferStack.h
@@ -20,355 +20,12 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <cutils/compiler.h>
-
 #include <utils/Debug.h>
-#include <utils/threads.h>
-#include <utils/String8.h>
-
-#include <ui/Rect.h>
 
 namespace android {
 // ---------------------------------------------------------------------------
 
-/*
- * These classes manage a stack of buffers in shared memory.
- * 
- * SharedClient: represents a client with several stacks
- * SharedBufferStack: represents a stack of buffers
- * SharedBufferClient: manipulates the SharedBufferStack from the client side 
- * SharedBufferServer: manipulates the SharedBufferStack from the server side 
- *
- * Buffers can be dequeued until there are none available, they can be locked
- * unless they are in use by the server, which is only the case for the last 
- * dequeue-able buffer. When these various conditions are not met, the caller
- * waits until the condition is met.
- * 
- */
-
-// ----------------------------------------------------------------------------
-
-class Region;
-class SharedBufferStack;
-class SharedClient;
-
-// ----------------------------------------------------------------------------
-
-class SharedBufferStack
-{
-    friend class SharedClient;
-    friend class SharedBufferBase;
-    friend class SharedBufferClient;
-    friend class SharedBufferServer;
-
-public:
-    // When changing these values, the COMPILE_TIME_ASSERT at the end of this
-    // file need to be updated.
-    static const unsigned int NUM_LAYERS_MAX  = 31;
-    static const unsigned int NUM_BUFFER_MAX  = 32;
-    static const unsigned int NUM_BUFFER_MIN  = 2;
-    static const unsigned int NUM_DISPLAY_MAX = 4;
-
-    struct Statistics { // 4 longs
-        typedef int32_t usecs_t;
-        usecs_t  totalTime;
-        usecs_t  reserved[3];
-    };
-
-    struct SmallRect {
-        uint16_t l, t, r, b;
-    };
-
-    struct FlatRegion { // 52 bytes = 4 * (1 + 2*N)
-        static const unsigned int NUM_RECT_MAX = 5;
-        uint32_t    count;
-        SmallRect   rects[NUM_RECT_MAX];
-    };
-    
-    struct BufferData {
-        FlatRegion dirtyRegion;
-        SmallRect  crop;
-        uint8_t transform;
-        uint8_t reserved[3];
-    };
-    
-    SharedBufferStack();
-    void init(int32_t identity);
-    status_t setDirtyRegion(int buffer, const Region& reg);
-    status_t setCrop(int buffer, const Rect& reg);
-    status_t setTransform(int buffer, uint8_t transform);
-    Region getDirtyRegion(int buffer) const;
-    Rect getCrop(int buffer) const;
-    uint32_t getTransform(int buffer) const;
-
-    // these attributes are part of the conditions/updates
-    volatile int32_t head;      // server's current front buffer
-    volatile int32_t available; // number of dequeue-able buffers
-    volatile int32_t queued;    // number of buffers waiting for post
-    volatile int32_t reserved1;
-    volatile status_t status;   // surface's status code
-
-    // not part of the conditions
-    volatile int32_t reallocMask;
-    volatile int8_t index[NUM_BUFFER_MAX];
-
-    int32_t     identity;       // surface's identity (const)
-    int32_t     token;          // surface's token (for debugging)
-    Statistics  stats;
-    int8_t      headBuf;        // last retired buffer
-    uint8_t     reservedBytes[3];
-    int32_t     reserved;
-    BufferData  buffers[NUM_BUFFER_MAX];     // 1024 bytes
-};
-
-// ----------------------------------------------------------------------------
-
-// 64 KB max
-class SharedClient
-{
-public:
-    SharedClient();
-    ~SharedClient();
-    status_t validate(size_t token) const;
-
-private:
-    friend class SharedBufferBase;
-    friend class SharedBufferClient;
-    friend class SharedBufferServer;
-
-    // FIXME: this should be replaced by a lock-less primitive
-    Mutex lock;
-    Condition cv;
-    SharedBufferStack surfaces[ SharedBufferStack::NUM_LAYERS_MAX ];
-};
-
-// ============================================================================
-
-class SharedBufferBase
-{
-public:
-    SharedBufferBase(SharedClient* sharedClient, int surface,
-            int32_t identity);
-    ~SharedBufferBase();
-    status_t getStatus() const;
-    int32_t getIdentity() const;
-    String8 dump(char const* prefix) const;
-
-protected:
-    SharedClient* const mSharedClient;
-    SharedBufferStack* const mSharedStack;
-    const int mIdentity;
-
-    friend struct Update;
-    friend struct QueueUpdate;
-
-    struct ConditionBase {
-        SharedBufferStack& stack;
-        inline ConditionBase(SharedBufferBase* sbc) 
-            : stack(*sbc->mSharedStack) { }
-        virtual ~ConditionBase() { };
-        virtual bool operator()() const = 0;
-        virtual const char* name() const = 0;
-    };
-    status_t waitForCondition(const ConditionBase& condition);
-
-    struct UpdateBase {
-        SharedBufferStack& stack;
-        inline UpdateBase(SharedBufferBase* sbb) 
-            : stack(*sbb->mSharedStack) { }
-    };
-    template <typename T>
-    status_t updateCondition(T update);
-};
-
-template <typename T>
-status_t SharedBufferBase::updateCondition(T update) {
-    SharedClient& client( *mSharedClient );
-    Mutex::Autolock _l(client.lock);
-    ssize_t result = update();
-    client.cv.broadcast();    
-    return result;
-}
-
-// ----------------------------------------------------------------------------
-
-class SharedBufferClient : public SharedBufferBase
-{
-public:
-    SharedBufferClient(SharedClient* sharedClient, int surface, int num,
-            int32_t identity);
-
-    ssize_t dequeue();
-    status_t undoDequeue(int buf);
-    
-    status_t lock(int buf);
-    status_t cancel(int buf);
-    status_t queue(int buf);
-    bool needNewBuffer(int buffer) const;
-    status_t setDirtyRegion(int buffer, const Region& reg);
-    status_t setCrop(int buffer, const Rect& reg);
-    status_t setTransform(int buffer, uint32_t transform);
-
-    class SetBufferCountCallback {
-        friend class SharedBufferClient;
-        virtual status_t operator()(int bufferCount) const = 0;
-    protected:
-        virtual ~SetBufferCountCallback() { }
-    };
-    status_t setBufferCount(int bufferCount, const SetBufferCountCallback& ipc);
-
-private:
-    friend struct Condition;
-    friend struct DequeueCondition;
-    friend struct LockCondition;
-
-    struct QueueUpdate : public UpdateBase {
-        inline QueueUpdate(SharedBufferBase* sbb);
-        inline ssize_t operator()();
-    };
-
-    struct DequeueUpdate : public UpdateBase {
-        inline DequeueUpdate(SharedBufferBase* sbb);
-        inline ssize_t operator()();
-    };
-
-    struct CancelUpdate : public UpdateBase {
-        int tail, buf;
-        inline CancelUpdate(SharedBufferBase* sbb, int tail, int buf);
-        inline ssize_t operator()();
-    };
-
-    // --
-
-    struct DequeueCondition : public ConditionBase {
-        inline DequeueCondition(SharedBufferClient* sbc);
-        inline bool operator()() const;
-        inline const char* name() const { return "DequeueCondition"; }
-    };
-
-    struct LockCondition : public ConditionBase {
-        int buf;
-        inline LockCondition(SharedBufferClient* sbc, int buf);
-        inline bool operator()() const;
-        inline const char* name() const { return "LockCondition"; }
-    };
-
-    int32_t computeTail() const;
-
-    mutable RWLock mLock;
-    int mNumBuffers;
-
-    int32_t tail;
-    int32_t queued_head;
-    // statistics...
-    nsecs_t mDequeueTime[SharedBufferStack::NUM_BUFFER_MAX];
-};
-
-// ----------------------------------------------------------------------------
-
-class SharedBufferServer
-    : public SharedBufferBase,
-      public LightRefBase<SharedBufferServer>
-{
-public:
-    SharedBufferServer(SharedClient* sharedClient, int surface, int num,
-            int32_t identity);
-
-    ssize_t retireAndLock();
-    void setStatus(status_t status);
-    status_t reallocateAll();
-    status_t reallocateAllExcept(int buffer);
-    int32_t getQueuedCount() const;
-    Region getDirtyRegion(int buffer) const;
-    Rect getCrop(int buffer) const;
-    uint32_t getTransform(int buffer) const;
-
-    status_t resize(int newNumBuffers);
-    status_t grow(int newNumBuffers);
-    status_t shrink(int newNumBuffers);
-
-    SharedBufferStack::Statistics getStats() const;
-    
-
-private:
-    friend class LightRefBase<SharedBufferServer>;
-    ~SharedBufferServer();
-
-    /*
-     * BufferList is basically a fixed-capacity sorted-vector of
-     * unsigned 5-bits ints using a 32-bits int as storage.
-     * it has efficient iterators to find items in the list and not in the list.
-     */
-    class BufferList {
-        size_t mCapacity;
-        uint32_t mList;
-    public:
-        BufferList(size_t c = SharedBufferStack::NUM_BUFFER_MAX)
-            : mCapacity(c), mList(0) { }
-        status_t add(int value);
-        status_t remove(int value);
-        uint32_t getMask() const { return mList; }
-
-        class const_iterator {
-            friend class BufferList;
-            uint32_t mask, curr;
-            const_iterator(uint32_t mask) :
-                mask(mask), curr(__builtin_clz(mask)) {
-            }
-        public:
-            inline bool operator == (const const_iterator& rhs) const {
-                return mask == rhs.mask;
-            }
-            inline bool operator != (const const_iterator& rhs) const {
-                return mask != rhs.mask;
-            }
-            inline int operator *() const { return curr; }
-            inline const const_iterator& operator ++() {
-                mask &= ~(1<<(31-curr));
-                curr = __builtin_clz(mask);
-                return *this;
-            }
-        };
-
-        inline const_iterator begin() const {
-            return const_iterator(mList);
-        }
-        inline const_iterator end() const   {
-            return const_iterator(0);
-        }
-        inline const_iterator free_begin() const {
-            uint32_t mask = (1 << (32-mCapacity)) - 1;
-            return const_iterator( ~(mList | mask) );
-        }
-    };
-
-    // this protects mNumBuffers and mBufferList
-    mutable RWLock mLock;
-    int mNumBuffers;
-    BufferList mBufferList;
-
-    struct BuffersAvailableCondition : public ConditionBase {
-        int mNumBuffers;
-        inline BuffersAvailableCondition(SharedBufferServer* sbs,
-                int numBuffers);
-        inline bool operator()() const;
-        inline const char* name() const { return "BuffersAvailableCondition"; }
-    };
-
-    struct RetireUpdate : public UpdateBase {
-        const int numBuffers;
-        inline RetireUpdate(SharedBufferBase* sbb, int numBuffers);
-        inline ssize_t operator()();
-    };
-
-    struct StatusUpdate : public UpdateBase {
-        const status_t status;
-        inline StatusUpdate(SharedBufferBase* sbb, status_t status);
-        inline ssize_t operator()();
-    };
-};
-
-// ===========================================================================
+#define NUM_DISPLAY_MAX 4
 
 struct display_cblk_t
 {
@@ -389,12 +46,11 @@
     uint8_t         connected;
     uint8_t         reserved[3];
     uint32_t        pad[7];
-    display_cblk_t  displays[SharedBufferStack::NUM_DISPLAY_MAX];
+    display_cblk_t  displays[NUM_DISPLAY_MAX];
 };
 
 // ---------------------------------------------------------------------------
 
-COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 65536)
 COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096)
 
 // ---------------------------------------------------------------------------
diff --git a/include/surfaceflinger/IGraphicBufferAlloc.h b/include/surfaceflinger/IGraphicBufferAlloc.h
index 01e4bd9..e1b6b57 100644
--- a/include/surfaceflinger/IGraphicBufferAlloc.h
+++ b/include/surfaceflinger/IGraphicBufferAlloc.h
@@ -27,6 +27,8 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+class GraphicBuffer;
+
 class IGraphicBufferAlloc : public IInterface
 {
 public:
diff --git a/include/surfaceflinger/ISurface.h b/include/surfaceflinger/ISurface.h
index cd0ee40..5fdf234 100644
--- a/include/surfaceflinger/ISurface.h
+++ b/include/surfaceflinger/ISurface.h
@@ -27,42 +27,23 @@
 
 #include <ui/PixelFormat.h>
 
-#include <hardware/hardware.h>
-#include <hardware/gralloc.h>
-
 namespace android {
 
 typedef int32_t    SurfaceID;
 
-class GraphicBuffer;
+class ISurfaceTexture;
 
 class ISurface : public IInterface
 {
 protected:
     enum {
-        RESERVED0 = IBinder::FIRST_CALL_TRANSACTION,
-        RESERVED1,
-        RESERVED2,
-        REQUEST_BUFFER,
-        SET_BUFFER_COUNT,
+        GET_SURFACE_TEXTURE = IBinder::FIRST_CALL_TRANSACTION,
     };
 
 public: 
     DECLARE_META_INTERFACE(Surface);
 
-    /*
-     * requests a new buffer for the given index. If w, h, or format are
-     * null the buffer is created with the parameters assigned to the
-     * surface it is bound to. Otherwise the buffer's parameters are
-     * set to those specified.
-     */
-    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
-            uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0;
-
-    /*
-     * sets the number of buffers dequeuable for this surface.
-     */
-    virtual status_t setBufferCount(int bufferCount) = 0;
+    virtual sp<ISurfaceTexture> getSurfaceTexture() const = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index dea1b10..03fd01b 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -33,6 +33,8 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+class IMemoryHeap;
+
 class ISurfaceComposer : public IInterface
 {
 public:
@@ -95,10 +97,6 @@
      */
     virtual sp<ISurfaceComposerClient> createConnection() = 0;
 
-    /* create a client connection with surface flinger
-     */
-    virtual sp<ISurfaceComposerClient> createClientConnection() = 0;
-
     /* create a graphic buffer allocator
      */
     virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc() = 0;
@@ -134,11 +132,6 @@
     virtual status_t turnElectronBeamOff(int32_t mode) = 0;
     virtual status_t turnElectronBeamOn(int32_t mode) = 0;
 
-    /* Signal surfaceflinger that there might be some work to do
-     * This is an ASYNCHRONOUS call.
-     */
-    virtual void signal() const = 0;
-
     /* verify that an ISurface was created by SurfaceFlinger.
      */
     virtual bool authenticateSurface(const sp<ISurface>& surface) const = 0;
@@ -154,7 +147,6 @@
         // Java by ActivityManagerService.
         BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
         CREATE_CONNECTION,
-        CREATE_CLIENT_CONNECTION,
         CREATE_GRAPHIC_BUFFER_ALLOC,
         GET_CBLK,
         OPEN_GLOBAL_TRANSACTION,
@@ -162,7 +154,6 @@
         SET_ORIENTATION,
         FREEZE_DISPLAY,
         UNFREEZE_DISPLAY,
-        SIGNAL,
         CAPTURE_SCREEN,
         TURN_ELECTRON_BEAM_OFF,
         TURN_ELECTRON_BEAM_ON,
diff --git a/include/surfaceflinger/ISurfaceComposerClient.h b/include/surfaceflinger/ISurfaceComposerClient.h
index 46b1bb7..2e75a0e 100644
--- a/include/surfaceflinger/ISurfaceComposerClient.h
+++ b/include/surfaceflinger/ISurfaceComposerClient.h
@@ -33,9 +33,6 @@
 
 // ----------------------------------------------------------------------------
 
-class IMemoryHeap;
-
-typedef int32_t    ClientID;
 typedef int32_t    DisplayID;
 
 // ----------------------------------------------------------------------------
@@ -57,9 +54,6 @@
         status_t writeToParcel(Parcel* parcel) const;
     };
 
-    virtual sp<IMemoryHeap> getControlBlock() const = 0;
-    virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const = 0;
-
     /*
      * Requires ACCESS_SURFACE_FLINGER permission
      */
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index ab30f45..8845dc9 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -43,9 +43,7 @@
 class Rect;
 class Surface;
 class SurfaceComposerClient;
-class SharedClient;
-class SharedBufferClient;
-class SurfaceClient;
+class SurfaceTextureClient;
 
 // ---------------------------------------------------------------------------
 
@@ -162,9 +160,6 @@
     status_t    lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
     status_t    unlockAndPost();
 
-    // setSwapRectangle() is intended to be used by GL ES clients
-    void        setSwapRectangle(const Rect& r);
-
     sp<IBinder> asBinder() const;
 
 private:
@@ -209,6 +204,7 @@
     static int query(const ANativeWindow* window, int what, int* value);
     static int perform(ANativeWindow* window, int operation, ...);
 
+    int setSwapInterval(int interval);
     int dequeueBuffer(ANativeWindowBuffer** buffer);
     int lockBuffer(ANativeWindowBuffer* buffer);
     int queueBuffer(ANativeWindowBuffer* buffer);
@@ -216,83 +212,23 @@
     int query(int what, int* value) const;
     int perform(int operation, va_list args);
 
-    void dispatch_setUsage(va_list args);
-    int  dispatch_connect(va_list args);
-    int  dispatch_disconnect(va_list args);
-    int  dispatch_crop(va_list args);
-    int  dispatch_set_buffer_count(va_list args);
-    int  dispatch_set_buffers_geometry(va_list args);
-    int  dispatch_set_buffers_transform(va_list args);
-    int  dispatch_set_buffers_timestamp(va_list args);
-
-    void setUsage(uint32_t reqUsage);
-    int  connect(int api);
-    int  disconnect(int api);
-    int  crop(Rect const* rect);
-    int  setBufferCount(int bufferCount);
-    int  setBuffersGeometry(int w, int h, int format);
-    int  setBuffersTransform(int transform);
-    int  setBuffersTimestamp(int64_t timestamp);
-
     /*
      *  private stuff...
      */
     void init();
     status_t validate(bool inCancelBuffer = false) const;
 
-    // When the buffer pool is a fixed size we want to make sure SurfaceFlinger
-    // won't stall clients, so we require an extra buffer.
-    enum { MIN_UNDEQUEUED_BUFFERS = 2 };
-
-    inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; }
-    inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; }
-
-    status_t getBufferLocked(int index,
-            uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
-    int getBufferIndex(const sp<GraphicBuffer>& buffer) const;
-
     int getConnectedApi() const;
     
-    bool needNewBuffer(int bufIdx,
-            uint32_t *pWidth, uint32_t *pHeight,
-            uint32_t *pFormat, uint32_t *pUsage) const;
-
     static void cleanCachedSurfacesLocked();
 
-    class BufferInfo {
-        uint32_t mWidth;
-        uint32_t mHeight;
-        uint32_t mFormat;
-        uint32_t mUsage;
-        mutable uint32_t mDirty;
-        enum {
-            GEOMETRY = 0x01
-        };
-    public:
-        BufferInfo();
-        void set(uint32_t w, uint32_t h, uint32_t format);
-        void set(uint32_t usage);
-        void get(uint32_t *pWidth, uint32_t *pHeight,
-                uint32_t *pFormat, uint32_t *pUsage) const;
-        bool validateBuffer(const sp<GraphicBuffer>& buffer) const;
-    };
-
     // constants
-    GraphicBufferMapper&        mBufferMapper;
-    SurfaceClient&              mClient;
-    SharedBufferClient*         mSharedBufferClient;
     status_t                    mInitCheck;
     sp<ISurface>                mSurface;
+    sp<SurfaceTextureClient>    mSurfaceTextureClient;
     uint32_t                    mIdentity;
     PixelFormat                 mFormat;
     uint32_t                    mFlags;
-
-    // protected by mSurfaceLock
-    Rect                        mSwapRectangle;
-    int                         mConnected;
-    Rect                        mNextBufferCrop;
-    uint32_t                    mNextBufferTransform;
-    BufferInfo                  mBufferInfo;
     
     // protected by mSurfaceLock. These are also used from lock/unlock
     // but in that case, they must be called form the same thread.
@@ -304,9 +240,6 @@
     mutable Region              mOldDirtyRegion;
     bool                        mReserved;
 
-    // only used from dequeueBuffer()
-    Vector< sp<GraphicBuffer> > mBuffers;
-
     // query() must be called from dequeueBuffer() thread
     uint32_t                    mWidth;
     uint32_t                    mHeight;
diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h
index c61a5bf..140b9f8 100644
--- a/include/surfaceflinger/SurfaceComposerClient.h
+++ b/include/surfaceflinger/SurfaceComposerClient.h
@@ -36,10 +36,10 @@
 
 // ---------------------------------------------------------------------------
 
-class Region;
-class SharedClient;
-class ISurfaceComposer;
 class DisplayInfo;
+class IMemoryHeap;
+class ISurfaceComposer;
+class Region;
 class surface_flinger_cblk_t;
 
 // ---------------------------------------------------------------------------
diff --git a/include/utils/BlobCache.h b/include/utils/BlobCache.h
new file mode 100644
index 0000000..8f76d72
--- /dev/null
+++ b/include/utils/BlobCache.h
@@ -0,0 +1,181 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#ifndef ANDROID_BLOB_CACHE_H
+#define ANDROID_BLOB_CACHE_H
+
+#include <stddef.h>
+
+#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
+#include <utils/threads.h>
+
+namespace android {
+
+// A BlobCache is an in-memory cache for binary key/value pairs. All the public
+// methods are thread-safe.
+//
+// The cache contents can be serialized to a file and reloaded in a subsequent
+// execution of the program. This serialization is non-portable and should only
+// be loaded by the device that generated it.
+class BlobCache : public RefBase {
+public:
+
+    // Create an empty blob cache. The blob cache will cache key/value pairs
+    // with key and value sizes less than or equal to maxKeySize and
+    // maxValueSize, respectively. The total combined size of ALL cache entries
+    // (key sizes plus value sizes) will not exceed maxTotalSize.
+    BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize);
+
+    // set inserts a new binary value into the cache and associates it with the
+    // given binary key.  If the key or value are too large for the cache then
+    // the cache remains unchanged.  This includes the case where a different
+    // value was previously associated with the given key - the old value will
+    // remain in the cache.  If the given key and value are small enough to be
+    // put in the cache (based on the maxKeySize, maxValueSize, and maxTotalSize
+    // values specified to the BlobCache constructor), then the key/value pair
+    // will be in the cache after set returns.  Note, however, that a subsequent
+    // call to set may evict old key/value pairs from the cache.
+    //
+    // Preconditions:
+    //   key != NULL
+    //   0 < keySize
+    //   value != NULL
+    //   0 < valueSize
+    void set(const void* key, size_t keySize, const void* value,
+            size_t valueSize);
+
+    // The get function retrieves from the cache the binary value associated
+    // with a given binary key.  If the key is present in the cache then the
+    // length of the binary value associated with that key is returned.  If the
+    // value argument is non-NULL and the size of the cached value is less than
+    // valueSize bytes then the cached value is copied into the buffer pointed
+    // to by the value argument.  If the key is not present in the cache then 0
+    // is returned and the buffer pointed to by the value argument is not
+    // modified.
+    //
+    // Note that when calling get multiple times with the same key, the later
+    // calls may fail, returning 0, even if earlier calls succeeded.  The return
+    // value must be checked for each call.
+    //
+    // Preconditions:
+    //   key != NULL
+    //   0 < keySize
+    //   0 <= valueSize
+    size_t get(const void* key, size_t keySize, void* value, size_t valueSize);
+
+private:
+    // Copying is disallowed.
+    BlobCache(const BlobCache&);
+    void operator=(const BlobCache&);
+
+    // clean evicts a randomly chosen set of entries from the cache such that
+    // the total size of all remaining entries is less than mMaxTotalSize/2.
+    void clean();
+
+    // isCleanable returns true if the cache is full enough for the clean method
+    // to have some effect, and false otherwise.
+    bool isCleanable() const;
+
+    // A Blob is an immutable sized unstructured data blob.
+    class Blob : public RefBase {
+    public:
+        Blob(const void* data, size_t size, bool copyData);
+        ~Blob();
+
+        bool operator<(const Blob& rhs) const;
+
+        const void* getData() const;
+        size_t getSize() const;
+
+    private:
+        // Copying is not allowed.
+        Blob(const Blob&);
+        void operator=(const Blob&);
+
+        // mData points to the buffer containing the blob data.
+        const void* mData;
+
+        // mSize is the size of the blob data in bytes.
+        size_t mSize;
+
+        // mOwnsData indicates whether or not this Blob object should free the
+        // memory pointed to by mData when the Blob gets destructed.
+        bool mOwnsData;
+    };
+
+    // A CacheEntry is a single key/value pair in the cache.
+    class CacheEntry {
+    public:
+        CacheEntry();
+        CacheEntry(const sp<Blob>& key, const sp<Blob>& value);
+        CacheEntry(const CacheEntry& ce);
+
+        bool operator<(const CacheEntry& rhs) const;
+        const CacheEntry& operator=(const CacheEntry&);
+
+        sp<Blob> getKey() const;
+        sp<Blob> getValue() const;
+
+        void setValue(const sp<Blob>& value);
+
+    private:
+
+        // mKey is the key that identifies the cache entry.
+        sp<Blob> mKey;
+
+        // mValue is the cached data associated with the key.
+        sp<Blob> mValue;
+    };
+
+    // mMaxKeySize is the maximum key size that will be cached. Calls to
+    // BlobCache::set with a keySize parameter larger than mMaxKeySize will
+    // simply not add the key/value pair to the cache.
+    const size_t mMaxKeySize;
+
+    // mMaxValueSize is the maximum value size that will be cached. Calls to
+    // BlobCache::set with a valueSize parameter larger than mMaxValueSize will
+    // simply not add the key/value pair to the cache.
+    const size_t mMaxValueSize;
+
+    // mMaxTotalSize is the maximum size that all cache entries can occupy. This
+    // includes space for both keys and values. When a call to BlobCache::set
+    // would otherwise cause this limit to be exceeded, either the key/value
+    // pair passed to BlobCache::set will not be cached or other cache entries
+    // will be evicted from the cache to make room for the new entry.
+    const size_t mMaxTotalSize;
+
+    // mTotalSize is the total combined size of all keys and values currently in
+    // the cache.
+    size_t mTotalSize;
+
+    // mRandState is the pseudo-random number generator state. It is passed to
+    // nrand48 to generate random numbers when needed. It must be protected by
+    // mMutex.
+    unsigned short mRandState[3];
+
+    // mCacheEntries stores all the cache entries that are resident in memory.
+    // Cache entries are added to it by the 'set' method.
+    SortedVector<CacheEntry> mCacheEntries;
+
+    // mMutex is used to synchronize access to all member variables.  It must be
+    // locked any time the member variables are written or read.
+    Mutex mMutex;
+};
+
+}
+
+#endif // ANDROID_BLOB_CACHE_H
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index 4126225..f8c3216 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -116,17 +116,23 @@
 
     typedef RefBase basetype;
 
+    // used to override the RefBase destruction.
+    class Destroyer {
+        friend class RefBase;
+    public:
+        virtual ~Destroyer();
+    private:
+        virtual void destroy(RefBase const* base) = 0;
+    };
+
+    // Make sure to never acquire a strong reference from this function. The
+    // same restrictions than for destructors apply.
+    void setDestroyer(Destroyer* destroyer);
+
 protected:
                             RefBase();
     virtual                 ~RefBase();
 
-    // called when the last reference goes away. this is responsible for
-    // calling the destructor. The default implementation just does
-    // "delete this;".
-    // Make sure to never acquire a strong reference from this function. The
-    // same restrictions than for destructors apply.
-    virtual void            destroy() const;
-
     //! Flags for extendObjectLifetime()
     enum {
         OBJECT_LIFETIME_WEAK    = 0x0001,
diff --git a/include/utils/threads.h b/include/utils/threads.h
index 41e5766..0bd69cf 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -526,6 +526,7 @@
     Thread& operator=(const Thread&);
     static  int             _threadLoop(void* user);
     const   bool            mCanCallJava;
+    // always hold mLock when reading or writing
             thread_id_t     mThread;
     mutable Mutex           mLock;
             Condition       mThreadExitedCondition;
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index b5737ff..4070eba 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -16,7 +16,6 @@
 	ISurfaceComposerClient.cpp \
 	IGraphicBufferAlloc.cpp \
 	LayerState.cpp \
-	SharedBufferStack.cpp \
 	Surface.cpp \
 	SurfaceComposerClient.cpp \
 
diff --git a/libs/gui/ISurface.cpp b/libs/gui/ISurface.cpp
index 23b90af..96155d7 100644
--- a/libs/gui/ISurface.cpp
+++ b/libs/gui/ISurface.cpp
@@ -22,9 +22,7 @@
 
 #include <binder/Parcel.h>
 
-#include <ui/GraphicBuffer.h>
-
-#include <surfaceflinger/Surface.h>
+#include <gui/ISurfaceTexture.h>
 #include <surfaceflinger/ISurface.h>
 
 namespace android {
@@ -39,30 +37,11 @@
     {
     }
 
-    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
-            uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
-    {
+    virtual sp<ISurfaceTexture> getSurfaceTexture() const {
         Parcel data, reply;
         data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
-        data.writeInt32(bufferIdx);
-        data.writeInt32(w);
-        data.writeInt32(h);
-        data.writeInt32(format);
-        data.writeInt32(usage);
-        remote()->transact(REQUEST_BUFFER, data, &reply);
-        sp<GraphicBuffer> buffer = new GraphicBuffer();
-        reply.read(*buffer);
-        return buffer;
-    }
-
-    virtual status_t setBufferCount(int bufferCount)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
-        data.writeInt32(bufferCount);
-        remote()->transact(SET_BUFFER_COUNT, data, &reply);
-        status_t err = reply.readInt32();
-        return err;
+        remote()->transact(GET_SURFACE_TEXTURE, data, &reply);
+        return interface_cast<ISurfaceTexture>(reply.readStrongBinder());
     }
 };
 
@@ -74,23 +53,9 @@
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
     switch(code) {
-        case REQUEST_BUFFER: {
+        case GET_SURFACE_TEXTURE: {
             CHECK_INTERFACE(ISurface, data, reply);
-            int bufferIdx = data.readInt32();
-            uint32_t w = data.readInt32();
-            uint32_t h = data.readInt32();
-            uint32_t format = data.readInt32();
-            uint32_t usage = data.readInt32();
-            sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, w, h, format, usage));
-            if (buffer == NULL)
-                return BAD_VALUE;
-            return reply->write(*buffer);
-        }
-        case SET_BUFFER_COUNT: {
-            CHECK_INTERFACE(ISurface, data, reply);
-            int bufferCount = data.readInt32();
-            status_t err = setBufferCount(bufferCount);
-            reply->writeInt32(err);
+            reply->writeStrongBinder( getSurfaceTexture()->asBinder() );
             return NO_ERROR;
         }
         default:
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 8951c3f..40450a3 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -57,15 +57,6 @@
         return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
     }
 
-    virtual sp<ISurfaceComposerClient> createClientConnection()
-    {
-        uint32_t n;
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        remote()->transact(BnSurfaceComposer::CREATE_CLIENT_CONNECTION, data, &reply);
-        return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
-    }
-
     virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc()
     {
         uint32_t n;
@@ -174,13 +165,6 @@
         return reply.readInt32();
     }
 
-    virtual void signal() const
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        remote()->transact(BnSurfaceComposer::SIGNAL, data, &reply, IBinder::FLAG_ONEWAY);
-    }
-
     virtual bool authenticateSurface(const sp<ISurface>& surface) const
     {
         Parcel data, reply;
@@ -229,11 +213,6 @@
             sp<IBinder> b = createConnection()->asBinder();
             reply->writeStrongBinder(b);
         } break;
-        case CREATE_CLIENT_CONNECTION: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> b = createClientConnection()->asBinder();
-            reply->writeStrongBinder(b);
-        } break;
         case CREATE_GRAPHIC_BUFFER_ALLOC: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> b = createGraphicBufferAlloc()->asBinder();
@@ -270,10 +249,6 @@
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             bootFinished();
         } break;
-        case SIGNAL: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            signal();
-        } break;
         case GET_CBLK: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> b = getCblk()->asBinder();
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index ea38e08..8d83392 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -50,9 +50,7 @@
 namespace android {
 
 enum {
-    GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
-    GET_TOKEN,
-    CREATE_SURFACE,
+    CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
     DESTROY_SURFACE,
     SET_STATE
 };
@@ -65,23 +63,6 @@
     {
     }
 
-    virtual sp<IMemoryHeap> getControlBlock() const
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
-        remote()->transact(GET_CBLK, data, &reply);
-        return interface_cast<IMemoryHeap>(reply.readStrongBinder());
-    }
-
-    virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
-        data.writeStrongBinder(sur->asBinder());
-        remote()->transact(GET_TOKEN, data, &reply);
-        return reply.readInt32();
-    }
-
     virtual sp<ISurface> createSurface( surface_data_t* params,
                                         const String8& name,
                                         DisplayID display,
@@ -131,41 +112,6 @@
 status_t BnSurfaceComposerClient::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
-    // codes that don't require permission check
-
-    switch(code) {
-        case GET_CBLK: {
-            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
-            sp<IMemoryHeap> ctl(getControlBlock());
-            reply->writeStrongBinder(ctl->asBinder());
-            return NO_ERROR;
-        } break;
-        case GET_TOKEN: {
-            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
-            sp<ISurface> sur = interface_cast<ISurface>(data.readStrongBinder());
-            ssize_t token = getTokenForSurface(sur);
-            reply->writeInt32(token);
-            return NO_ERROR;
-        } break;
-    }
-
-    // these must be checked
-
-     IPCThreadState* ipc = IPCThreadState::self();
-     const int pid = ipc->getCallingPid();
-     const int uid = ipc->getCallingUid();
-     const int self_pid = getpid();
-     if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) {
-         // we're called from a different process, do the real check
-         if (!checkCallingPermission(
-                 String16("android.permission.ACCESS_SURFACE_FLINGER")))
-         {
-             LOGE("Permission Denial: "
-                     "can't openGlobalTransaction pid=%d, uid=%d", pid, uid);
-             return PERMISSION_DENIED;
-         }
-     }
-
      switch(code) {
         case CREATE_SURFACE: {
             CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
diff --git a/libs/gui/SharedBufferStack.cpp b/libs/gui/SharedBufferStack.cpp
deleted file mode 100644
index 7505d53..0000000
--- a/libs/gui/SharedBufferStack.cpp
+++ /dev/null
@@ -1,714 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "SharedBufferStack"
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Debug.h>
-#include <utils/Log.h>
-#include <utils/threads.h>
-
-#include <private/surfaceflinger/SharedBufferStack.h>
-
-#include <ui/Rect.h>
-#include <ui/Region.h>
-
-#define DEBUG_ATOMICS 0
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-SharedClient::SharedClient()
-    : lock(Mutex::SHARED), cv(Condition::SHARED)
-{
-}
-
-SharedClient::~SharedClient() {
-}
-
-
-// these functions are used by the clients
-status_t SharedClient::validate(size_t i) const {
-    if (uint32_t(i) >= uint32_t(SharedBufferStack::NUM_LAYERS_MAX))
-        return BAD_INDEX;
-    return surfaces[i].status;
-}
-
-// ----------------------------------------------------------------------------
-
-
-SharedBufferStack::SharedBufferStack()
-{
-}
-
-void SharedBufferStack::init(int32_t i)
-{
-    status = NO_ERROR;
-    identity = i;
-}
-
-status_t SharedBufferStack::setCrop(int buffer, const Rect& crop)
-{
-    if (uint32_t(buffer) >= NUM_BUFFER_MAX)
-        return BAD_INDEX;
-
-    buffers[buffer].crop.l = uint16_t(crop.left);
-    buffers[buffer].crop.t = uint16_t(crop.top);
-    buffers[buffer].crop.r = uint16_t(crop.right);
-    buffers[buffer].crop.b = uint16_t(crop.bottom);
-    return NO_ERROR;
-}
-
-status_t SharedBufferStack::setTransform(int buffer, uint8_t transform)
-{
-    if (uint32_t(buffer) >= NUM_BUFFER_MAX)
-        return BAD_INDEX;
-    buffers[buffer].transform = transform;
-    return NO_ERROR;
-}
-
-status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty)
-{
-    if (uint32_t(buffer) >= NUM_BUFFER_MAX)
-        return BAD_INDEX;
-
-    FlatRegion& reg(buffers[buffer].dirtyRegion);
-    if (dirty.isEmpty()) {
-        reg.count = 0;
-        return NO_ERROR;
-    }
-
-    size_t count;
-    Rect const* r = dirty.getArray(&count);
-    if (count > FlatRegion::NUM_RECT_MAX) {
-        const Rect bounds(dirty.getBounds());
-        reg.count = 1;
-        reg.rects[0].l = uint16_t(bounds.left);
-        reg.rects[0].t = uint16_t(bounds.top);
-        reg.rects[0].r = uint16_t(bounds.right);
-        reg.rects[0].b = uint16_t(bounds.bottom);
-    } else {
-        reg.count = count;
-        for (size_t i=0 ; i<count ; i++) {
-            reg.rects[i].l = uint16_t(r[i].left);
-            reg.rects[i].t = uint16_t(r[i].top);
-            reg.rects[i].r = uint16_t(r[i].right);
-            reg.rects[i].b = uint16_t(r[i].bottom);
-        }
-    }
-    return NO_ERROR;
-}
-
-Region SharedBufferStack::getDirtyRegion(int buffer) const
-{
-    Region res;
-    if (uint32_t(buffer) >= NUM_BUFFER_MAX)
-        return res;
-
-    const FlatRegion& reg(buffers[buffer].dirtyRegion);
-    if (reg.count > FlatRegion::NUM_RECT_MAX)
-        return res;
-
-    if (reg.count == 1) {
-        const Rect r(
-                reg.rects[0].l,
-                reg.rects[0].t,
-                reg.rects[0].r,
-                reg.rects[0].b);
-        res.set(r);
-    } else {
-        for (size_t i=0 ; i<reg.count ; i++) {
-            const Rect r(
-                    reg.rects[i].l,
-                    reg.rects[i].t,
-                    reg.rects[i].r,
-                    reg.rects[i].b);
-            res.orSelf(r);
-        }
-    }
-    return res;
-}
-
-Rect SharedBufferStack::getCrop(int buffer) const
-{
-    Rect res(-1, -1);
-    if (uint32_t(buffer) >= NUM_BUFFER_MAX)
-        return res;
-    res.left = buffers[buffer].crop.l;
-    res.top = buffers[buffer].crop.t;
-    res.right = buffers[buffer].crop.r;
-    res.bottom = buffers[buffer].crop.b;
-    return res;
-}
-
-uint32_t SharedBufferStack::getTransform(int buffer) const
-{
-    if (uint32_t(buffer) >= NUM_BUFFER_MAX)
-        return 0;
-    return buffers[buffer].transform;
-}
-
-
-// ----------------------------------------------------------------------------
-
-SharedBufferBase::SharedBufferBase(SharedClient* sharedClient,
-        int surface, int32_t identity)
-    : mSharedClient(sharedClient), 
-      mSharedStack(sharedClient->surfaces + surface),
-      mIdentity(identity)
-{
-}
-
-SharedBufferBase::~SharedBufferBase()
-{
-}
-
-status_t SharedBufferBase::getStatus() const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.status;
-}
-
-int32_t SharedBufferBase::getIdentity() const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.identity;
-}
-
-String8 SharedBufferBase::dump(char const* prefix) const
-{
-    const size_t SIZE = 1024;
-    char buffer[SIZE];
-    String8 result;
-    SharedBufferStack& stack( *mSharedStack );
-    snprintf(buffer, SIZE, 
-            "%s[ head=%2d, available=%2d, queued=%2d ] "
-            "reallocMask=%08x, identity=%d, status=%d",
-            prefix, stack.head, stack.available, stack.queued,
-            stack.reallocMask, stack.identity, stack.status);
-    result.append(buffer);
-    result.append("\n");
-    return result;
-}
-
-status_t SharedBufferBase::waitForCondition(const ConditionBase& condition)
-{
-    const SharedBufferStack& stack( *mSharedStack );
-    SharedClient& client( *mSharedClient );
-    const nsecs_t TIMEOUT = s2ns(1);
-    const int identity = mIdentity;
-
-    Mutex::Autolock _l(client.lock);
-    while ((condition()==false) &&
-            (stack.identity == identity) &&
-            (stack.status == NO_ERROR))
-    {
-        status_t err = client.cv.waitRelative(client.lock, TIMEOUT);
-        // handle errors and timeouts
-        if (CC_UNLIKELY(err != NO_ERROR)) {
-            if (err == TIMED_OUT) {
-                if (condition()) {
-                    LOGE("waitForCondition(%s) timed out (identity=%d), "
-                        "but condition is true! We recovered but it "
-                        "shouldn't happen." , condition.name(), stack.identity);
-                    break;
-                } else {
-                    LOGW("waitForCondition(%s) timed out "
-                        "(identity=%d, status=%d). "
-                        "CPU may be pegged. trying again.", condition.name(),
-                        stack.identity, stack.status);
-                }
-            } else {
-                LOGE("waitForCondition(%s) error (%s) ",
-                        condition.name(), strerror(-err));
-                return err;
-            }
-        }
-    }
-    return (stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status;
-}
-// ============================================================================
-// conditions and updates
-// ============================================================================
-
-SharedBufferClient::DequeueCondition::DequeueCondition(
-        SharedBufferClient* sbc) : ConditionBase(sbc)  { 
-}
-bool SharedBufferClient::DequeueCondition::operator()() const {
-    return stack.available > 0;
-}
-
-SharedBufferClient::LockCondition::LockCondition(
-        SharedBufferClient* sbc, int buf) : ConditionBase(sbc), buf(buf) { 
-}
-bool SharedBufferClient::LockCondition::operator()() const {
-    // NOTE: if stack.head is messed up, we could crash the client
-    // or cause some drawing artifacts. This is okay, as long as it is
-    // limited to the client.
-    return (buf != stack.index[stack.head]);
-}
-
-SharedBufferServer::BuffersAvailableCondition::BuffersAvailableCondition(
-        SharedBufferServer* sbs, int numBuffers) : ConditionBase(sbs),
-        mNumBuffers(numBuffers) {
-}
-bool SharedBufferServer::BuffersAvailableCondition::operator()() const {
-    return stack.available == mNumBuffers;
-}
-
-// ----------------------------------------------------------------------------
-
-SharedBufferClient::QueueUpdate::QueueUpdate(SharedBufferBase* sbb)
-    : UpdateBase(sbb) {    
-}
-ssize_t SharedBufferClient::QueueUpdate::operator()() {
-    android_atomic_inc(&stack.queued);
-    return NO_ERROR;
-}
-
-SharedBufferClient::DequeueUpdate::DequeueUpdate(SharedBufferBase* sbb)
-    : UpdateBase(sbb) {
-}
-ssize_t SharedBufferClient::DequeueUpdate::operator()() {
-    if (android_atomic_dec(&stack.available) == 0) {
-        LOGW("dequeue probably called from multiple threads!");
-    }
-    return NO_ERROR;
-}
-
-SharedBufferClient::CancelUpdate::CancelUpdate(SharedBufferBase* sbb,
-        int tail, int buf)
-    : UpdateBase(sbb), tail(tail), buf(buf) {
-}
-ssize_t SharedBufferClient::CancelUpdate::operator()() {
-    stack.index[tail] = buf;
-    android_atomic_inc(&stack.available);
-    return NO_ERROR;
-}
-
-SharedBufferServer::RetireUpdate::RetireUpdate(
-        SharedBufferBase* sbb, int numBuffers)
-    : UpdateBase(sbb), numBuffers(numBuffers) {
-}
-ssize_t SharedBufferServer::RetireUpdate::operator()() {
-    int32_t head = stack.head;
-    if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX)
-        return BAD_VALUE;
-
-    // Decrement the number of queued buffers 
-    int32_t queued;
-    do {
-        queued = stack.queued;
-        if (queued == 0) {
-            return NOT_ENOUGH_DATA;
-        }
-    } while (android_atomic_cmpxchg(queued, queued-1, &stack.queued));
-    
-    // lock the buffer before advancing head, which automatically unlocks
-    // the buffer we preventively locked upon entering this function
-
-    head = (head + 1) % numBuffers;
-    const int8_t headBuf = stack.index[head];
-    stack.headBuf = headBuf;
-
-    // head is only modified here, so we don't need to use cmpxchg
-    android_atomic_write(head, &stack.head);
-
-    // now that head has moved, we can increment the number of available buffers
-    android_atomic_inc(&stack.available);
-    return head;
-}
-
-SharedBufferServer::StatusUpdate::StatusUpdate(
-        SharedBufferBase* sbb, status_t status)
-    : UpdateBase(sbb), status(status) {
-}
-
-ssize_t SharedBufferServer::StatusUpdate::operator()() {
-    android_atomic_write(status, &stack.status);
-    return NO_ERROR;
-}
-
-// ============================================================================
-
-SharedBufferClient::SharedBufferClient(SharedClient* sharedClient,
-        int surface, int num, int32_t identity)
-    : SharedBufferBase(sharedClient, surface, identity),
-      mNumBuffers(num), tail(0)
-{
-    SharedBufferStack& stack( *mSharedStack );
-    tail = computeTail();
-    queued_head = stack.head;
-}
-
-int32_t SharedBufferClient::computeTail() const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers;
-}
-
-ssize_t SharedBufferClient::dequeue()
-{
-    SharedBufferStack& stack( *mSharedStack );
-
-    RWLock::AutoRLock _rd(mLock);
-
-    const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);
-
-    //LOGD("[%d] about to dequeue a buffer",
-    //        mSharedStack->identity);
-    DequeueCondition condition(this);
-    status_t err = waitForCondition(condition);
-    if (err != NO_ERROR)
-        return ssize_t(err);
-
-    DequeueUpdate update(this);
-    updateCondition( update );
-
-    int dequeued = stack.index[tail];
-    tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1);
-    LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail++=%d, %s",
-            dequeued, tail, dump("").string());
-
-    mDequeueTime[dequeued] = dequeueTime; 
-
-    return dequeued;
-}
-
-status_t SharedBufferClient::undoDequeue(int buf)
-{
-    return cancel(buf);
-}
-
-status_t SharedBufferClient::cancel(int buf)
-{
-    RWLock::AutoRLock _rd(mLock);
-
-    // calculate the new position of the tail index (essentially tail--)
-    int localTail = (tail + mNumBuffers - 1) % mNumBuffers;
-    CancelUpdate update(this, localTail, buf);
-    status_t err = updateCondition( update );
-    if (err == NO_ERROR) {
-        tail = localTail;
-    }
-    return err;
-}
-
-status_t SharedBufferClient::lock(int buf)
-{
-    RWLock::AutoRLock _rd(mLock);
-
-    SharedBufferStack& stack( *mSharedStack );
-    LockCondition condition(this, buf);
-    status_t err = waitForCondition(condition);
-    return err;
-}
-
-status_t SharedBufferClient::queue(int buf)
-{
-    RWLock::AutoRLock _rd(mLock);
-
-    SharedBufferStack& stack( *mSharedStack );
-
-    queued_head = (queued_head + 1) % mNumBuffers;
-    stack.index[queued_head] = buf;
-
-    QueueUpdate update(this);
-    status_t err = updateCondition( update );
-    LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string());
-
-    const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
-    stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
-
-    return err;
-}
-
-bool SharedBufferClient::needNewBuffer(int buf) const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    const uint32_t mask = 1<<(31-buf);
-    return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0;
-}
-
-status_t SharedBufferClient::setCrop(int buf, const Rect& crop)
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.setCrop(buf, crop);
-}
-
-status_t SharedBufferClient::setTransform(int buf, uint32_t transform)
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.setTransform(buf, uint8_t(transform));
-}
-
-status_t SharedBufferClient::setDirtyRegion(int buf, const Region& reg)
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.setDirtyRegion(buf, reg);
-}
-
-status_t SharedBufferClient::setBufferCount(
-        int bufferCount, const SetBufferCountCallback& ipc)
-{
-    SharedBufferStack& stack( *mSharedStack );
-    if (uint32_t(bufferCount) >= SharedBufferStack::NUM_BUFFER_MAX)
-        return BAD_VALUE;
-
-    if (uint32_t(bufferCount) < SharedBufferStack::NUM_BUFFER_MIN)
-        return BAD_VALUE;
-
-    RWLock::AutoWLock _wr(mLock);
-
-    status_t err = ipc(bufferCount);
-    if (err == NO_ERROR) {
-        mNumBuffers = bufferCount;
-        queued_head = (stack.head + stack.queued) % mNumBuffers;
-        tail = computeTail();
-    }
-    return err;
-}
-
-// ----------------------------------------------------------------------------
-
-SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,
-        int surface, int num, int32_t identity)
-    : SharedBufferBase(sharedClient, surface, identity),
-      mNumBuffers(num)
-{
-    mSharedStack->init(identity);
-    mSharedStack->token = surface;
-    mSharedStack->head = num-1;
-    mSharedStack->available = num;
-    mSharedStack->queued = 0;
-    mSharedStack->reallocMask = 0;
-    memset(mSharedStack->buffers, 0, sizeof(mSharedStack->buffers));
-    for (int i=0 ; i<num ; i++) {
-        mBufferList.add(i);
-        mSharedStack->index[i] = i;
-    }
-}
-
-SharedBufferServer::~SharedBufferServer()
-{
-}
-
-ssize_t SharedBufferServer::retireAndLock()
-{
-    RWLock::AutoRLock _l(mLock);
-
-    RetireUpdate update(this, mNumBuffers);
-    ssize_t buf = updateCondition( update );
-    if (buf >= 0) {
-        if (uint32_t(buf) >= SharedBufferStack::NUM_BUFFER_MAX)
-            return BAD_VALUE;
-        SharedBufferStack& stack( *mSharedStack );
-        buf = stack.index[buf];
-        LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s",
-                int(buf), dump("").string());
-    }
-    return buf;
-}
-
-void SharedBufferServer::setStatus(status_t status)
-{
-    if (status < NO_ERROR) {
-        StatusUpdate update(this, status);
-        updateCondition( update );
-    }
-}
-
-status_t SharedBufferServer::reallocateAll()
-{
-    RWLock::AutoRLock _l(mLock);
-
-    SharedBufferStack& stack( *mSharedStack );
-    uint32_t mask = mBufferList.getMask();
-    android_atomic_or(mask, &stack.reallocMask);
-    return NO_ERROR;
-}
-
-status_t SharedBufferServer::reallocateAllExcept(int buffer)
-{
-    RWLock::AutoRLock _l(mLock);
-
-    SharedBufferStack& stack( *mSharedStack );
-    BufferList temp(mBufferList);
-    temp.remove(buffer);
-    uint32_t mask = temp.getMask();
-    android_atomic_or(mask, &stack.reallocMask);
-    return NO_ERROR;
-}
-
-int32_t SharedBufferServer::getQueuedCount() const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.queued;
-}
-
-Region SharedBufferServer::getDirtyRegion(int buf) const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.getDirtyRegion(buf);
-}
-
-Rect SharedBufferServer::getCrop(int buf) const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.getCrop(buf);
-}
-
-uint32_t SharedBufferServer::getTransform(int buf) const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.getTransform(buf);
-}
-
-/*
- * NOTE: this is not thread-safe on the server-side, meaning
- * 'head' cannot move during this operation. The client-side
- * can safely operate an usual.
- *
- */
-status_t SharedBufferServer::resize(int newNumBuffers)
-{
-    if ((unsigned int)(newNumBuffers) < SharedBufferStack::NUM_BUFFER_MIN ||
-        (unsigned int)(newNumBuffers) > SharedBufferStack::NUM_BUFFER_MAX) {
-        return BAD_VALUE;
-    }
-
-    RWLock::AutoWLock _l(mLock);
-
-    if (newNumBuffers < mNumBuffers) {
-        return shrink(newNumBuffers);
-    } else {
-        return grow(newNumBuffers);
-    }
-}
-
-status_t SharedBufferServer::grow(int newNumBuffers)
-{
-    SharedBufferStack& stack( *mSharedStack );
-    const int numBuffers = mNumBuffers;
-    const int extra = newNumBuffers - numBuffers;
-
-    // read the head, make sure it's valid
-    int32_t head = stack.head;
-    if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX)
-        return BAD_VALUE;
-
-    int base = numBuffers;
-    int32_t avail = stack.available;
-    int tail = head - avail + 1;
-
-    if (tail >= 0) {
-        int8_t* const index = const_cast<int8_t*>(stack.index);
-        const int nb = numBuffers - head;
-        memmove(&index[head + extra], &index[head], nb);
-        base = head;
-        // move head 'extra' ahead, this doesn't impact stack.index[head];
-        stack.head = head + extra;
-    }
-    stack.available += extra;
-
-    // fill the new free space with unused buffers
-    BufferList::const_iterator curr(mBufferList.free_begin());
-    for (int i=0 ; i<extra ; i++) {
-        stack.index[base+i] = *curr;
-        mBufferList.add(*curr);
-        ++curr;
-    }
-
-    mNumBuffers = newNumBuffers;
-    return NO_ERROR;
-}
-
-status_t SharedBufferServer::shrink(int newNumBuffers)
-{
-    SharedBufferStack& stack( *mSharedStack );
-
-    // Shrinking is only supported if there are no buffers currently dequeued.
-    int32_t avail = stack.available;
-    int32_t queued = stack.queued;
-    if (avail + queued != mNumBuffers) {
-        return INVALID_OPERATION;
-    }
-
-    // Wait for any queued buffers to be displayed.
-    BuffersAvailableCondition condition(this, mNumBuffers);
-    status_t err = waitForCondition(condition);
-    if (err < 0) {
-        return err;
-    }
-
-    // Reset head to index 0 and make it refer to buffer 0.  The same renaming
-    // (head -> 0) is done in the BufferManager.
-    int32_t head = stack.head;
-    int8_t* index = const_cast<int8_t*>(stack.index);
-    for (int8_t i = 0; i < newNumBuffers; i++) {
-        index[i] = i;
-    }
-    stack.head = 0;
-    stack.headBuf = 0;
-
-    // Free the buffers from the end of the list that are no longer needed.
-    for (int i = newNumBuffers; i < mNumBuffers; i++) {
-        mBufferList.remove(i);
-    }
-
-    // Tell the client to reallocate all the buffers.
-    reallocateAll();
-
-    mNumBuffers = newNumBuffers;
-    stack.available = newNumBuffers;
-
-    return NO_ERROR;
-}
-
-SharedBufferStack::Statistics SharedBufferServer::getStats() const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.stats;
-}
-
-// ---------------------------------------------------------------------------
-status_t SharedBufferServer::BufferList::add(int value)
-{
-    if (uint32_t(value) >= mCapacity)
-        return BAD_VALUE;
-    uint32_t mask = 1<<(31-value);
-    if (mList & mask)
-        return ALREADY_EXISTS;
-    mList |= mask;
-    return NO_ERROR;
-}
-
-status_t SharedBufferServer::BufferList::remove(int value)
-{
-    if (uint32_t(value) >= mCapacity)
-        return BAD_VALUE;
-    uint32_t mask = 1<<(31-value);
-    if (!(mList & mask))
-        return NAME_NOT_FOUND;
-    mList &= ~mask;
-    return NO_ERROR;
-}
-
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 0c5767b..4d1d923 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -21,13 +21,15 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#include <utils/Errors.h>
-#include <utils/threads.h>
 #include <utils/CallStack.h>
+#include <utils/Errors.h>
 #include <utils/Log.h>
+#include <utils/threads.h>
 
-#include <binder/IPCThreadState.h>
 #include <binder/IMemory.h>
+#include <binder/IPCThreadState.h>
+
+#include <gui/SurfaceTextureClient.h>
 
 #include <ui/DisplayInfo.h>
 #include <ui/GraphicBuffer.h>
@@ -35,12 +37,11 @@
 #include <ui/GraphicLog.h>
 #include <ui/Rect.h>
 
-#include <surfaceflinger/Surface.h>
 #include <surfaceflinger/ISurface.h>
 #include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/Surface.h>
 #include <surfaceflinger/SurfaceComposerClient.h>
 
-#include <private/surfaceflinger/SharedBufferStack.h>
 #include <private/surfaceflinger/LayerState.h>
 
 namespace android {
@@ -273,58 +274,10 @@
 //  Surface
 // ============================================================================
 
-class SurfaceClient : public Singleton<SurfaceClient>
-{
-    // all these attributes are constants
-    sp<ISurfaceComposer> mComposerService;
-    sp<ISurfaceComposerClient> mClient;
-    status_t mStatus;
-    SharedClient* mControl;
-    sp<IMemoryHeap> mControlMemory;
-
-    SurfaceClient()
-        : Singleton<SurfaceClient>(), mStatus(NO_INIT)
-    {
-        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-        mComposerService = sf;
-        mClient = sf->createClientConnection();
-        if (mClient != NULL) {
-            mControlMemory = mClient->getControlBlock();
-            if (mControlMemory != NULL) {
-                mControl = static_cast<SharedClient *>(
-                        mControlMemory->getBase());
-                if (mControl) {
-                    mStatus = NO_ERROR;
-                }
-            }
-        }
-    }
-    friend class Singleton<SurfaceClient>;
-public:
-    status_t initCheck() const {
-        return mStatus;
-    }
-    SharedClient* getSharedClient() const {
-        return mControl;
-    }
-    ssize_t getTokenForSurface(const sp<ISurface>& sur) const {
-        // TODO: we could cache a few tokens here to avoid an IPC
-        return mClient->getTokenForSurface(sur);
-    }
-    void signalServer() const {
-        mComposerService->signal();
-    }
-};
-
-ANDROID_SINGLETON_STATIC_INSTANCE(SurfaceClient);
-
 // ---------------------------------------------------------------------------
 
 Surface::Surface(const sp<SurfaceControl>& surface)
-    : mBufferMapper(GraphicBufferMapper::get()),
-      mClient(SurfaceClient::getInstance()),
-      mSharedBufferClient(NULL),
-      mInitCheck(NO_INIT),
+    : mInitCheck(NO_INIT),
       mSurface(surface->mSurface),
       mIdentity(surface->mIdentity),
       mFormat(surface->mFormat), mFlags(surface->mFlags),
@@ -334,10 +287,7 @@
 }
 
 Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
-    : mBufferMapper(GraphicBufferMapper::get()),
-      mClient(SurfaceClient::getInstance()),
-      mSharedBufferClient(NULL),
-      mInitCheck(NO_INIT)
+    : mInitCheck(NO_INIT)
 {
     mSurface    = interface_cast<ISurface>(ref);
     mIdentity   = parcel.readInt32();
@@ -382,7 +332,6 @@
 
 }
 
-
 Mutex Surface::sCachedSurfacesLock;
 DefaultKeyedVector<wp<IBinder>, wp<Surface> > Surface::sCachedSurfaces;
 
@@ -422,32 +371,29 @@
     ANativeWindow::query            = query;
     ANativeWindow::perform          = perform;
 
-    DisplayInfo dinfo;
-    SurfaceComposerClient::getDisplayInfo(0, &dinfo);
-    const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
-    const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
-    // FIXME: set real values here
-    const_cast<int&>(ANativeWindow::minSwapInterval) = 1;
-    const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
-    const_cast<uint32_t&>(ANativeWindow::flags) = 0;
+    if (mSurface != NULL) {
+        sp<ISurfaceTexture> surfaceTexture(mSurface->getSurfaceTexture());
+        LOGE_IF(surfaceTexture==0, "got a NULL ISurfaceTexture from ISurface");
+        if (surfaceTexture != NULL) {
+            mSurfaceTextureClient = new SurfaceTextureClient(surfaceTexture);
+            mSurfaceTextureClient->setUsage(GraphicBuffer::USAGE_HW_RENDER);
+        }
 
-    mNextBufferTransform = 0;
-    mConnected = 0;
-    mSwapRectangle.makeInvalid();
-    mNextBufferCrop = Rect(0,0);
-    // two buffers by default
-    mBuffers.setCapacity(2);
-    mBuffers.insertAt(0, 2);
+        DisplayInfo dinfo;
+        SurfaceComposerClient::getDisplayInfo(0, &dinfo);
+        const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
+        const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
 
-    if (mSurface != 0 && mClient.initCheck() == NO_ERROR) {
-        int32_t token = mClient.getTokenForSurface(mSurface);
-        if (token >= 0) {
-            mSharedBufferClient = new SharedBufferClient(
-                    mClient.getSharedClient(), token, 2, mIdentity);
-            mInitCheck = mClient.getSharedClient()->validate(token);
-        } else {
-            LOGW("Not initializing the shared buffer client because token = %d",
-                    token);
+        const_cast<int&>(ANativeWindow::minSwapInterval) =
+                mSurfaceTextureClient->minSwapInterval;
+
+        const_cast<int&>(ANativeWindow::maxSwapInterval) =
+                mSurfaceTextureClient->maxSwapInterval;
+
+        const_cast<uint32_t&>(ANativeWindow::flags) = 0;
+
+        if (mSurfaceTextureClient != 0) {
+            mInitCheck = NO_ERROR;
         }
     }
 }
@@ -456,9 +402,8 @@
 {
     // clear all references and trigger an IPC now, to make sure things
     // happen without delay, since these resources are quite heavy.
-    mBuffers.clear();
+    mSurfaceTextureClient.clear();
     mSurface.clear();
-    delete mSharedBufferClient;
     IPCThreadState::self()->flushCommands();
 }
 
@@ -473,32 +418,6 @@
         LOGE("invalid token (identity=%u)", mIdentity);
         return mInitCheck;
     }
-
-    // verify the identity of this surface
-    uint32_t identity = mSharedBufferClient->getIdentity();
-    if (mIdentity != identity) {
-        LOGE("[Surface] using an invalid surface, "
-                "identity=%u should be %d",
-                mIdentity, identity);
-        CallStack stack;
-        stack.update();
-        stack.dump("Surface");
-        return BAD_INDEX;
-    }
-
-    // check the surface didn't become invalid
-    status_t err = mSharedBufferClient->getStatus();
-    if (err != NO_ERROR) {
-        if (!inCancelBuffer) {
-            LOGE("surface (identity=%u) is invalid, err=%d (%s)",
-                    mIdentity, err, strerror(-err));
-            CallStack stack;
-            stack.update();
-            stack.dump("Surface");
-        }
-        return err;
-    }
-
     return NO_ERROR;
 }
 
@@ -509,7 +428,8 @@
 // ----------------------------------------------------------------------------
 
 int Surface::setSwapInterval(ANativeWindow* window, int interval) {
-    return 0;
+    Surface* self = getSelf(window);
+    return self->setSwapInterval(interval);
 }
 
 int Surface::dequeueBuffer(ANativeWindow* window, 
@@ -554,383 +474,52 @@
 
 // ----------------------------------------------------------------------------
 
-bool Surface::needNewBuffer(int bufIdx,
-        uint32_t *pWidth, uint32_t *pHeight,
-        uint32_t *pFormat, uint32_t *pUsage) const
-{
-    Mutex::Autolock _l(mSurfaceLock);
-
-    // Always call needNewBuffer(), since it clears the needed buffers flags
-    bool needNewBuffer = mSharedBufferClient->needNewBuffer(bufIdx);
-    bool validBuffer = mBufferInfo.validateBuffer(mBuffers[bufIdx]);
-    bool newNeewBuffer = needNewBuffer || !validBuffer;
-    if (newNeewBuffer) {
-        mBufferInfo.get(pWidth, pHeight, pFormat, pUsage);
-    }
-    return newNeewBuffer;
+int Surface::setSwapInterval(int interval) {
+    return mSurfaceTextureClient->setSwapInterval(interval);
 }
 
-int Surface::dequeueBuffer(ANativeWindowBuffer** buffer)
-{
-    status_t err = validate();
-    if (err != NO_ERROR)
-        return err;
-
-    GraphicLog& logger(GraphicLog::getInstance());
-    logger.log(GraphicLog::SF_APP_DEQUEUE_BEFORE, mIdentity, -1);
-
-    ssize_t bufIdx = mSharedBufferClient->dequeue();
-
-    logger.log(GraphicLog::SF_APP_DEQUEUE_AFTER, mIdentity, bufIdx);
-
-    if (bufIdx < 0) {
-        LOGE("error dequeuing a buffer (%s)", strerror(bufIdx));
-        return bufIdx;
-    }
-
-    // grow the buffer array if needed
-    const size_t size = mBuffers.size();
-    const size_t needed = bufIdx+1;
-    if (size < needed) {
-        mBuffers.insertAt(size, needed-size);
-    }
-
-    uint32_t w, h, format, usage;
-    if (needNewBuffer(bufIdx, &w, &h, &format, &usage)) {
-        err = getBufferLocked(bufIdx, w, h, format, usage);
-        LOGE_IF(err, "getBufferLocked(%ld, %u, %u, %u, %08x) failed (%s)",
-                bufIdx, w, h, format, usage, strerror(-err));
-        if (err == NO_ERROR) {
-            // reset the width/height with the what we get from the buffer
-            const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
-            mWidth  = uint32_t(backBuffer->width);
-            mHeight = uint32_t(backBuffer->height);
-        }
-    }
-
-    // if we still don't have a buffer here, we probably ran out of memory
-    const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
-    if (!err && backBuffer==0) {
-        err = NO_MEMORY;
-    }
-
+int Surface::dequeueBuffer(ANativeWindowBuffer** buffer) {
+    status_t err = mSurfaceTextureClient->dequeueBuffer(buffer);
     if (err == NO_ERROR) {
-        mDirtyRegion.set(backBuffer->width, backBuffer->height);
-        *buffer = backBuffer.get();
-    } else {
-        mSharedBufferClient->undoDequeue(bufIdx);
-    }
-
-    return err;
-}
-
-int Surface::cancelBuffer(ANativeWindowBuffer* buffer)
-{
-    status_t err = validate(true);
-    switch (err) {
-    case NO_ERROR:
-        // no error, common case
-        break;
-    case BAD_INDEX:
-        // legitimate errors here
-        return err;
-    default:
-        // other errors happen because the surface is now invalid,
-        // for instance because it has been destroyed. In this case,
-        // we just fail silently (canceling a buffer is not technically
-        // an error at this point)
-        return NO_ERROR;
-    }
-
-    int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
-
-    err = mSharedBufferClient->cancel(bufIdx);
-
-    LOGE_IF(err, "error canceling buffer %d (%s)", bufIdx, strerror(-err));
-    return err;
-}
-
-
-int Surface::lockBuffer(ANativeWindowBuffer* buffer)
-{
-    status_t err = validate();
-    if (err != NO_ERROR)
-        return err;
-
-    int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
-
-    GraphicLog& logger(GraphicLog::getInstance());
-    logger.log(GraphicLog::SF_APP_LOCK_BEFORE, mIdentity, bufIdx);
-
-    err = mSharedBufferClient->lock(bufIdx);
-
-    logger.log(GraphicLog::SF_APP_LOCK_AFTER, mIdentity, bufIdx);
-
-    LOGE_IF(err, "error locking buffer %d (%s)", bufIdx, strerror(-err));
-    return err;
-}
-
-int Surface::queueBuffer(ANativeWindowBuffer* buffer)
-{
-    status_t err = validate();
-    if (err != NO_ERROR)
-        return err;
-
-    if (mSwapRectangle.isValid()) {
-        mDirtyRegion.set(mSwapRectangle);
-    }
-    
-    int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
-
-    GraphicLog::getInstance().log(GraphicLog::SF_APP_QUEUE, mIdentity, bufIdx);
-
-    mSharedBufferClient->setTransform(bufIdx, mNextBufferTransform);
-    mSharedBufferClient->setCrop(bufIdx, mNextBufferCrop);
-    mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion);
-    err = mSharedBufferClient->queue(bufIdx);
-    LOGE_IF(err, "error queuing buffer %d (%s)", bufIdx, strerror(-err));
-
-    if (err == NO_ERROR) {
-        // TODO: can we avoid this IPC if we know there is one pending?
-        mClient.signalServer();
+        mDirtyRegion.set(buffer[0]->width, buffer[0]->height);
     }
     return err;
 }
 
-int Surface::query(int what, int* value) const
-{
+int Surface::cancelBuffer(ANativeWindowBuffer* buffer) {
+    return mSurfaceTextureClient->cancelBuffer(buffer);
+}
+
+int Surface::lockBuffer(ANativeWindowBuffer* buffer) {
+    return mSurfaceTextureClient->lockBuffer(buffer);
+}
+
+int Surface::queueBuffer(ANativeWindowBuffer* buffer) {
+    return mSurfaceTextureClient->queueBuffer(buffer);
+}
+
+int Surface::query(int what, int* value) const {
     switch (what) {
-    case NATIVE_WINDOW_WIDTH:
-        *value = int(mWidth);
+    case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+        // TODO: this is not needed anymore
+        *value = 1;
         return NO_ERROR;
-    case NATIVE_WINDOW_HEIGHT:
-        *value = int(mHeight);
-        return NO_ERROR;
-    case NATIVE_WINDOW_FORMAT:
-        *value = int(mFormat);
-        return NO_ERROR;
-    case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
-        *value = MIN_UNDEQUEUED_BUFFERS;
-        return NO_ERROR;
-    case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
-        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-        *value = sf->authenticateSurface(mSurface) ? 1 : 0;
-        return NO_ERROR;
-    }
     case NATIVE_WINDOW_CONCRETE_TYPE:
+        // TODO: this is not needed anymore
         *value = NATIVE_WINDOW_SURFACE;
         return NO_ERROR;
     }
-    return BAD_VALUE;
+    return mSurfaceTextureClient->query(what, value);
 }
 
-int Surface::perform(int operation, va_list args)
-{
-    status_t err = validate();
-    if (err != NO_ERROR)
-        return err;
-
-    int res = NO_ERROR;
-    switch (operation) {
-    case NATIVE_WINDOW_SET_USAGE:
-        dispatch_setUsage( args );
-        break;
-    case NATIVE_WINDOW_CONNECT:
-        res = dispatch_connect( args );
-        break;
-    case NATIVE_WINDOW_DISCONNECT:
-        res = dispatch_disconnect( args );
-        break;
-    case NATIVE_WINDOW_SET_CROP:
-        res = dispatch_crop( args );
-        break;
-    case NATIVE_WINDOW_SET_BUFFER_COUNT:
-        res = dispatch_set_buffer_count( args );
-        break;
-    case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
-        res = dispatch_set_buffers_geometry( args );
-        break;
-    case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
-        res = dispatch_set_buffers_transform( args );
-        break;
-    case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
-        res = dispatch_set_buffers_timestamp( args );
-        break;
-    default:
-        res = NAME_NOT_FOUND;
-        break;
-    }
-    return res;
-}
-
-void Surface::dispatch_setUsage(va_list args) {
-    int usage = va_arg(args, int);
-    setUsage( usage );
-}
-int Surface::dispatch_connect(va_list args) {
-    int api = va_arg(args, int);
-    return connect( api );
-}
-int Surface::dispatch_disconnect(va_list args) {
-    int api = va_arg(args, int);
-    return disconnect( api );
-}
-int Surface::dispatch_crop(va_list args) {
-    android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
-    return crop( reinterpret_cast<Rect const*>(rect) );
-}
-int Surface::dispatch_set_buffer_count(va_list args) {
-    size_t bufferCount = va_arg(args, size_t);
-    return setBufferCount(bufferCount);
-}
-int Surface::dispatch_set_buffers_geometry(va_list args) {
-    int w = va_arg(args, int);
-    int h = va_arg(args, int);
-    int f = va_arg(args, int);
-    return setBuffersGeometry(w, h, f);
-}
-
-int Surface::dispatch_set_buffers_transform(va_list args) {
-    int transform = va_arg(args, int);
-    return setBuffersTransform(transform);
-}
-
-int Surface::dispatch_set_buffers_timestamp(va_list args) {
-    int64_t timestamp = va_arg(args, int64_t);
-    return setBuffersTimestamp(timestamp);
-}
-
-void Surface::setUsage(uint32_t reqUsage)
-{
-    Mutex::Autolock _l(mSurfaceLock);
-    mBufferInfo.set(reqUsage);
-}
-
-int Surface::connect(int api)
-{
-    Mutex::Autolock _l(mSurfaceLock);
-    int err = NO_ERROR;
-    switch (api) {
-        case NATIVE_WINDOW_API_EGL:
-            if (mConnected) {
-                err = -EINVAL;
-            } else {
-                mConnected = api;
-            }
-            break;
-        default:
-            err = -EINVAL;
-            break;
-    }
-    return err;
-}
-
-int Surface::disconnect(int api)
-{
-    Mutex::Autolock _l(mSurfaceLock);
-    int err = NO_ERROR;
-    switch (api) {
-        case NATIVE_WINDOW_API_EGL:
-            if (mConnected == api) {
-                mConnected = 0;
-            } else {
-                err = -EINVAL;
-            }
-            break;
-        default:
-            err = -EINVAL;
-            break;
-    }
-    return err;
-}
-
-int Surface::crop(Rect const* rect)
-{
-    Mutex::Autolock _l(mSurfaceLock);
-    // TODO: validate rect size
-
-    if (rect == NULL || rect->isEmpty()) {
-        mNextBufferCrop = Rect(0,0);
-    } else {
-        mNextBufferCrop = *rect;
-    }
-
-    return NO_ERROR;
-}
-
-int Surface::setBufferCount(int bufferCount)
-{
-    sp<ISurface> s(mSurface);
-    if (s == 0) return NO_INIT;
-
-    class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback {
-        sp<ISurface> surface;
-        virtual status_t operator()(int bufferCount) const {
-            return surface->setBufferCount(bufferCount);
-        }
-    public:
-        SetBufferCountIPC(const sp<ISurface>& surface) : surface(surface) { }
-    } ipc(s);
-
-    status_t err = mSharedBufferClient->setBufferCount(bufferCount, ipc);
-    LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s",
-            bufferCount, strerror(-err));
-
-    if (err == NO_ERROR) {
-        // Clear out any references to the old buffers.
-        mBuffers.clear();
-    }
-
-    return err;
-}
-
-int Surface::setBuffersGeometry(int w, int h, int format)
-{
-    if (w<0 || h<0 || format<0)
-        return BAD_VALUE;
-
-    if ((w && !h) || (!w && h))
-        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;
-    }
-
-    mNextBufferCrop = Rect(0,0);
-
-    return NO_ERROR;
-}
-
-int Surface::setBuffersTransform(int transform)
-{
-    Mutex::Autolock _l(mSurfaceLock);
-    mNextBufferTransform = transform;
-    return NO_ERROR;
-}
-
-int Surface::setBuffersTimestamp(int64_t timestamp)
-{
-    // Surface doesn't really have anything meaningful to do with timestamps
-    // so they'll just be dropped here.
-    return NO_ERROR;
+int Surface::perform(int operation, va_list args) {
+    return mSurfaceTextureClient->perform(operation, args);
 }
 
 // ----------------------------------------------------------------------------
 
-int Surface::getConnectedApi() const
-{
-    Mutex::Autolock _l(mSurfaceLock);
-    return mConnected;
+int Surface::getConnectedApi() const {
+    return mSurfaceTextureClient->getConnectedApi();
 }
 
 // ----------------------------------------------------------------------------
@@ -967,16 +556,17 @@
     }
 
     // we're intending to do software rendering from this point
-    setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+    mSurfaceTextureClient->setUsage(
+            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
 
     ANativeWindowBuffer* out;
-    status_t err = dequeueBuffer(&out);
+    status_t err = mSurfaceTextureClient->dequeueBuffer(&out);
     LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
     if (err == NO_ERROR) {
         sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
-        err = lockBuffer(backBuffer.get());
-        LOGE_IF(err, "lockBuffer (idx=%d) failed (%s)",
-                getBufferIndex(backBuffer), strerror(-err));
+        err = mSurfaceTextureClient->lockBuffer(backBuffer.get());
+        LOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
+                backBuffer->handle, strerror(-err));
         if (err == NO_ERROR) {
             const Rect bounds(backBuffer->width, backBuffer->height);
             const Region boundsRegion(bounds);
@@ -1043,110 +633,14 @@
     status_t err = mLockedBuffer->unlock();
     LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
     
-    err = queueBuffer(mLockedBuffer.get());
-    LOGE_IF(err, "queueBuffer (idx=%d) failed (%s)",
-            getBufferIndex(mLockedBuffer), strerror(-err));
+    err = mSurfaceTextureClient->queueBuffer(mLockedBuffer.get());
+    LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
+            mLockedBuffer->handle, strerror(-err));
 
     mPostedBuffer = mLockedBuffer;
     mLockedBuffer = 0;
     return err;
 }
 
-void Surface::setSwapRectangle(const Rect& r) {
-    Mutex::Autolock _l(mSurfaceLock);
-    mSwapRectangle = r;
-}
-
-int Surface::getBufferIndex(const sp<GraphicBuffer>& buffer) const
-{
-    int idx = buffer->getIndex();
-    if (idx < 0) {
-        // The buffer doesn't have an index set.  See if the handle the same as
-        // one of the buffers for which we do know the index.  This can happen
-        // e.g. if GraphicBuffer is used to wrap an ANativeWindowBuffer that
-        // was dequeued from an ANativeWindow.
-        for (size_t i = 0; i < mBuffers.size(); i++) {
-            if (mBuffers[i] != 0 && buffer->handle == mBuffers[i]->handle) {
-                idx = mBuffers[i]->getIndex();
-                break;
-            }
-        }
-    }
-    return idx;
-}
-
-status_t Surface::getBufferLocked(int index,
-        uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
-{
-    sp<ISurface> s(mSurface);
-    if (s == 0) return NO_INIT;
-
-    status_t err = NO_MEMORY;
-
-    // free the current buffer
-    sp<GraphicBuffer>& currentBuffer(mBuffers.editItemAt(index));
-    if (currentBuffer != 0) {
-        currentBuffer.clear();
-    }
-
-    sp<GraphicBuffer> buffer = s->requestBuffer(index, w, h, format, usage);
-    LOGE_IF(buffer==0,
-            "ISurface::getBuffer(%d, %08x) returned NULL",
-            index, usage);
-    if (buffer != 0) { // this should always happen by construction
-        LOGE_IF(buffer->handle == NULL, 
-                "Surface (identity=%d) requestBuffer(%d, %u, %u, %u, %08x) "
-                "returned a buffer with a null handle",
-                mIdentity, index, w, h, format, usage);
-        err = mSharedBufferClient->getStatus();
-        LOGE_IF(err,  "Surface (identity=%d) state = %d", mIdentity, err);
-        if (!err && buffer->handle != NULL) {
-            currentBuffer = buffer;
-            currentBuffer->setIndex(index);
-        } else {
-            err = err<0 ? err : status_t(NO_MEMORY);
-        }
-    }
-    return err; 
-}
-
-// ----------------------------------------------------------------------------
-Surface::BufferInfo::BufferInfo()
-    : mWidth(0), mHeight(0), mFormat(0),
-      mUsage(GRALLOC_USAGE_HW_RENDER), mDirty(0)
-{
-}
-
-void Surface::BufferInfo::set(uint32_t w, uint32_t h, uint32_t format) {
-    if ((mWidth != w) || (mHeight != h) || (mFormat != format)) {
-        mWidth = w;
-        mHeight = h;
-        mFormat = format;
-        mDirty |= GEOMETRY;
-    }
-}
-
-void Surface::BufferInfo::set(uint32_t usage) {
-    mUsage = usage;
-}
-
-void Surface::BufferInfo::get(uint32_t *pWidth, uint32_t *pHeight,
-        uint32_t *pFormat, uint32_t *pUsage) const {
-    *pWidth  = mWidth;
-    *pHeight = mHeight;
-    *pFormat = mFormat;
-    *pUsage  = mUsage;
-}
-
-bool Surface::BufferInfo::validateBuffer(const sp<GraphicBuffer>& buffer) const {
-    // make sure we AT LEAST have the usage flags we want
-    if (mDirty || buffer==0 ||
-            ((buffer->usage & mUsage) != mUsage)) {
-        mDirty = 0;
-        return false;
-    }
-    return true;
-}
-
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index a1ff2c1..1678711 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -20,19 +20,20 @@
 #include <sys/types.h>
 
 #include <utils/Errors.h>
-#include <utils/threads.h>
-#include <utils/SortedVector.h>
 #include <utils/Log.h>
 #include <utils/Singleton.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
+#include <utils/threads.h>
 
-#include <binder/IServiceManager.h>
 #include <binder/IMemory.h>
+#include <binder/IServiceManager.h>
 
 #include <ui/DisplayInfo.h>
 
+#include <surfaceflinger/ISurface.h>
 #include <surfaceflinger/ISurfaceComposer.h>
 #include <surfaceflinger/ISurfaceComposerClient.h>
-#include <surfaceflinger/ISurface.h>
 #include <surfaceflinger/SurfaceComposerClient.h>
 
 #include <private/surfaceflinger/LayerState.h>
@@ -217,7 +218,7 @@
 status_t SurfaceComposerClient::getDisplayInfo(
         DisplayID dpy, DisplayInfo* info)
 {
-    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
+    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
         return BAD_VALUE;
 
     volatile surface_flinger_cblk_t const * cblk = get_cblk();
@@ -235,7 +236,7 @@
 
 ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy)
 {
-    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
+    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
         return BAD_VALUE;
     volatile surface_flinger_cblk_t const * cblk = get_cblk();
     volatile display_cblk_t const * dcblk = cblk->displays + dpy;
@@ -244,7 +245,7 @@
 
 ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy)
 {
-    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
+    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
         return BAD_VALUE;
     volatile surface_flinger_cblk_t const * cblk = get_cblk();
     volatile display_cblk_t const * dcblk = cblk->displays + dpy;
@@ -253,7 +254,7 @@
 
 ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy)
 {
-    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
+    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
         return BAD_VALUE;
     volatile surface_flinger_cblk_t const * cblk = get_cblk();
     volatile display_cblk_t const * dcblk = cblk->displays + dpy;
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index ee97dcf..3cecdb4 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -96,6 +96,7 @@
     sp<ISurfaceComposer> composer(ComposerService::getComposerService());
     mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
     mNextCrop.makeInvalid();
+    memcpy(mCurrentTransformMatrix, mtxIdentity, sizeof(mCurrentTransformMatrix));
 }
 
 SurfaceTexture::~SurfaceTexture() {
@@ -270,7 +271,7 @@
             if (state == BufferSlot::DEQUEUED) {
                 dequeuedCount++;
             }
-            if (state == BufferSlot::FREE || i == mCurrentTexture) {
+            if (state == BufferSlot::FREE /*|| i == mCurrentTexture*/) {
                 foundSync = i;
                 if (i != mCurrentTexture) {
                     found = i;
@@ -547,6 +548,7 @@
         mCurrentCrop = mSlots[buf].mCrop;
         mCurrentTransform = mSlots[buf].mTransform;
         mCurrentTimestamp = mSlots[buf].mTimestamp;
+        computeCurrentTransformMatrix();
         mDequeueCondition.signal();
     } else {
         // We always bind the texture even if we don't update its contents.
@@ -596,8 +598,12 @@
 }
 
 void SurfaceTexture::getTransformMatrix(float mtx[16]) {
-    LOGV("SurfaceTexture::getTransformMatrix");
     Mutex::Autolock lock(mMutex);
+    memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
+}
+
+void SurfaceTexture::computeCurrentTransformMatrix() {
+    LOGV("SurfaceTexture::computeCurrentTransformMatrix");
 
     float xform[16];
     for (int i = 0; i < 16; i++) {
@@ -684,7 +690,7 @@
     // coordinate of 0, so SurfaceTexture must behave the same way.  We don't
     // want to expose this to applications, however, so we must add an
     // additional vertical flip to the transform after all the other transforms.
-    mtxMul(mtx, mtxFlipV, mtxBeforeFlipV);
+    mtxMul(mCurrentTransformMatrix, mtxFlipV, mtxBeforeFlipV);
 }
 
 nsecs_t SurfaceTexture::getTimestamp() {
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index c20fcf27..22b0852 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -181,6 +181,12 @@
 int SurfaceTextureClient::query(int what, int* value) const {
     LOGV("SurfaceTextureClient::query");
     switch (what) {
+    case NATIVE_WINDOW_FORMAT:
+        if (mReqFormat) {
+            *value = mReqFormat;
+            return NO_ERROR;
+        }
+        break;
     case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
         // TODO: this is not needed anymore
         *value = 0;
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 2f704c8..e1a85f3 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -505,13 +505,121 @@
 
     ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
     ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
+    thread->run();
     ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
     ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[1]));
-    thread->run();
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2]));
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[2]));
+    //ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2]));
+    //ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[2]));
     thread->bufferDequeued();
     thread->requestExitAndWait();
 }
 
+TEST_F(SurfaceTextureClientTest, GetTransformMatrixReturnsVerticalFlip) {
+    sp<ANativeWindow> anw(mSTC);
+    sp<SurfaceTexture> st(mST);
+    android_native_buffer_t* buf[3];
+    float mtx[16] = {};
+    ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4));
+    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
+    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
+    ASSERT_EQ(OK, st->updateTexImage());
+    st->getTransformMatrix(mtx);
+
+    EXPECT_EQ(1.f, mtx[0]);
+    EXPECT_EQ(0.f, mtx[1]);
+    EXPECT_EQ(0.f, mtx[2]);
+    EXPECT_EQ(0.f, mtx[3]);
+
+    EXPECT_EQ(0.f, mtx[4]);
+    EXPECT_EQ(-1.f, mtx[5]);
+    EXPECT_EQ(0.f, mtx[6]);
+    EXPECT_EQ(0.f, mtx[7]);
+
+    EXPECT_EQ(0.f, mtx[8]);
+    EXPECT_EQ(0.f, mtx[9]);
+    EXPECT_EQ(1.f, mtx[10]);
+    EXPECT_EQ(0.f, mtx[11]);
+
+    EXPECT_EQ(0.f, mtx[12]);
+    EXPECT_EQ(1.f, mtx[13]);
+    EXPECT_EQ(0.f, mtx[14]);
+    EXPECT_EQ(1.f, mtx[15]);
 }
+
+TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffers) {
+    sp<ANativeWindow> anw(mSTC);
+    sp<SurfaceTexture> st(mST);
+    android_native_buffer_t* buf[3];
+    float mtx[16] = {};
+    ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4));
+    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
+    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
+    ASSERT_EQ(OK, st->updateTexImage());
+    ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 6)); // frees buffers
+    st->getTransformMatrix(mtx);
+
+    EXPECT_EQ(1.f, mtx[0]);
+    EXPECT_EQ(0.f, mtx[1]);
+    EXPECT_EQ(0.f, mtx[2]);
+    EXPECT_EQ(0.f, mtx[3]);
+
+    EXPECT_EQ(0.f, mtx[4]);
+    EXPECT_EQ(-1.f, mtx[5]);
+    EXPECT_EQ(0.f, mtx[6]);
+    EXPECT_EQ(0.f, mtx[7]);
+
+    EXPECT_EQ(0.f, mtx[8]);
+    EXPECT_EQ(0.f, mtx[9]);
+    EXPECT_EQ(1.f, mtx[10]);
+    EXPECT_EQ(0.f, mtx[11]);
+
+    EXPECT_EQ(0.f, mtx[12]);
+    EXPECT_EQ(1.f, mtx[13]);
+    EXPECT_EQ(0.f, mtx[14]);
+    EXPECT_EQ(1.f, mtx[15]);
+}
+
+TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWithCrop) {
+    sp<ANativeWindow> anw(mSTC);
+    sp<SurfaceTexture> st(mST);
+    android_native_buffer_t* buf[3];
+    float mtx[16] = {};
+    android_native_rect_t crop;
+    crop.left = 0;
+    crop.top = 0;
+    crop.right = 5;
+    crop.bottom = 5;
+
+    ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4));
+    ASSERT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 8, 8, 0));
+    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
+    ASSERT_EQ(OK, native_window_set_crop(anw.get(), &crop));
+    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
+    ASSERT_EQ(OK, st->updateTexImage());
+    ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 6)); // frees buffers
+    st->getTransformMatrix(mtx);
+
+    // This accounts for the 1 texel shrink for each edge that's included in the
+    // transform matrix to avoid texturing outside the crop region.
+    EXPECT_EQ(.5f, mtx[0]);
+    EXPECT_EQ(0.f, mtx[1]);
+    EXPECT_EQ(0.f, mtx[2]);
+    EXPECT_EQ(0.f, mtx[3]);
+
+    EXPECT_EQ(0.f, mtx[4]);
+    EXPECT_EQ(-.5f, mtx[5]);
+    EXPECT_EQ(0.f, mtx[6]);
+    EXPECT_EQ(0.f, mtx[7]);
+
+    EXPECT_EQ(0.f, mtx[8]);
+    EXPECT_EQ(0.f, mtx[9]);
+    EXPECT_EQ(1.f, mtx[10]);
+    EXPECT_EQ(0.f, mtx[11]);
+
+    EXPECT_EQ(0.f, mtx[12]);
+    EXPECT_EQ(.5f, mtx[13]);
+    EXPECT_EQ(0.f, mtx[14]);
+    EXPECT_EQ(1.f, mtx[15]);
+}
+
+} // namespace android
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 8747ba5..56c1702 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+
 #include <gtest/gtest.h>
 #include <gui/SurfaceTexture.h>
 #include <gui/SurfaceTextureClient.h>
 #include <ui/GraphicBuffer.h>
 #include <utils/String8.h>
+#include <utils/threads.h>
 
 #include <surfaceflinger/ISurfaceComposer.h>
 #include <surfaceflinger/Surface.h>
@@ -270,8 +273,12 @@
         *outPgm = program;
     }
 
+    static int abs(int value) {
+        return value > 0 ? value : -value;
+    }
+
     ::testing::AssertionResult checkPixel(int x, int y, int r,
-            int g, int b, int a) {
+            int g, int b, int a, int tolerance=2) {
         GLubyte pixel[4];
         String8 msg;
         glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
@@ -285,22 +292,22 @@
             return ::testing::AssertionFailure(
                     ::testing::Message(msg.string()));
         }
-        if (r >= 0 && GLubyte(r) != pixel[0]) {
+        if (r >= 0 && abs(r - int(pixel[0])) > tolerance) {
             msg += String8::format("r(%d isn't %d)", pixel[0], r);
         }
-        if (g >= 0 && GLubyte(g) != pixel[1]) {
+        if (g >= 0 && abs(g - int(pixel[1])) > tolerance) {
             if (!msg.isEmpty()) {
                 msg += " ";
             }
             msg += String8::format("g(%d isn't %d)", pixel[1], g);
         }
-        if (b >= 0 && GLubyte(b) != pixel[2]) {
+        if (b >= 0 && abs(b - int(pixel[2])) > tolerance) {
             if (!msg.isEmpty()) {
                 msg += " ";
             }
             msg += String8::format("b(%d isn't %d)", pixel[2], b);
         }
-        if (a >= 0 && GLubyte(a) != pixel[3]) {
+        if (a >= 0 && abs(a - int(pixel[3])) > tolerance) {
             if (!msg.isEmpty()) {
                 msg += " ";
             }
@@ -618,4 +625,270 @@
     }
 }
 
+/*
+ * This test is for testing GL -> GL texture streaming via SurfaceTexture.  It
+ * contains functionality to create a producer thread that will perform GL
+ * rendering to an ANativeWindow that feeds frames to a SurfaceTexture.
+ * Additionally it supports interlocking the producer and consumer threads so
+ * that a specific sequence of calls can be deterministically created by the
+ * test.
+ *
+ * The intended usage is as follows:
+ *
+ * TEST_F(...) {
+ *     class PT : public ProducerThread {
+ *         virtual void render() {
+ *             ...
+ *             swapBuffers();
+ *         }
+ *     };
+ *
+ *     runProducerThread(new PT());
+ *
+ *     // The order of these calls will vary from test to test and may include
+ *     // multiple frames and additional operations (e.g. GL rendering from the
+ *     // texture).
+ *     fc->waitForFrame();
+ *     mST->updateTexImage();
+ *     fc->finishFrame();
+ * }
+ *
+ */
+class SurfaceTextureGLToGLTest : public SurfaceTextureGLTest {
+protected:
+
+    // ProducerThread is an abstract base class to simplify the creation of
+    // OpenGL ES frame producer threads.
+    class ProducerThread : public Thread {
+    public:
+        virtual ~ProducerThread() {
+        }
+
+        void setEglObjects(EGLDisplay producerEglDisplay,
+                EGLSurface producerEglSurface,
+                EGLContext producerEglContext) {
+            mProducerEglDisplay = producerEglDisplay;
+            mProducerEglSurface = producerEglSurface;
+            mProducerEglContext = producerEglContext;
+        }
+
+        virtual bool threadLoop() {
+            eglMakeCurrent(mProducerEglDisplay, mProducerEglSurface,
+                    mProducerEglSurface, mProducerEglContext);
+            render();
+            eglMakeCurrent(mProducerEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
+                    EGL_NO_CONTEXT);
+            return false;
+        }
+
+    protected:
+        virtual void render() = 0;
+
+        void swapBuffers() {
+            eglSwapBuffers(mProducerEglDisplay, mProducerEglSurface);
+        }
+
+        EGLDisplay mProducerEglDisplay;
+        EGLSurface mProducerEglSurface;
+        EGLContext mProducerEglContext;
+    };
+
+    // FrameCondition is a utility class for interlocking between the producer
+    // and consumer threads.  The FrameCondition object should be created and
+    // destroyed in the consumer thread only.  The consumer thread should set
+    // the FrameCondition as the FrameAvailableListener of the SurfaceTexture,
+    // and should call both waitForFrame and finishFrame once for each expected
+    // frame.
+    //
+    // This interlocking relies on the fact that onFrameAvailable gets called
+    // synchronously from SurfaceTexture::queueBuffer.
+    class FrameCondition : public SurfaceTexture::FrameAvailableListener {
+    public:
+        // waitForFrame waits for the next frame to arrive.  This should be
+        // called from the consumer thread once for every frame expected by the
+        // test.
+        void waitForFrame() {
+            LOGV("+waitForFrame");
+            Mutex::Autolock lock(mMutex);
+            status_t result = mFrameAvailableCondition.wait(mMutex);
+            LOGV("-waitForFrame");
+        }
+
+        // Allow the producer to return from its swapBuffers call and continue
+        // on to produce the next frame.  This should be called by the consumer
+        // thread once for every frame expected by the test.
+        void finishFrame() {
+            LOGV("+finishFrame");
+            Mutex::Autolock lock(mMutex);
+            mFrameFinishCondition.signal();
+            LOGV("-finishFrame");
+        }
+
+        // This should be called by SurfaceTexture on the producer thread.
+        virtual void onFrameAvailable() {
+            LOGV("+onFrameAvailable");
+            Mutex::Autolock lock(mMutex);
+            mFrameAvailableCondition.signal();
+            mFrameFinishCondition.wait(mMutex);
+            LOGV("-onFrameAvailable");
+        }
+
+    protected:
+        Mutex mMutex;
+        Condition mFrameAvailableCondition;
+        Condition mFrameFinishCondition;
+    };
+
+    SurfaceTextureGLToGLTest():
+            mProducerEglSurface(EGL_NO_SURFACE),
+            mProducerEglContext(EGL_NO_CONTEXT) {
+    }
+
+    virtual void SetUp() {
+        SurfaceTextureGLTest::SetUp();
+
+        EGLConfig myConfig = {0};
+        EGLint numConfigs = 0;
+        EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig,
+                1, &numConfigs));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+        mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, myConfig,
+                mANW.get(), NULL);
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface);
+
+        mProducerEglContext = eglCreateContext(mEglDisplay, myConfig,
+                EGL_NO_CONTEXT, getContextAttribs());
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        ASSERT_NE(EGL_NO_CONTEXT, mProducerEglContext);
+
+        mFC = new FrameCondition();
+        mST->setFrameAvailableListener(mFC);
+    }
+
+    virtual void TearDown() {
+        if (mProducerThread != NULL) {
+            mProducerThread->requestExitAndWait();
+        }
+        if (mProducerEglContext != EGL_NO_CONTEXT) {
+            eglDestroyContext(mEglDisplay, mProducerEglContext);
+        }
+        if (mProducerEglSurface != EGL_NO_SURFACE) {
+            eglDestroySurface(mEglDisplay, mProducerEglSurface);
+        }
+        mProducerThread.clear();
+        mFC.clear();
+    }
+
+    void runProducerThread(const sp<ProducerThread> producerThread) {
+        ASSERT_TRUE(mProducerThread == NULL);
+        mProducerThread = producerThread;
+        producerThread->setEglObjects(mEglDisplay, mProducerEglSurface,
+                mProducerEglContext);
+        producerThread->run();
+    }
+
+    EGLSurface mProducerEglSurface;
+    EGLContext mProducerEglContext;
+    sp<ProducerThread> mProducerThread;
+    sp<FrameCondition> mFC;
+};
+
+// XXX: This test is disabled because it causes hangs on some devices.
+TEST_F(SurfaceTextureGLToGLTest, DISABLED_UpdateTexImageBeforeFrameFinishedWorks) {
+    class PT : public ProducerThread {
+        virtual void render() {
+            glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+            glClear(GL_COLOR_BUFFER_BIT);
+            swapBuffers();
+        }
+    };
+
+    runProducerThread(new PT());
+
+    mFC->waitForFrame();
+    mST->updateTexImage();
+    mFC->finishFrame();
+
+    // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
 }
+
+// XXX: This test is disabled because it causes hangs on some devices.
+TEST_F(SurfaceTextureGLToGLTest, DISABLED_UpdateTexImageAfterFrameFinishedWorks) {
+    class PT : public ProducerThread {
+        virtual void render() {
+            glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+            glClear(GL_COLOR_BUFFER_BIT);
+            swapBuffers();
+        }
+    };
+
+    runProducerThread(new PT());
+
+    mFC->waitForFrame();
+    mFC->finishFrame();
+    mST->updateTexImage();
+
+    // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
+}
+
+// XXX: This test is disabled because it causes hangs on some devices.
+TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedUpdateTexImageBeforeFrameFinishedWorks) {
+    enum { NUM_ITERATIONS = 1024 };
+
+    class PT : public ProducerThread {
+        virtual void render() {
+            for (int i = 0; i < NUM_ITERATIONS; i++) {
+                glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+                glClear(GL_COLOR_BUFFER_BIT);
+                LOGV("+swapBuffers");
+                swapBuffers();
+                LOGV("-swapBuffers");
+            }
+        }
+    };
+
+    runProducerThread(new PT());
+
+    for (int i = 0; i < NUM_ITERATIONS; i++) {
+        mFC->waitForFrame();
+        LOGV("+updateTexImage");
+        mST->updateTexImage();
+        LOGV("-updateTexImage");
+        mFC->finishFrame();
+
+        // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
+    }
+}
+
+// XXX: This test is disabled because it causes hangs on some devices.
+TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedUpdateTexImageAfterFrameFinishedWorks) {
+    enum { NUM_ITERATIONS = 1024 };
+
+    class PT : public ProducerThread {
+        virtual void render() {
+            for (int i = 0; i < NUM_ITERATIONS; i++) {
+                glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+                glClear(GL_COLOR_BUFFER_BIT);
+                LOGV("+swapBuffers");
+                swapBuffers();
+                LOGV("-swapBuffers");
+            }
+        }
+    };
+
+    runProducerThread(new PT());
+
+    for (int i = 0; i < NUM_ITERATIONS; i++) {
+        mFC->waitForFrame();
+        mFC->finishFrame();
+        LOGV("+updateTexImage");
+        mST->updateTexImage();
+        LOGV("-updateTexImage");
+
+        // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
+    }
+}
+
+} // namespace android
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index e8d40ba..093189c 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -21,6 +21,7 @@
 	Asset.cpp \
 	AssetDir.cpp \
 	AssetManager.cpp \
+	BlobCache.cpp \
 	BufferedTextOutput.cpp \
 	CallStack.cpp \
 	Debug.cpp \
diff --git a/libs/utils/BlobCache.cpp b/libs/utils/BlobCache.cpp
new file mode 100644
index 0000000..1298fa7
--- /dev/null
+++ b/libs/utils/BlobCache.cpp
@@ -0,0 +1,232 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#define LOG_TAG "BlobCache"
+//#define LOG_NDEBUG 0
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <utils/BlobCache.h>
+#include <utils/Log.h>
+
+namespace android {
+
+BlobCache::BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize):
+        mMaxKeySize(maxKeySize),
+        mMaxValueSize(maxValueSize),
+        mMaxTotalSize(maxTotalSize),
+        mTotalSize(0) {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    mRandState[0] = (now >> 0) & 0xFFFF;
+    mRandState[1] = (now >> 16) & 0xFFFF;
+    mRandState[2] = (now >> 32) & 0xFFFF;
+    LOGV("initializing random seed using %lld", now);
+}
+
+void BlobCache::set(const void* key, size_t keySize, const void* value,
+        size_t valueSize) {
+    if (mMaxKeySize < keySize) {
+        LOGV("set: not caching because the key is too large: %d (limit: %d)",
+                keySize, mMaxKeySize);
+        return;
+    }
+    if (mMaxValueSize < valueSize) {
+        LOGV("set: not caching because the value is too large: %d (limit: %d)",
+                valueSize, mMaxValueSize);
+        return;
+    }
+    if (mMaxTotalSize < keySize + valueSize) {
+        LOGV("set: not caching because the combined key/value size is too "
+                "large: %d (limit: %d)", keySize + valueSize, mMaxTotalSize);
+        return;
+    }
+    if (keySize == 0) {
+        LOGW("set: not caching because keySize is 0");
+        return;
+    }
+    if (valueSize <= 0) {
+        LOGW("set: not caching because valueSize is 0");
+        return;
+    }
+
+    Mutex::Autolock lock(mMutex);
+    sp<Blob> dummyKey(new Blob(key, keySize, false));
+    CacheEntry dummyEntry(dummyKey, NULL);
+
+    while (true) {
+
+        ssize_t index = mCacheEntries.indexOf(dummyEntry);
+        if (index < 0) {
+            // Create a new cache entry.
+            sp<Blob> keyBlob(new Blob(key, keySize, true));
+            sp<Blob> valueBlob(new Blob(value, valueSize, true));
+            size_t newTotalSize = mTotalSize + keySize + valueSize;
+            if (mMaxTotalSize < newTotalSize) {
+                if (isCleanable()) {
+                    // Clean the cache and try again.
+                    clean();
+                    continue;
+                } else {
+                    LOGV("set: not caching new key/value pair because the "
+                            "total cache size limit would be exceeded: %d "
+                            "(limit: %d)",
+                            keySize + valueSize, mMaxTotalSize);
+                    break;
+                }
+            }
+            mCacheEntries.add(CacheEntry(keyBlob, valueBlob));
+            mTotalSize = newTotalSize;
+            LOGV("set: created new cache entry with %d byte key and %d byte value",
+                    keySize, valueSize);
+        } else {
+            // Update the existing cache entry.
+            sp<Blob> valueBlob(new Blob(value, valueSize, true));
+            sp<Blob> oldValueBlob(mCacheEntries[index].getValue());
+            size_t newTotalSize = mTotalSize + valueSize - oldValueBlob->getSize();
+            if (mMaxTotalSize < newTotalSize) {
+                if (isCleanable()) {
+                    // Clean the cache and try again.
+                    clean();
+                    continue;
+                } else {
+                    LOGV("set: not caching new value because the total cache "
+                            "size limit would be exceeded: %d (limit: %d)",
+                            keySize + valueSize, mMaxTotalSize);
+                    break;
+                }
+            }
+            mCacheEntries.editItemAt(index).setValue(valueBlob);
+            mTotalSize = newTotalSize;
+            LOGV("set: updated existing cache entry with %d byte key and %d byte "
+                    "value", keySize, valueSize);
+        }
+        break;
+    }
+}
+
+size_t BlobCache::get(const void* key, size_t keySize, void* value,
+        size_t valueSize) {
+    if (mMaxKeySize < keySize) {
+        LOGV("get: not searching because the key is too large: %d (limit %d)",
+                keySize, mMaxKeySize);
+        return 0;
+    }
+    Mutex::Autolock lock(mMutex);
+    sp<Blob> dummyKey(new Blob(key, keySize, false));
+    CacheEntry dummyEntry(dummyKey, NULL);
+    ssize_t index = mCacheEntries.indexOf(dummyEntry);
+    if (index < 0) {
+        LOGV("get: no cache entry found for key of size %d", keySize);
+        return 0;
+    }
+
+    // The key was found. Return the value if the caller's buffer is large
+    // enough.
+    sp<Blob> valueBlob(mCacheEntries[index].getValue());
+    size_t valueBlobSize = valueBlob->getSize();
+    if (valueBlobSize <= valueSize) {
+        LOGV("get: copying %d bytes to caller's buffer", valueBlobSize);
+        memcpy(value, valueBlob->getData(), valueBlobSize);
+    } else {
+        LOGV("get: caller's buffer is too small for value: %d (needs %d)",
+                valueSize, valueBlobSize);
+    }
+    return valueBlobSize;
+}
+
+void BlobCache::clean() {
+    // Remove a random cache entry until the total cache size gets below half
+    // the maximum total cache size.
+    while (mTotalSize > mMaxTotalSize / 2) {
+        size_t i = size_t(nrand48(mRandState) % (mCacheEntries.size()));
+        const CacheEntry& entry(mCacheEntries[i]);
+        mTotalSize -= entry.getKey()->getSize() + entry.getValue()->getSize();
+        mCacheEntries.removeAt(i);
+    }
+}
+
+bool BlobCache::isCleanable() const {
+    return mTotalSize > mMaxTotalSize / 2;
+}
+
+BlobCache::Blob::Blob(const void* data, size_t size, bool copyData):
+        mData(copyData ? malloc(size) : data),
+        mSize(size),
+        mOwnsData(copyData) {
+    if (copyData) {
+        memcpy(const_cast<void*>(mData), data, size);
+    }
+}
+
+BlobCache::Blob::~Blob() {
+    if (mOwnsData) {
+        free(const_cast<void*>(mData));
+    }
+}
+
+bool BlobCache::Blob::operator<(const Blob& rhs) const {
+    if (mSize == rhs.mSize) {
+        return memcmp(mData, rhs.mData, mSize) < 0;
+    } else {
+        return mSize < rhs.mSize;
+    }
+}
+
+const void* BlobCache::Blob::getData() const {
+    return mData;
+}
+
+size_t BlobCache::Blob::getSize() const {
+    return mSize;
+}
+
+BlobCache::CacheEntry::CacheEntry() {
+}
+
+BlobCache::CacheEntry::CacheEntry(const sp<Blob>& key, const sp<Blob>& value):
+        mKey(key),
+        mValue(value) {
+}
+
+BlobCache::CacheEntry::CacheEntry(const CacheEntry& ce):
+        mKey(ce.mKey),
+        mValue(ce.mValue) {
+}
+
+bool BlobCache::CacheEntry::operator<(const CacheEntry& rhs) const {
+    return *mKey < *rhs.mKey;
+}
+
+const BlobCache::CacheEntry& BlobCache::CacheEntry::operator=(const CacheEntry& rhs) {
+    mKey = rhs.mKey;
+    mValue = rhs.mValue;
+    return *this;
+}
+
+sp<BlobCache::Blob> BlobCache::CacheEntry::getKey() const {
+    return mKey;
+}
+
+sp<BlobCache::Blob> BlobCache::CacheEntry::getValue() const {
+    return mValue;
+}
+
+void BlobCache::CacheEntry::setValue(const sp<Blob>& value) {
+    mValue = value;
+}
+
+} // namespace android
diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp
index 58e0811..8db20095 100644
--- a/libs/utils/RefBase.cpp
+++ b/libs/utils/RefBase.cpp
@@ -49,6 +49,11 @@
 
 // ---------------------------------------------------------------------------
 
+RefBase::Destroyer::~Destroyer() {
+}
+
+// ---------------------------------------------------------------------------
+
 class RefBase::weakref_impl : public RefBase::weakref_type
 {
 public:
@@ -56,7 +61,7 @@
     volatile int32_t    mWeak;
     RefBase* const      mBase;
     volatile int32_t    mFlags;
-
+    Destroyer*          mDestroyer;
 
 #if !DEBUG_REFS
 
@@ -65,6 +70,7 @@
         , mWeak(0)
         , mBase(base)
         , mFlags(0)
+        , mDestroyer(0)
     {
     }
 
@@ -345,10 +351,6 @@
     const_cast<RefBase*>(this)->onFirstRef();
 }
 
-void RefBase::destroy() const {
-    delete this;
-}
-
 void RefBase::decStrong(const void* id) const
 {
     weakref_impl* const refs = mRefs;
@@ -361,7 +363,11 @@
     if (c == 1) {
         const_cast<RefBase*>(this)->onLastStrongRef(id);
         if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
-            destroy();
+            if (refs->mDestroyer) {
+                refs->mDestroyer->destroy(this);
+            } else {
+                delete this;
+            }
         }
     }
     refs->decWeak(id);
@@ -394,7 +400,9 @@
     return mRefs->mStrong;
 }
 
-
+void RefBase::setDestroyer(RefBase::Destroyer* destroyer) {
+    mRefs->mDestroyer = destroyer;
+}
 
 RefBase* RefBase::weakref_type::refBase() const
 {
@@ -420,7 +428,11 @@
     if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
         if (impl->mStrong == INITIAL_STRONG_VALUE) {
             if (impl->mBase) {
-                impl->mBase->destroy();
+                if (impl->mDestroyer) {
+                    impl->mDestroyer->destroy(impl->mBase);
+                } else {
+                    delete impl->mBase;
+                }
             }
         } else {
             // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
@@ -430,7 +442,11 @@
         impl->mBase->onLastWeakRef(id);
         if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
             if (impl->mBase) {
-                impl->mBase->destroy();
+                if (impl->mDestroyer) {
+                    impl->mDestroyer->destroy(impl->mBase);
+                } else {
+                    delete impl->mBase;
+                }
             }
         }
     }
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index 8b5da0e..c748228 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -168,6 +168,9 @@
         return 0;
     }
 
+    // Note that *threadID is directly available to the parent only, as it is
+    // assigned after the child starts.  Use memory barrier / lock if the child
+    // or other threads also need access.
     if (threadId != NULL) {
         *threadId = (android_thread_id_t)thread; // XXX: this is not portable
     }
@@ -718,7 +721,6 @@
         res = androidCreateRawThreadEtc(_threadLoop,
                 this, name, priority, stack, &mThread);
     }
-    // The new thread wakes up at _threadLoop, but immediately blocks on mLock
     
     if (res == false) {
         mStatus = UNKNOWN_ERROR;   // something happened!
@@ -742,11 +744,6 @@
 {
     Thread* const self = static_cast<Thread*>(user);
 
-    // force a memory barrier before reading any fields, in particular mHoldSelf
-    {
-    Mutex::Autolock _l(self->mLock);
-    }
-
     sp<Thread> strong(self->mHoldSelf);
     wp<Thread> weak(strong);
     self->mHoldSelf.clear();
@@ -816,6 +813,7 @@
 
 status_t Thread::requestExitAndWait()
 {
+    Mutex::Autolock _l(mLock);
     if (mThread == getThreadId()) {
         LOGW(
         "Thread (this=%p): don't call waitForExit() from this "
@@ -825,9 +823,8 @@
         return WOULD_BLOCK;
     }
     
-    requestExit();
+    mExitPending = true;
 
-    Mutex::Autolock _l(mLock);
     while (mRunning == true) {
         mThreadExitedCondition.wait(mLock);
     }
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 72d4876..87ad98e 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -6,6 +6,7 @@
 
 # Build the unit tests.
 test_src_files := \
+	BlobCache_test.cpp \
 	ObbFile_test.cpp \
 	Looper_test.cpp \
 	String8_test.cpp \
diff --git a/libs/utils/tests/BlobCache_test.cpp b/libs/utils/tests/BlobCache_test.cpp
new file mode 100644
index 0000000..653ea5e
--- /dev/null
+++ b/libs/utils/tests/BlobCache_test.cpp
@@ -0,0 +1,257 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <utils/BlobCache.h>
+
+namespace android {
+
+class BlobCacheTest : public ::testing::Test {
+protected:
+    enum {
+        MAX_KEY_SIZE = 6,
+        MAX_VALUE_SIZE = 8,
+        MAX_TOTAL_SIZE = 13,
+    };
+
+    virtual void SetUp() {
+        mBC = new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE);
+    }
+
+    virtual void TearDown() {
+        mBC.clear();
+    }
+
+    sp<BlobCache> mBC;
+};
+
+TEST_F(BlobCacheTest, CacheSingleValueSucceeds) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
+    ASSERT_EQ('e', buf[0]);
+    ASSERT_EQ('f', buf[1]);
+    ASSERT_EQ('g', buf[2]);
+    ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) {
+    char buf[2] = { 0xee, 0xee };
+    mBC->set("ab", 2, "cd", 2);
+    mBC->set("ef", 2, "gh", 2);
+    ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2));
+    ASSERT_EQ('c', buf[0]);
+    ASSERT_EQ('d', buf[1]);
+    ASSERT_EQ(size_t(2), mBC->get("ef", 2, buf, 2));
+    ASSERT_EQ('g', buf[0]);
+    ASSERT_EQ('h', buf[1]);
+}
+
+TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) {
+    char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf+1, 4));
+    ASSERT_EQ(0xee, buf[0]);
+    ASSERT_EQ('e', buf[1]);
+    ASSERT_EQ('f', buf[2]);
+    ASSERT_EQ('g', buf[3]);
+    ASSERT_EQ('h', buf[4]);
+    ASSERT_EQ(0xee, buf[5]);
+}
+
+TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) {
+    char buf[3] = { 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3));
+    ASSERT_EQ(0xee, buf[0]);
+    ASSERT_EQ(0xee, buf[1]);
+    ASSERT_EQ(0xee, buf[2]);
+}
+
+TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) {
+    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, NULL, 0));
+}
+
+TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    mBC->set("abcd", 4, "ijkl", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
+    ASSERT_EQ('i', buf[0]);
+    ASSERT_EQ('j', buf[1]);
+    ASSERT_EQ('k', buf[2]);
+    ASSERT_EQ('l', buf[3]);
+}
+
+TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) {
+    char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
+    ASSERT_EQ('e', buf[0]);
+    ASSERT_EQ('f', buf[1]);
+    ASSERT_EQ('g', buf[2]);
+    ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(BlobCacheTest, DoesntCacheIfKeyIsTooBig) {
+    char key[MAX_KEY_SIZE+1];
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    for (int i = 0; i < MAX_KEY_SIZE+1; i++) {
+        key[i] = 'a';
+    }
+    mBC->set(key, MAX_KEY_SIZE+1, "bbbb", 4);
+    ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE+1, buf, 4));
+    ASSERT_EQ(0xee, buf[0]);
+    ASSERT_EQ(0xee, buf[1]);
+    ASSERT_EQ(0xee, buf[2]);
+    ASSERT_EQ(0xee, buf[3]);
+}
+
+TEST_F(BlobCacheTest, DoesntCacheIfValueIsTooBig) {
+    char buf[MAX_VALUE_SIZE+1];
+    for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
+        buf[i] = 'b';
+    }
+    mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1);
+    for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
+        buf[i] = 0xee;
+    }
+    ASSERT_EQ(size_t(0), mBC->get("abcd", 4, buf, MAX_VALUE_SIZE+1));
+    for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
+        SCOPED_TRACE(i);
+        ASSERT_EQ(0xee, buf[i]);
+    }
+}
+
+TEST_F(BlobCacheTest, DoesntCacheIfKeyValuePairIsTooBig) {
+    // Check a testing assumptions
+    ASSERT_TRUE(MAX_TOTAL_SIZE < MAX_KEY_SIZE + MAX_VALUE_SIZE);
+    ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
+
+    enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE + 1 };
+
+    char key[MAX_KEY_SIZE];
+    char buf[bufSize];
+    for (int i = 0; i < MAX_KEY_SIZE; i++) {
+        key[i] = 'a';
+    }
+    for (int i = 0; i < bufSize; i++) {
+        buf[i] = 'b';
+    }
+
+    mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE);
+    ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, NULL, 0));
+}
+
+TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) {
+    char key[MAX_KEY_SIZE];
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    for (int i = 0; i < MAX_KEY_SIZE; i++) {
+        key[i] = 'a';
+    }
+    mBC->set(key, MAX_KEY_SIZE, "wxyz", 4);
+    ASSERT_EQ(size_t(4), mBC->get(key, MAX_KEY_SIZE, buf, 4));
+    ASSERT_EQ('w', buf[0]);
+    ASSERT_EQ('x', buf[1]);
+    ASSERT_EQ('y', buf[2]);
+    ASSERT_EQ('z', buf[3]);
+}
+
+TEST_F(BlobCacheTest, CacheMaxValueSizeSucceeds) {
+    char buf[MAX_VALUE_SIZE];
+    for (int i = 0; i < MAX_VALUE_SIZE; i++) {
+        buf[i] = 'b';
+    }
+    mBC->set("abcd", 4, buf, MAX_VALUE_SIZE);
+    for (int i = 0; i < MAX_VALUE_SIZE; i++) {
+        buf[i] = 0xee;
+    }
+    ASSERT_EQ(size_t(MAX_VALUE_SIZE), mBC->get("abcd", 4, buf,
+            MAX_VALUE_SIZE));
+    for (int i = 0; i < MAX_VALUE_SIZE; i++) {
+        SCOPED_TRACE(i);
+        ASSERT_EQ('b', buf[i]);
+    }
+}
+
+TEST_F(BlobCacheTest, CacheMaxKeyValuePairSizeSucceeds) {
+    // Check a testing assumption
+    ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
+
+    enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE };
+
+    char key[MAX_KEY_SIZE];
+    char buf[bufSize];
+    for (int i = 0; i < MAX_KEY_SIZE; i++) {
+        key[i] = 'a';
+    }
+    for (int i = 0; i < bufSize; i++) {
+        buf[i] = 'b';
+    }
+
+    mBC->set(key, MAX_KEY_SIZE, buf, bufSize);
+    ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, NULL, 0));
+}
+
+TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
+    char buf[1] = { 0xee };
+    mBC->set("x", 1, "y", 1);
+    ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1));
+    ASSERT_EQ('y', buf[0]);
+}
+
+TEST_F(BlobCacheTest, CacheSizeDoesntExceedTotalLimit) {
+    for (int i = 0; i < 256; i++) {
+        uint8_t k = i;
+        mBC->set(&k, 1, "x", 1);
+    }
+    int numCached = 0;
+    for (int i = 0; i < 256; i++) {
+        uint8_t k = i;
+        if (mBC->get(&k, 1, NULL, 0) == 1) {
+            numCached++;
+        }
+    }
+    ASSERT_GE(MAX_TOTAL_SIZE / 2, numCached);
+}
+
+TEST_F(BlobCacheTest, ExceedingTotalLimitHalvesCacheSize) {
+    // Fill up the entire cache with 1 char key/value pairs.
+    const int maxEntries = MAX_TOTAL_SIZE / 2;
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        mBC->set(&k, 1, "x", 1);
+    }
+    // Insert one more entry, causing a cache overflow.
+    {
+        uint8_t k = maxEntries;
+        mBC->set(&k, 1, "x", 1);
+    }
+    // Count the number of entries in the cache.
+    int numCached = 0;
+    for (int i = 0; i < maxEntries+1; i++) {
+        uint8_t k = i;
+        if (mBC->get(&k, 1, NULL, 0) == 1) {
+            numCached++;
+        }
+    }
+    ASSERT_EQ(maxEntries/2 + 1, numCached);
+}
+
+} // namespace android
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index a953487..b8ae79c 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -128,7 +128,6 @@
     size_t        mNumStssTableEntries;
     List<int32_t> mStssTableEntries;
 
-    size_t        mNumSttsTableEntries;
     struct SttsTableEntry {
 
         SttsTableEntry(uint32_t count, uint32_t duration)
@@ -137,8 +136,20 @@
         uint32_t sampleCount;
         uint32_t sampleDuration;  // time scale based
     };
+    size_t        mNumSttsTableEntries;
     List<SttsTableEntry> mSttsTableEntries;
 
+    struct CttsTableEntry {
+        CttsTableEntry(uint32_t count, int32_t timescaledDur)
+            : sampleCount(count), sampleDuration(timescaledDur) {}
+
+        uint32_t sampleCount;
+        int32_t sampleDuration;  // time scale based
+    };
+    bool          mHasNegativeCttsDeltaDuration;
+    size_t        mNumCttsTableEntries;
+    List<CttsTableEntry> mCttsTableEntries;
+
     // Sequence parameter set or picture parameter set
     struct AVCParamSet {
         AVCParamSet(uint16_t length, const uint8_t *data)
@@ -219,6 +230,7 @@
 
     // Duration is time scale based
     void addOneSttsTableEntry(size_t sampleCount, int32_t timescaledDur);
+    void addOneCttsTableEntry(size_t sampleCount, int32_t timescaledDur);
     void sendTrackSummary(bool hasMultipleTracks);
 
     // Write the boxes
@@ -227,6 +239,7 @@
     void writeStszBox();
     void writeStssBox();
     void writeSttsBox();
+    void writeCttsBox();
     void writeD263Box();
     void writePaspBox();
     void writeAvccBox();
@@ -1147,6 +1160,7 @@
         mEstimatedTrackSizeBytes += mNumStscTableEntries * 12 +  // stsc box size
                                     mNumStssTableEntries * 4 +   // stss box size
                                     mNumSttsTableEntries * 8 +   // stts box size
+                                    mNumCttsTableEntries * 8 +   // ctts box size
                                     stcoBoxSizeBytes +           // stco box size
                                     stszBoxSizeBytes;            // stsz box size
     }
@@ -1173,6 +1187,20 @@
     ++mNumSttsTableEntries;
 }
 
+void MPEG4Writer::Track::addOneCttsTableEntry(
+        size_t sampleCount, int32_t duration) {
+
+    if (mIsAudio) {
+        return;
+    }
+    if (duration < 0 && !mHasNegativeCttsDeltaDuration) {
+        mHasNegativeCttsDeltaDuration = true;
+    }
+    CttsTableEntry cttsEntry(sampleCount, duration);
+    mCttsTableEntries.push_back(cttsEntry);
+    ++mNumCttsTableEntries;
+}
+
 void MPEG4Writer::Track::addChunkOffset(off64_t offset) {
     ++mNumStcoTableEntries;
     mChunkOffsets.push_back(offset);
@@ -1483,6 +1511,7 @@
     mNumStssTableEntries = 0;
     mNumStscTableEntries = 0;
     mNumSttsTableEntries = 0;
+    mNumCttsTableEntries = 0;
     mMdatSizeBytes = 0;
     mIsMediaTimeAdjustmentOn = false;
     mPrevMediaTimeAdjustTimestampUs = 0;
@@ -1491,6 +1520,7 @@
     mTotalDriftTimeToAdjustUs = 0;
     mPrevTotalAccumDriftTimeUs = 0;
     mMaxChunkDurationUs = 0;
+    mHasNegativeCttsDeltaDuration = false;
 
     pthread_create(&mThread, &attr, ThreadWrapper, this);
     pthread_attr_destroy(&attr);
@@ -1932,14 +1962,19 @@
     int64_t chunkTimestampUs = 0;
     int32_t nChunks = 0;
     int32_t nZeroLengthFrames = 0;
-    int64_t lastTimestampUs = 0;  // Previous sample time stamp in ms
-    int64_t lastDurationUs = 0;   // Between the previous two samples in ms
-    int64_t currDurationTicks = 0;  // Timescale based ticks
-    int64_t lastDurationTicks = 0;  // Timescale based ticks
-    int32_t sampleCount = 1;      // Sample count in the current stts table entry
-    uint32_t previousSampleSize = 0;  // Size of the previous sample
+    int64_t lastTimestampUs = 0;      // Previous sample time stamp
+    int64_t lastCttsTimeUs = 0;       // Previous sample time stamp
+    int64_t lastDurationUs = 0;       // Between the previous two samples
+    int64_t currDurationTicks = 0;    // Timescale based ticks
+    int64_t lastDurationTicks = 0;    // Timescale based ticks
+    int32_t sampleCount = 1;          // Sample count in the current stts table entry
+    int64_t currCttsDurTicks = 0;     // Timescale based ticks
+    int64_t lastCttsDurTicks = 0;     // Timescale based ticks
+    int32_t cttsSampleCount = 1;      // Sample count in the current ctts table entry
+    uint32_t previousSampleSize = 0;      // Size of the previous sample
     int64_t previousPausedDurationUs = 0;
-    int64_t timestampUs;
+    int64_t timestampUs = 0;
+    int64_t cttsDeltaTimeUs = 0;
 
     if (mIsAudio) {
         prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
@@ -2063,7 +2098,6 @@
          *
          */
         CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
-        LOGV("%s timestampUs: %lld", mIsAudio? "Audio": "Video", timestampUs);
 
 ////////////////////////////////////////////////////////////////////////////////
         if (mNumSamples == 0) {
@@ -2084,6 +2118,24 @@
 
         timestampUs -= previousPausedDurationUs;
         CHECK(timestampUs >= 0);
+        if (!mIsAudio) {
+            /*
+             * Composition time: timestampUs
+             * Decoding time: decodingTimeUs
+             * Composition time delta = composition time - decoding time
+             *
+             * We save picture decoding time stamp delta in stts table entries,
+             * and composition time delta duration in ctts table entries.
+             */
+            int64_t decodingTimeUs;
+            CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs));
+            decodingTimeUs -= previousPausedDurationUs;
+            int64_t timeUs = decodingTimeUs;
+            cttsDeltaTimeUs = timestampUs - decodingTimeUs;
+            timestampUs = decodingTimeUs;
+            LOGV("decoding time: %lld and ctts delta time: %lld",
+                timestampUs, cttsDeltaTimeUs);
+        }
 
         // Media time adjustment for real-time applications
         if (mIsRealTimeRecording) {
@@ -2139,6 +2191,18 @@
             } else {
                 ++sampleCount;
             }
+
+            if (!mIsAudio) {
+                currCttsDurTicks =
+                     ((cttsDeltaTimeUs * mTimeScale + 500000LL) / 1000000LL -
+                     (lastCttsTimeUs * mTimeScale + 500000LL) / 1000000LL);
+                if (currCttsDurTicks != lastCttsDurTicks) {
+                    addOneCttsTableEntry(cttsSampleCount, lastCttsDurTicks);
+                    cttsSampleCount = 1;
+                } else {
+                    ++cttsSampleCount;
+                }
+            }
         }
         if (mSamplesHaveSameSize) {
             if (mNumSamples >= 2 && previousSampleSize != sampleSize) {
@@ -2152,6 +2216,11 @@
         lastDurationTicks = currDurationTicks;
         lastTimestampUs = timestampUs;
 
+        if (!mIsAudio) {
+            lastCttsDurTicks = currCttsDurTicks;
+            lastCttsTimeUs = cttsDeltaTimeUs;
+        }
+
         if (isSync != 0) {
             addOneStssTableEntry(mNumSamples);
         }
@@ -2221,8 +2290,10 @@
     if (mNumSamples == 1) {
         lastDurationUs = 0;  // A single sample's duration
         lastDurationTicks = 0;
+        lastCttsDurTicks = 0;
     } else {
         ++sampleCount;  // Count for the last sample
+        ++cttsSampleCount;
     }
 
     if (mNumSamples <= 2) {
@@ -2234,6 +2305,7 @@
         addOneSttsTableEntry(sampleCount, lastDurationTicks);
     }
 
+    addOneCttsTableEntry(cttsSampleCount, lastCttsDurTicks);
     mTrackDurationUs += lastDurationUs;
     mReachedEOS = true;
 
@@ -2432,6 +2504,7 @@
     }
     mOwner->endBox();  // stsd
     writeSttsBox();
+    writeCttsBox();
     if (!mIsAudio) {
         writeStssBox();
     }
@@ -2782,13 +2855,49 @@
     int32_t dur = (trackStartTimeOffsetUs * mTimeScale + 500000LL) / 1000000LL;
     mOwner->writeInt32(dur + it->sampleDuration);
 
+    int64_t totalCount = 1;
     while (++it != mSttsTableEntries.end()) {
         mOwner->writeInt32(it->sampleCount);
         mOwner->writeInt32(it->sampleDuration);
+        totalCount += it->sampleCount;
     }
+    CHECK(totalCount == mNumSamples);
     mOwner->endBox();  // stts
 }
 
+void MPEG4Writer::Track::writeCttsBox() {
+    if (mIsAudio) {  // ctts is not for audio
+        return;
+    }
+
+    // Do not write ctts box when there is no need to have it.
+    if ((mNumCttsTableEntries == 1 &&
+        mCttsTableEntries.begin()->sampleDuration == 0) ||
+        mNumCttsTableEntries == 0) {
+        return;
+    }
+
+    LOGV("ctts box has %d entries", mNumCttsTableEntries);
+
+    mOwner->beginBox("ctts");
+    if (mHasNegativeCttsDeltaDuration) {
+        mOwner->writeInt32(0x00010000);  // version=1, flags=0
+    } else {
+        mOwner->writeInt32(0);  // version=0, flags=0
+    }
+    mOwner->writeInt32(mNumCttsTableEntries);
+
+    int64_t totalCount = 0;
+    for (List<CttsTableEntry>::iterator it = mCttsTableEntries.begin();
+         it != mCttsTableEntries.end(); ++it) {
+        mOwner->writeInt32(it->sampleCount);
+        mOwner->writeInt32(it->sampleDuration);
+        totalCount += it->sampleCount;
+    }
+    CHECK(totalCount == mNumSamples);
+    mOwner->endBox();  // ctts
+}
+
 void MPEG4Writer::Track::writeStssBox() {
     mOwner->beginBox("stss");
     mOwner->writeInt32(0);  // version=0, flags=0
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 72d0d08..c4fcc79 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1981,6 +1981,20 @@
     return bufInfo;
 }
 
+int64_t OMXCodec::retrieveDecodingTimeUs(bool isCodecSpecific) {
+    CHECK(mIsEncoder);
+    CHECK(!mDecodingTimeList.empty());
+    List<int64_t>::iterator it = mDecodingTimeList.begin();
+    int64_t timeUs = *it;
+
+    // If the output buffer is codec specific configuration,
+    // do not remove the decoding time from the list.
+    if (!isCodecSpecific) {
+        mDecodingTimeList.erase(it);
+    }
+    return timeUs;
+}
+
 void OMXCodec::on_message(const omx_message &msg) {
     if (mState == ERROR) {
         LOGW("Dropping OMX message - we're in ERROR state.");
@@ -2128,14 +2142,21 @@
                 if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
                     buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
                 }
+                bool isCodecSpecific = false;
                 if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_CODECCONFIG) {
                     buffer->meta_data()->setInt32(kKeyIsCodecConfig, true);
+                    isCodecSpecific = true;
                 }
 
                 if (isGraphicBuffer || mQuirks & kOutputBuffersAreUnreadable) {
                     buffer->meta_data()->setInt32(kKeyIsUnreadable, true);
                 }
 
+                if (mIsEncoder) {
+                    int64_t decodingTimeUs = retrieveDecodingTimeUs(isCodecSpecific);
+                    buffer->meta_data()->setInt64(kKeyDecodingTime, decodingTimeUs);
+                }
+
                 buffer->meta_data()->setPointer(
                         kKeyPlatformPrivate,
                         msg.u.extended_buffer_data.platform_private);
@@ -2938,6 +2959,9 @@
         int64_t lastBufferTimeUs;
         CHECK(srcBuffer->meta_data()->findInt64(kKeyTime, &lastBufferTimeUs));
         CHECK(lastBufferTimeUs >= 0);
+        if (mIsEncoder) {
+            mDecodingTimeList.push_back(lastBufferTimeUs);
+        }
 
         if (offset == 0) {
             timestampUs = lastBufferTimeUs;
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml
index ef57228..72519fb 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml
@@ -57,15 +57,15 @@
                 android:layout_width="match_parent"
                 android:layout_weight="1"
                 >
-                <LinearLayout
+                <com.android.systemui.statusbar.policy.NotificationRowLayout
                     android:id="@+id/content"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:gravity="center_horizontal|bottom"
-                    android:orientation="vertical"
                     android:clickable="true"
                     android:focusable="true"
                     android:descendantFocusability="afterDescendants"
+                    systemui:rowHeight="@dimen/notification_height"
                     />
             </ScrollView>
         </LinearLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml
index 8e456b2..93085d7 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml
@@ -1,6 +1,6 @@
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="65dp"
+    android:layout_height="@dimen/notification_height"
     >
 
     <ImageButton
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 18e8273..6670eff 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -18,7 +18,9 @@
 */
 -->
 
-<com.android.systemui.statusbar.phone.ExpandedView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.systemui.statusbar.phone.ExpandedView 
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:orientation="vertical"
     android:focusable="true"
     android:descendantFocusability="afterDescendants"
@@ -97,10 +99,11 @@
                     android:textAppearance="@style/TextAppearance.StatusBar.Title"
                     android:text="@string/status_bar_ongoing_events_title"
                     />
-                <LinearLayout android:id="@+id/ongoingItems"
+                <com.android.systemui.statusbar.policy.NotificationRowLayout
+                    android:id="@+id/ongoingItems"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:orientation="vertical"
+                    systemui:rowHeight="@dimen/notification_height"
                     />
 
                 <TextView android:id="@+id/latestTitle"
@@ -111,10 +114,11 @@
                     android:textAppearance="@style/TextAppearance.StatusBar.Title"
                     android:text="@string/status_bar_latest_events_title"
                     />
-                <LinearLayout android:id="@+id/latestItems"
+                <com.android.systemui.statusbar.policy.NotificationRowLayout
+                    android:id="@+id/latestItems"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:orientation="vertical"
+                    systemui:rowHeight="@dimen/notification_height"
                     />
             </LinearLayout>
         </ScrollView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 8e456b2..93085d7 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -1,6 +1,6 @@
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="65dp"
+    android:layout_height="@dimen/notification_height"
     >
 
     <ImageButton
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index fb2f7d63..5291629 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -24,5 +24,8 @@
     <declare-styleable name="NotificationLinearLayout">
         <attr name="insetLeft" format="dimension" />
     </declare-styleable>
+    <declare-styleable name="NotificationRowLayout">
+        <attr name="rowHeight" format="dimension" />
+    </declare-styleable>
 </resources>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 657dc46..5f0fbef 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -47,5 +47,8 @@
 
     <!-- thickness (height) of the navigation bar on phones that require it -->
     <dimen name="navigation_bar_size">42dp</dimen>
+
+    <!-- thickness (height) of each notification row, including any separators or padding -->
+    <dimen name="notification_height">65dp</dimen>
 </resources>
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
index 92b8976..51fc7c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.animation.LayoutTransition;
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.Display;
@@ -37,6 +38,8 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
+
+        setLayerType(LAYER_TYPE_HARDWARE, null);
     }
 
     /** We want to shrink down to 0, and ignore the background. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 00de920..3d15a1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -130,11 +130,11 @@
     // ongoing
     NotificationData mOngoing = new NotificationData();
     TextView mOngoingTitle;
-    LinearLayout mOngoingItems;
+    ViewGroup mOngoingItems;
     // latest
     NotificationData mLatest = new NotificationData();
     TextView mLatestTitle;
-    LinearLayout mLatestItems;
+    ViewGroup mLatestItems;
     // position
     int[] mPositionTmp = new int[2];
     boolean mExpanded;
@@ -268,9 +268,9 @@
         mExpandedView = expanded;
         mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout);
         mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle);
-        mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems);
+        mOngoingItems = (ViewGroup)expanded.findViewById(R.id.ongoingItems);
         mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle);
-        mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems);
+        mLatestItems = (ViewGroup)expanded.findViewById(R.id.latestItems);
         mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle);
         mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button);
         mClearButton.setOnClickListener(mClearButtonListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
new file mode 100644
index 0000000..24eee27
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.HashSet;
+
+import com.android.systemui.R;
+
+public class NotificationRowLayout extends ViewGroup {
+    private static final String TAG = "NotificationRowLayout";
+    private static final boolean DEBUG = false;
+
+    private static final boolean ANIMATE_LAYOUT = true;
+
+    private static final int ANIM_LEN = DEBUG ? 5000 : 250;
+
+    Rect mTmpRect = new Rect();
+    int mNumRows = 0;
+    int mRowHeight = 0;
+    int mHeight = 0;
+
+    HashSet<View> mAppearingViews = new HashSet<View>();
+    HashSet<View> mDisappearingViews = new HashSet<View>();
+
+    public NotificationRowLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public NotificationRowLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NotificationRowLayout,
+                defStyle, 0);
+        mRowHeight = a.getDimensionPixelSize(R.styleable.NotificationRowLayout_rowHeight, 0);
+        a.recycle();
+
+        setLayoutTransition(null);
+
+        if (DEBUG) {
+            setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
+                @Override
+                public void onChildViewAdded(View parent, View child) {
+                    Slog.d(TAG, "view added: " + child + "; new count: " + getChildCount());
+                }
+                @Override
+                public void onChildViewRemoved(View parent, View child) {
+                    Slog.d(TAG, "view removed: " + child + "; new count: " + (getChildCount() - 1));
+                }
+            });
+
+            setBackgroundColor(0x80FF8000);
+        }
+
+    }
+
+    //**
+    @Override
+    public void addView(View child, int index, LayoutParams params) {
+        super.addView(child, index, params);
+
+        final View childF = child;
+
+        if (ANIMATE_LAYOUT) {
+            mAppearingViews.add(child);
+
+            child.setPivotY(0);
+            AnimatorSet a = new AnimatorSet();
+            a.playTogether(
+                    ObjectAnimator.ofFloat(child, "alpha", 0f, 1f)
+//                    ,ObjectAnimator.ofFloat(child, "scaleY", 0f, 1f)
+            );
+            a.setDuration(ANIM_LEN);
+            a.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mAppearingViews.remove(childF);
+                }
+            });
+            a.start();
+            requestLayout(); // start the container animation
+        }
+    }
+
+    @Override
+    public void removeView(View child) {
+        final View childF = child;
+        if (ANIMATE_LAYOUT) {
+            if (mAppearingViews.contains(child)) {
+                mAppearingViews.remove(child);
+            }
+            mDisappearingViews.add(child);
+
+            child.setPivotY(0);
+            AnimatorSet a = new AnimatorSet();
+            a.playTogether(
+                    ObjectAnimator.ofFloat(child, "alpha", 0f)
+//                    ,ObjectAnimator.ofFloat(child, "scaleY", 0f)
+                    ,ObjectAnimator.ofFloat(child, "translationX", 300f)
+            );
+            a.setDuration(ANIM_LEN);
+            a.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    NotificationRowLayout.super.removeView(childF);
+                    childF.setAlpha(1f);
+                    mDisappearingViews.remove(childF);
+                }
+            });
+            a.start();
+            requestLayout(); // start the container animation
+        } else {
+            super.removeView(child);
+        }
+    }
+    //**
+
+    @Override
+    public void onFinishInflate() {
+        super.onFinishInflate();
+        setWillNotDraw(false);
+    }
+
+    @Override
+    public void onDraw(android.graphics.Canvas c) {
+        super.onDraw(c);
+        if (DEBUG) {
+            Slog.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
+                    + getMeasuredHeight() + "px");
+            c.save();
+            c.clipRect(6, 6, c.getWidth() - 6, getMeasuredHeight() - 6,
+                    android.graphics.Region.Op.DIFFERENCE);
+            c.drawColor(0xFFFF8000);
+            c.restore();
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int count = getChildCount();
+
+        // pass 1: count the number of non-GONE views
+        int numRows = 0;
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+            if (mDisappearingViews.contains(child)) {
+                continue;
+            }
+            numRows++;
+        }
+        if (numRows != mNumRows) {
+            // uh oh, now you made us go and do work
+            
+            final int computedHeight = numRows * mRowHeight;
+            if (DEBUG) {
+                Slog.d(TAG, String.format("rows went from %d to %d, resizing to %dpx",
+                            mNumRows, numRows, computedHeight));
+            }
+
+            mNumRows = numRows;
+
+            if (ANIMATE_LAYOUT && isShown()) {
+                ObjectAnimator.ofInt(this, "forcedHeight", computedHeight)
+                    .setDuration(ANIM_LEN)
+                    .start();
+            } else {
+                setForcedHeight(computedHeight);
+            }
+        }
+
+        // pass 2: you know, do the measuring
+        final int childWidthMS = widthMeasureSpec;
+        final int childHeightMS = MeasureSpec.makeMeasureSpec(
+                mRowHeight, MeasureSpec.EXACTLY);
+
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+
+            child.measure(childWidthMS, childHeightMS);
+        }
+
+        setMeasuredDimension(
+                getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
+                resolveSize(getForcedHeight(), heightMeasureSpec));
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        final int width = right - left;
+        final int height = bottom - top;
+
+        if (DEBUG) Slog.d(TAG, "onLayout: height=" + height);
+
+        final int count = getChildCount();
+        int y = 0;
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+//            final int thisRowHeight = (int)(
+//                ((mAppearingViews.contains(child) || mDisappearingViews.contains(child))
+//                        ? child.getScaleY()
+//                        : 1.0f)
+//                * mRowHeight);
+            final int thisRowHeight = (int)(child.getAlpha() * mRowHeight);
+//            child.layout(0, y, width, y + thisRowHeight);
+            child.layout(0, y, width, y + mRowHeight);
+            y += thisRowHeight;
+        }
+    }
+
+    public void setForcedHeight(int h) {
+        if (DEBUG) Slog.d(TAG, "forcedHeight: " + h);
+        if (h != mHeight) {
+            mHeight = h;
+            requestLayout();
+        }
+    }
+
+    public int getForcedHeight() {
+        return mHeight;
+    }
+}
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 6f7a6ee..0178395 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -22,6 +22,7 @@
 import com.android.internal.widget.SlidingTab;
 import com.android.internal.widget.WaveView;
 import com.android.internal.widget.WaveView.OnTriggerListener;
+import com.android.internal.widget.multiwaveview.MultiWaveView;
 
 import android.app.ActivityManager;
 import android.content.Context;
@@ -91,6 +92,8 @@
     private WaveView mEnergyWave;
     private SlidingTabMethods mSlidingTabMethods;
     private WaveViewMethods mWaveViewMethods;
+    private MultiWaveView mMultiWaveView;
+    private MultiWaveViewMethods mMultiWaveViewMethods;
 
     /**
      * The status of this lock screen.
@@ -166,34 +169,9 @@
             if (whichHandle == SlidingTab.OnTriggerListener.LEFT_HANDLE) {
                 mCallback.goToUnlockScreen();
             } else if (whichHandle == SlidingTab.OnTriggerListener.RIGHT_HANDLE) {
-                // toggle silent mode
-                mSilentMode = !mSilentMode;
-                if (mSilentMode) {
-                    final boolean vibe = (Settings.System.getInt(
-                        getContext().getContentResolver(),
-                        Settings.System.VIBRATE_IN_SILENT, 1) == 1);
-
-                    mAudioManager.setRingerMode(vibe
-                        ? AudioManager.RINGER_MODE_VIBRATE
-                        : AudioManager.RINGER_MODE_SILENT);
-                } else {
-                    mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
-                }
-
+                toggleRingMode();
                 updateRightTabResources();
-
-                String message = mSilentMode ?
-                        getContext().getString(R.string.global_action_silent_mode_on_status) :
-                        getContext().getString(R.string.global_action_silent_mode_off_status);
-
-                final int toastIcon = mSilentMode
-                    ? R.drawable.ic_lock_ringer_off
-                    : R.drawable.ic_lock_ringer_on;
-
-                final int toastColor = mSilentMode
-                    ? getContext().getResources().getColor(R.color.keyguard_text_color_soundoff)
-                    : getContext().getResources().getColor(R.color.keyguard_text_color_soundon);
-                toastMessage(mScreenLocked, message, toastColor, toastIcon);
+                doSilenceRingToast();
                 mCallback.pokeWakelock();
             }
         }
@@ -214,19 +192,14 @@
         }
     }
 
-    class WaveViewMethods implements WaveView.OnTriggerListener {
-        private static final int WAIT_FOR_ANIMATION_TIMEOUT = 0;
-        private static final int STAY_ON_WHILE_GRABBED_TIMEOUT = 30000;
+    private static final int WAIT_FOR_ANIMATION_TIMEOUT = 0;
+    private static final int STAY_ON_WHILE_GRABBED_TIMEOUT = 30000;
 
+    class WaveViewMethods implements WaveView.OnTriggerListener {
         /** {@inheritDoc} */
         public void onTrigger(View v, int whichHandle) {
             if (whichHandle == WaveView.OnTriggerListener.CENTER_HANDLE) {
-                // Delay hiding lock screen long enough for animation to finish
-                postDelayed(new Runnable() {
-                    public void run() {
-                        mCallback.goToUnlockScreen();
-                    }
-                }, WAIT_FOR_ANIMATION_TIMEOUT);
+                requestUnlockScreen();
             }
         }
 
@@ -243,6 +216,80 @@
         }
     }
 
+    class MultiWaveViewMethods implements MultiWaveView.OnTriggerListener {
+        public void onGrabbed(View v, int handle) {
+
+        }
+        public void onReleased(View v, int handle) {
+
+        }
+        public void onTrigger(View v, int target) {
+            if (target == 0) { // TODO: Use resources to determine which handle was used
+                mCallback.goToUnlockScreen();
+            } else if (target == 2) {
+                toggleRingMode();
+                updateResources();
+                doSilenceRingToast();
+                mCallback.pokeWakelock();
+            }
+
+        }
+
+        private void updateResources() {
+            mMultiWaveView.setTargetResources(mSilentMode ? R.array.lockscreen_targets_when_silent
+                    : R.array.lockscreen_targets_when_soundon);
+        }
+
+        public void onGrabbedStateChange(View v, int handle) {
+            // Don't poke the wake lock when returning to a state where the handle is
+            // not grabbed since that can happen when the system (instead of the user)
+            // cancels the grab.
+            if (handle != MultiWaveView.OnTriggerListener.NO_HANDLE) {
+                mCallback.pokeWakelock();
+            }
+        }
+    }
+
+    private void requestUnlockScreen() {
+        // Delay hiding lock screen long enough for animation to finish
+        postDelayed(new Runnable() {
+            public void run() {
+                mCallback.goToUnlockScreen();
+            }
+        }, WAIT_FOR_ANIMATION_TIMEOUT);
+    }
+
+    private void doSilenceRingToast() {
+        String message = mSilentMode ?
+                getContext().getString(R.string.global_action_silent_mode_on_status) :
+                getContext().getString(R.string.global_action_silent_mode_off_status);
+
+        final int toastIcon = mSilentMode
+            ? R.drawable.ic_lock_ringer_off
+            : R.drawable.ic_lock_ringer_on;
+
+        final int toastColor = mSilentMode
+            ? getContext().getResources().getColor(R.color.keyguard_text_color_soundoff)
+            : getContext().getResources().getColor(R.color.keyguard_text_color_soundon);
+        toastMessage(mScreenLocked, message, toastColor, toastIcon);
+    }
+
+    private void toggleRingMode() {
+        // toggle silent mode
+        mSilentMode = !mSilentMode;
+        if (mSilentMode) {
+            final boolean vibe = (Settings.System.getInt(
+                getContext().getContentResolver(),
+                Settings.System.VIBRATE_IN_SILENT, 1) == 1);
+
+            mAudioManager.setRingerMode(vibe
+                ? AudioManager.RINGER_MODE_VIBRATE
+                : AudioManager.RINGER_MODE_SILENT);
+        } else {
+            mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+        }
+    }
+
     /**
      * In general, we enable unlocking the insecure key guard with the menu key. However, there are
      * some cases where we wish to disable it, notably when the menu button placement or technology
@@ -319,9 +366,9 @@
         mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
         mSilentMode = isSilentMode();
 
-        mSlidingTab = (SlidingTab) findViewById(R.id.tab_selector);
-        mEnergyWave = (WaveView) findViewById(R.id.wave_view);
-        if (mSlidingTab != null) {
+        View unlockWidget = findViewById(R.id.unlock_widget);
+        if (unlockWidget instanceof SlidingTab) {
+            mSlidingTab = (SlidingTab) unlockWidget;
             mSlidingTab.setHoldAfterTrigger(true, false);
             mSlidingTab.setLeftHintText(R.string.lockscreen_unlock_label);
             mSlidingTab.setLeftTabResources(
@@ -332,11 +379,17 @@
             mSlidingTabMethods = new SlidingTabMethods();
             mSlidingTab.setOnTriggerListener(mSlidingTabMethods);
             mSlidingTabMethods.updateRightTabResources();
-        } else if (mEnergyWave != null) {
+        } else if (unlockWidget instanceof WaveView) {
+            mEnergyWave = (WaveView) unlockWidget;
             mWaveViewMethods = new WaveViewMethods();
             mEnergyWave.setOnTriggerListener(mWaveViewMethods);
+        } else if (unlockWidget instanceof MultiWaveView) {
+            mMultiWaveView = (MultiWaveView) unlockWidget;
+            mMultiWaveViewMethods = new MultiWaveViewMethods();
+            mMultiWaveViewMethods.updateResources(); // update silence/ring resources
+            mMultiWaveView.setOnTriggerListener(mMultiWaveViewMethods);
         } else {
-            throw new IllegalStateException("Must have either SlidingTab or WaveView defined");
+            throw new IllegalStateException("Unrecognized unlock widget: " + unlockWidget);
         }
 
         resetStatusInfo(updateMonitor);
diff --git a/services/camera/libcameraservice/CameraHardwareInterface.h b/services/camera/libcameraservice/CameraHardwareInterface.h
index 7a18831..a3749cf 100644
--- a/services/camera/libcameraservice/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/CameraHardwareInterface.h
@@ -552,7 +552,7 @@
 #define anw(n) __to_anw(((struct camera_preview_window *)n)->user)
 
     static int __dequeue_buffer(struct preview_stream_ops* w,
-                      buffer_handle_t** buffer)
+                                buffer_handle_t** buffer, int *stride)
     {
         int rc;
         ANativeWindow *a = anw(w);
@@ -560,8 +560,10 @@
         rc = a->dequeueBuffer(a, &anb);
         if (!rc) {
             rc = a->lockBuffer(a, anb);
-            if (!rc)
+            if (!rc) {
                 *buffer = &anb->handle;
+                *stride = anb->stride;
+            }
             else
                 a->cancelBuffer(a, anb);
         }
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 29add52..6e803a4 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -192,6 +192,7 @@
         outAxisInfo->maxValue = info.maximum;
         outAxisInfo->flat = info.flat;
         outAxisInfo->fuzz = info.fuzz;
+        outAxisInfo->resolution = info.resolution;
     }
     return OK;
 }
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index 558959b..abe1318 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -34,39 +34,6 @@
 
 #include <linux/input.h>
 
-/* These constants are not defined in linux/input.h in the version of the kernel
- * headers currently provided with Bionic. */
-
-#define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len)
-
-#define INPUT_PROP_POINTER 0x00
-#define INPUT_PROP_DIRECT 0x01
-#define INPUT_PROP_BUTTONPAD 0x02
-#define INPUT_PROP_SEMI_MT 0x03
-#define INPUT_PROP_MAX 0x1f
-#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
-
-#define ABS_MT_SLOT 0x2f
-#define ABS_MT_TOUCH_MAJOR 0x30
-#define ABS_MT_TOUCH_MINOR 0x31
-#define ABS_MT_WIDTH_MAJOR 0x32
-#define ABS_MT_WIDTH_MINOR 0x33
-#define ABS_MT_ORIENTATION 0x34
-#define ABS_MT_POSITION_X 0x35
-#define ABS_MT_POSITION_Y 0x36
-#define ABS_MT_TOOL_TYPE 0x37
-#define ABS_MT_BLOB_ID 0x38
-#define ABS_MT_TRACKING_ID 0x39
-#define ABS_MT_PRESSURE 0x3a
-#define ABS_MT_DISTANCE 0x3b
-
-#define MT_TOOL_FINGER 0
-#define MT_TOOL_PEN 1
-
-#define SYN_MT_REPORT 2
-#define SYN_DROPPED 3
-
-
 /* Convenience constants. */
 
 #define BTN_FIRST 0x100  // first button scancode
@@ -97,6 +64,7 @@
     int32_t maxValue;  // maximum value
     int32_t flat;      // center flat position, eg. flat == 8 means center is between -8 and 8
     int32_t fuzz;      // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise
+    int32_t resolution; // resolution in units per mm or radians per mm
 
     inline void clear() {
         valid = false;
@@ -104,6 +72,7 @@
         maxValue = 0;
         flat = 0;
         fuzz = 0;
+        resolution = 0;
     }
 };
 
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 4c6098d..eff65c2 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -1464,6 +1464,23 @@
         injectionPermission = INJECTION_PERMISSION_GRANTED;
     }
 
+    // Check whether windows listening for outside touches are owned by the same UID. If it is
+    // set the policy flag that we will not reveal coordinate information to this window.
+    if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
+        const InputWindow* foregroundWindow = mTempTouchState.getFirstForegroundWindow();
+        const int32_t foregroundWindowUid = foregroundWindow->ownerUid;
+        for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
+            const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
+            if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
+                const InputWindow* inputWindow = touchedWindow.window;
+                if (inputWindow->ownerUid != foregroundWindowUid) {
+                    mTempTouchState.addOrUpdateWindow(inputWindow,
+                            InputTarget::FLAG_ZERO_COORDS, BitSet32(0));
+                }
+            }
+        }
+    }
+
     // Ensure all touched foreground windows are ready for new input.
     for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
         const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
@@ -1987,7 +2004,8 @@
 
         // Set the X and Y offset depending on the input source.
         float xOffset, yOffset, scaleFactor;
-        if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
+        if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER
+                && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
             scaleFactor = dispatchEntry->scaleFactor;
             xOffset = dispatchEntry->xOffset * scaleFactor;
             yOffset = dispatchEntry->yOffset * scaleFactor;
@@ -2002,6 +2020,14 @@
             xOffset = 0.0f;
             yOffset = 0.0f;
             scaleFactor = 1.0f;
+
+            // We don't want the dispatch target to know.
+            if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
+                for (size_t i = 0; i < motionEntry->pointerCount; i++) {
+                    scaledCoords[i].clear();
+                }
+                usingCoords = scaledCoords;
+            }
         }
 
         // Update the connection's input state.
@@ -2030,9 +2056,11 @@
             MotionSample* nextMotionSample = firstMotionSample->next;
             for (; nextMotionSample != NULL; nextMotionSample = nextMotionSample->next) {
                 if (usingCoords == scaledCoords) {
-                    for (size_t i = 0; i < motionEntry->pointerCount; i++) {
-                        scaledCoords[i] = nextMotionSample->pointerCoords[i];
-                        scaledCoords[i].scale(scaleFactor);
+                    if (!(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
+                        for (size_t i = 0; i < motionEntry->pointerCount; i++) {
+                            scaledCoords[i] = nextMotionSample->pointerCoords[i];
+                            scaledCoords[i].scale(scaleFactor);
+                        }
                     }
                 } else {
                     usingCoords = nextMotionSample->pointerCoords;
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index 37cef90..39d4aeb 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -96,6 +96,12 @@
         /* This flag indicates that a motion event is being split across multiple windows. */
         FLAG_SPLIT = 1 << 2,
 
+        /* This flag indicates that the pointer coordinates dispatched to the application
+         * will be zeroed out to avoid revealing information to an application. This is
+         * used in conjunction with FLAG_DISPATCH_AS_OUTSIDE to prevent apps not sharing
+         * the same UID from watching all touches. */
+        FLAG_ZERO_COORDS = 1 << 3,
+
         /* This flag indicates that the event should be sent as is.
          * Should always be set unless the event is to be transmuted. */
         FLAG_DISPATCH_AS_IS = 1 << 8,
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index fcc6198..15bb300 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -1044,8 +1044,8 @@
 void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump,
         const RawAbsoluteAxisInfo& axis, const char* name) {
     if (axis.valid) {
-        dump.appendFormat(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d\n",
-                name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz);
+        dump.appendFormat(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n",
+                name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz, axis.resolution);
     } else {
         dump.appendFormat(INDENT4 "%s: unknown range\n", name);
     }
@@ -5656,9 +5656,10 @@
         dump.appendFormat(INDENT4 "  scale=%0.5f, offset=%0.5f, "
                 "highScale=%0.5f, highOffset=%0.5f\n",
                 axis.scale, axis.offset, axis.highScale, axis.highOffset);
-        dump.appendFormat(INDENT4 "  rawAxis=%d, rawMin=%d, rawMax=%d, rawFlat=%d, rawFuzz=%d\n",
+        dump.appendFormat(INDENT4 "  rawAxis=%d, rawMin=%d, rawMax=%d, "
+                "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n",
                 mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue,
-                axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz);
+                axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz, axis.rawAxisInfo.resolution);
     }
 }
 
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index d04c9e7..acda86b 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -481,7 +481,7 @@
     }
 
     void addAbsoluteAxis(int32_t deviceId, int axis,
-            int32_t minValue, int32_t maxValue, int flat, int fuzz) {
+            int32_t minValue, int32_t maxValue, int flat, int fuzz, int resolution = 0) {
         Device* device = getDevice(deviceId);
 
         RawAbsoluteAxisInfo info;
@@ -490,6 +490,7 @@
         info.maxValue = maxValue;
         info.flat = flat;
         info.fuzz = fuzz;
+        info.resolution = resolution;
         device->absoluteAxes.add(axis, info);
     }
 
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 8f179f5..2190b30 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -882,8 +882,7 @@
                 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
 
         final String[] ifaces = listInterfaces();
-        final NetworkStats.Builder stats = new NetworkStats.Builder(
-                SystemClock.elapsedRealtime(), ifaces.length);
+        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), ifaces.length);
 
         for (String iface : ifaces) {
             final long rx = getInterfaceCounter(iface, true);
@@ -891,7 +890,7 @@
             stats.addEntry(iface, NetworkStats.UID_ALL, rx, tx);
         }
 
-        return stats.build();
+        return stats;
     }
 
     @Override
@@ -900,7 +899,7 @@
                 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
 
         final String[] knownUids = PATH_PROC_UID_STAT.list();
-        final NetworkStats.Builder stats = new NetworkStats.Builder(
+        final NetworkStats stats = new NetworkStats(
                 SystemClock.elapsedRealtime(), knownUids.length);
 
         for (String uid : knownUids) {
@@ -908,7 +907,7 @@
             collectNetworkStatsDetail(stats, uidInt);
         }
 
-        return stats.build();
+        return stats;
     }
 
     @Override
@@ -918,13 +917,12 @@
                     android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
         }
 
-        final NetworkStats.Builder stats = new NetworkStats.Builder(
-                SystemClock.elapsedRealtime(), 1);
+        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
         collectNetworkStatsDetail(stats, uid);
-        return stats.build();
+        return stats;
     }
 
-    private void collectNetworkStatsDetail(NetworkStats.Builder stats, int uid) {
+    private void collectNetworkStatsDetail(NetworkStats stats, int uid) {
         // TODO: kernel module will provide interface-level stats in future
         // TODO: migrate these stats to come across netd in bulk, instead of all
         // these individual file reads.
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index fd03e5f..3484baf 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -306,6 +306,7 @@
                 connectivity = new ConnectivityService(context, networkManagement, networkPolicy);
                 ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
                 networkStats.bindConnectivityManager(connectivity);
+                networkPolicy.bindConnectivityManager(connectivity);
             } catch (Throwable e) {
                 Slog.e(TAG, "Failure starting Connectivity Service", e);
             }
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 86671d6..ec59da6 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -46,6 +46,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.IWindow;
+import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.IAccessibilityInteractionConnection;
@@ -149,9 +150,6 @@
 
             synchronized (mLock) {
                 notifyEventListenerLocked(service, eventType);
-                AccessibilityEvent oldEvent = service.mPendingEvents.get(eventType);
-                service.mPendingEvents.remove(eventType);
-                tryRecycleLocked(oldEvent);
             }
         }
     };
@@ -319,17 +317,14 @@
 
     public boolean sendAccessibilityEvent(AccessibilityEvent event) {
         synchronized (mLock) {
-            mSecurityPolicy.updateRetrievalAllowingWindowAndEventSourceLocked(event);
-            notifyAccessibilityServicesDelayedLocked(event, false);
-            notifyAccessibilityServicesDelayedLocked(event, true);
+            if (mSecurityPolicy.canDispatchAccessibilityEvent(event)) {
+                mSecurityPolicy.updateRetrievalAllowingWindowAndEventSourceLocked(event);
+                notifyAccessibilityServicesDelayedLocked(event, false);
+                notifyAccessibilityServicesDelayedLocked(event, true);
+            }
         }
-        // event not scheduled for dispatch => recycle
-        if (mHandledFeedbackTypes == 0) {
-            event.recycle();
-        } else {
-            mHandledFeedbackTypes = 0;
-        }
-
+        event.recycle();
+        mHandledFeedbackTypes = 0;
         return (OWN_PROCESS_ID != Binder.getCallingPid());
     }
 
@@ -517,46 +512,27 @@
     private void notifyAccessibilityServiceDelayedLocked(Service service,
             AccessibilityEvent event) {
         synchronized (mLock) {
-            int eventType = event.getEventType();
+            final int eventType = event.getEventType();
+            // Make a copy since during dispatch it is possible the event to
+            // be modified to remove its source if the receiving service does
+            // not have permission to access the window content.
+            AccessibilityEvent newEvent = AccessibilityEvent.obtain(event);
             AccessibilityEvent oldEvent = service.mPendingEvents.get(eventType);
-            service.mPendingEvents.put(eventType, event);
+            service.mPendingEvents.put(eventType, newEvent);
 
-            int what = eventType | (service.mId << 16);
+            final int what = eventType | (service.mId << 16);
             if (oldEvent != null) {
                 mHandler.removeMessages(what);
-                tryRecycleLocked(oldEvent);
+                oldEvent.recycle();
             }
 
             Message message = mHandler.obtainMessage(what, service);
-            message.arg1 = event.getEventType();
+            message.arg1 = eventType;
             mHandler.sendMessageDelayed(message, service.mNotificationTimeout);
         }
     }
 
     /**
-     * Recycles an event if it can be safely recycled. The condition is that no
-     * not notified service is interested in the event.
-     *
-     * @param event The event.
-     */
-    private void tryRecycleLocked(AccessibilityEvent event) {
-        if (event == null) {
-            return;
-        }
-        int eventType = event.getEventType();
-        List<Service> services = mServices;
-
-        // linear in the number of service which is not large
-        for (int i = 0, count = services.size(); i < count; i++) {
-            Service service = services.get(i);
-            if (service.mPendingEvents.get(eventType) == event) {
-                return;
-            }
-        }
-        event.recycle();
-    }
-
-    /**
      * Notifies a service for a scheduled event given the event type.
      *
      * @param service The service.
@@ -565,7 +541,7 @@
     private void notifyEventListenerLocked(Service service, int eventType) {
         IEventListener listener = service.mServiceInterface;
         AccessibilityEvent event = service.mPendingEvents.get(eventType);
-
+        service.mPendingEvents.remove(eventType);
         try {
             if (mSecurityPolicy.canRetrieveWindowContent(service)) {
                 event.setConnection(service);
@@ -574,6 +550,7 @@
             }
             event.setSealed(true);
             listener.onAccessibilityEvent(event);
+            event.recycle();
             if (DEBUG) {
                 Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
             }
@@ -926,7 +903,7 @@
             }
         }
 
-        public AccessibilityNodeInfo findAccessibilityNodeInfoByViewId(int viewId) {
+        public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId) {
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
                 final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this);
@@ -961,10 +938,18 @@
             return null;
         }
 
-        public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText(String text) {
+        public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewTextInActiveWindow(
+                String text) {
+            return findAccessibilityNodeInfosByViewText(text,
+                    mSecurityPolicy.mRetrievalAlowingWindowId, View.NO_ID);
+        }
+
+        public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText(String text,
+                int accessibilityWindowId, int accessibilityViewId) {
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
-                final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this);
+                final boolean permissionGranted =
+                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId);
                 if (permissionGranted) {
                     connection = getConnectionToRetrievalAllowingWindowLocked();
                 }
@@ -978,7 +963,8 @@
             final long identityToken = Binder.clearCallingIdentity();
             try {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
-                connection.findAccessibilityNodeInfosByViewText(text, interactionId, mCallback);
+                connection.findAccessibilityNodeInfosByViewText(text, accessibilityViewId,
+                        interactionId, mCallback);
                 List<AccessibilityNodeInfo> infos =
                     mCallback.getFindAccessibilityNodeInfosResultAndClear(interactionId);
                 if (infos != null) {
@@ -1112,16 +1098,23 @@
             | AccessibilityEvent.TYPE_VIEW_CLICKED | AccessibilityEvent.TYPE_VIEW_FOCUSED
             | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
             | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
-            | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
+            | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_VIEW_SELECTED
+            | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
 
         private int mRetrievalAlowingWindowId;
 
+        private boolean canDispatchAccessibilityEvent(AccessibilityEvent event) {
+            // Send window changed event only for the retrieval allowing window.
+            return (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
+                    || event.getWindowId() == mRetrievalAlowingWindowId);
+        }
+
         public void updateRetrievalAllowingWindowAndEventSourceLocked(AccessibilityEvent event) {
-            final int windowId = event.getSourceAccessibilityWindowId();
+            final int windowId = event.getWindowId();
             final int eventType = event.getEventType();
             if ((eventType & RETRIEVAL_ALLOWING_EVENT_TYPES) != 0) {
                 mRetrievalAlowingWindowId = windowId;
-            } else {
+            } else { 
                 event.setSource(null);
             }
         }
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index b754dba..ab85b14 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -126,13 +126,15 @@
 
         // Unpack the config.
         // TODO: move constants into VpnBuilder.
+        int mtu = config.getInt("mtu", -1);
         String session = config.getString("session");
         String addresses = config.getString("addresses");
         String routes = config.getString("routes");
         String dnsServers = config.getString("dnsServers");
 
-        // Create interface and configure addresses and routes.
-        ParcelFileDescriptor descriptor = nativeConfigure(addresses, routes);
+        // Create and configure the interface.
+        ParcelFileDescriptor descriptor =
+                ParcelFileDescriptor.adoptFd(nativeEstablish(mtu, addresses, routes));
 
         // Replace the interface and abort if it fails.
         try {
@@ -250,7 +252,7 @@
         }
     }
 
-    private native ParcelFileDescriptor nativeConfigure(String addresses, String routes);
+    private native int nativeEstablish(int mtu, String addresses, String routes);
     private native String nativeGetName(int fd);
     private native void nativeReset(String name);
     private native int nativeCheck(String name);
diff --git a/services/java/com/android/server/net/NetworkIdentity.java b/services/java/com/android/server/net/NetworkIdentity.java
index f7a7c49..4a207f7 100644
--- a/services/java/com/android/server/net/NetworkIdentity.java
+++ b/services/java/com/android/server/net/NetworkIdentity.java
@@ -26,6 +26,7 @@
 import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G;
+import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN;
 import static android.telephony.TelephonyManager.getNetworkClass;
 
 import android.content.Context;
@@ -148,6 +149,7 @@
         if (isNetworkTypeMobile(type)
                 && Objects.equal(this.subscriberId, subscriberId)) {
             switch (getNetworkClass(subType)) {
+                case NETWORK_CLASS_UNKNOWN:
                 case NETWORK_CLASS_2_G:
                 case NETWORK_CLASS_3_G:
                     return true;
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 1a90a92..e7d60638 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -16,15 +16,26 @@
 
 package com.android.server.net;
 
+import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
 import static android.Manifest.permission.DUMP;
 import static android.Manifest.permission.MANAGE_APP_TOKENS;
-import static android.Manifest.permission.UPDATE_DEVICE_STATS;
+import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
+import static android.Manifest.permission.READ_PHONE_STATE;
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.NetworkPolicy.LIMIT_DISABLED;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_PAID_BACKGROUND;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_PAID;
+import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
 import static android.net.NetworkPolicyManager.dumpPolicy;
 import static android.net.NetworkPolicyManager.dumpRules;
+import static android.net.TrafficStats.TEMPLATE_MOBILE_ALL;
+import static android.net.TrafficStats.isNetworkTemplateMobile;
+import static android.text.format.DateUtils.DAY_IN_MILLIS;
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
 import android.app.IActivityManager;
 import android.app.IProcessObserver;
@@ -33,19 +44,52 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.ConnectivityManager;
+import android.net.IConnectivityManager;
 import android.net.INetworkPolicyListener;
 import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
+import android.net.NetworkPolicy;
+import android.net.NetworkState;
+import android.net.NetworkStats;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IPowerManager;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.telephony.TelephonyManager;
+import android.text.format.Time;
+import android.util.NtpTrustedTime;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
+import android.util.TrustedTime;
+import android.util.Xml;
 
+import com.android.internal.os.AtomicFile;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.Objects;
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
 import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.io.PrintWriter;
+import java.net.ProtocolException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+
+import libcore.io.IoUtils;
 
 /**
  * Service that maintains low-level network policy rules and collects usage
@@ -58,17 +102,45 @@
 public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
     private static final String TAG = "NetworkPolicy";
     private static final boolean LOGD = true;
+    private static final boolean LOGV = false;
+
+    private static final int VERSION_CURRENT = 1;
+
+    private static final long KB_IN_BYTES = 1024;
+    private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
+    private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
+
+    private static final String TAG_POLICY_LIST = "policy-list";
+    private static final String TAG_NETWORK_POLICY = "network-policy";
+    private static final String TAG_UID_POLICY = "uid-policy";
+
+    private static final String ATTR_VERSION = "version";
+    private static final String ATTR_NETWORK_TEMPLATE = "networkTemplate";
+    private static final String ATTR_SUBSCRIBER_ID = "subscriberId";
+    private static final String ATTR_CYCLE_DAY = "cycleDay";
+    private static final String ATTR_WARNING_BYTES = "warningBytes";
+    private static final String ATTR_LIMIT_BYTES = "limitBytes";
+    private static final String ATTR_UID = "uid";
+    private static final String ATTR_POLICY = "policy";
+
+    private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
 
     private final Context mContext;
     private final IActivityManager mActivityManager;
     private final IPowerManager mPowerManager;
     private final INetworkStatsService mNetworkStats;
+    private final TrustedTime mTime;
+
+    private IConnectivityManager mConnManager;
 
     private final Object mRulesLock = new Object();
 
     private boolean mScreenOn;
 
-    /** Current network policy for each UID. */
+    /** Current policy for network templates. */
+    private ArrayList<NetworkPolicy> mNetworkPolicy = Lists.newArrayList();
+
+    /** Current policy for each UID. */
     private SparseIntArray mUidPolicy = new SparseIntArray();
     /** Current derived network rules for each UID. */
     private SparseIntArray mUidRules = new SparseIntArray();
@@ -81,26 +153,50 @@
     private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<
             INetworkPolicyListener>();
 
-    // TODO: save/restore policy information from disk
+    private final HandlerThread mHandlerThread;
+    private final Handler mHandler;
+
+    private final AtomicFile mPolicyFile;
 
     // TODO: keep whitelist of system-critical services that should never have
     // rules enforced, such as system, phone, and radio UIDs.
 
-    // TODO: keep record of billing cycle details, and limit rules
-    // TODO: keep map of interfaces-to-billing-relationship
-
-    // TODO: dispatch callbacks through handler when locked
-
     public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
             IPowerManager powerManager, INetworkStatsService networkStats) {
+        // TODO: move to using cached NtpTrustedTime
+        this(context, activityManager, powerManager, networkStats, new NtpTrustedTime(),
+                getSystemDir());
+    }
+
+    private static File getSystemDir() {
+        return new File(Environment.getDataDirectory(), "system");
+    }
+
+    public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
+            IPowerManager powerManager, INetworkStatsService networkStats, TrustedTime time,
+            File systemDir) {
         mContext = checkNotNull(context, "missing context");
         mActivityManager = checkNotNull(activityManager, "missing activityManager");
         mPowerManager = checkNotNull(powerManager, "missing powerManager");
         mNetworkStats = checkNotNull(networkStats, "missing networkStats");
+        mTime = checkNotNull(time, "missing TrustedTime");
+
+        mHandlerThread = new HandlerThread(TAG);
+        mHandlerThread.start();
+        mHandler = new Handler(mHandlerThread.getLooper());
+
+        mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"));
+    }
+
+    public void bindConnectivityManager(IConnectivityManager connManager) {
+        mConnManager = checkNotNull(connManager, "missing IConnectivityManager");
     }
 
     public void systemReady() {
-        // TODO: read current policy from disk
+        synchronized (mRulesLock) {
+            // read policy from disk
+            readPolicyLocked();
+        }
 
         updateScreenOn();
 
@@ -120,6 +216,11 @@
         screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
         mContext.registerReceiver(mScreenReceiver, screenFilter);
 
+        // watch for network interfaces to be claimed
+        final IntentFilter ifaceFilter = new IntentFilter();
+        ifaceFilter.addAction(CONNECTIVITY_ACTION);
+        mContext.registerReceiver(mIfaceReceiver, ifaceFilter, CONNECTIVITY_INTERNAL, mHandler);
+
     }
 
     private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
@@ -139,7 +240,7 @@
                     mUidPidForeground.put(uid, pidForeground);
                 }
                 pidForeground.put(pid, foregroundActivities);
-                computeUidForegroundL(uid);
+                computeUidForegroundLocked(uid);
             }
         }
 
@@ -153,7 +254,7 @@
                 final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
                 if (pidForeground != null) {
                     pidForeground.delete(pid);
-                    computeUidForegroundL(uid);
+                    computeUidForegroundLocked(uid);
                 }
             }
         }
@@ -170,23 +271,269 @@
         }
     };
 
+    /**
+     * Receiver that watches for {@link IConnectivityManager} to claim network
+     * interfaces. Used to apply {@link NetworkPolicy} to matching networks.
+     */
+    private BroadcastReceiver mIfaceReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // on background handler thread, and verified CONNECTIVITY_INTERNAL
+            // permission above.
+            synchronized (mRulesLock) {
+                ensureActiveMobilePolicyLocked();
+                updateIfacesLocked();
+            }
+        }
+    };
+
+    /**
+     * Examine all connected {@link NetworkState}, looking for
+     * {@link NetworkPolicy} that need to be enforced. When matches found, set
+     * remaining quota based on usage cycle and historical stats.
+     */
+    private void updateIfacesLocked() {
+        if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
+
+        final NetworkState[] states;
+        try {
+            states = mConnManager.getAllNetworkState();
+        } catch (RemoteException e) {
+            Slog.w(TAG, "problem reading network state");
+            return;
+        }
+
+        // first, derive identity for all connected networks, which can be used
+        // to match against templates.
+        final HashMap<NetworkIdentity, String> networks = Maps.newHashMap();
+        for (NetworkState state : states) {
+            // stash identity and iface away for later use
+            if (state.networkInfo.isConnected()) {
+                final String iface = state.linkProperties.getInterfaceName();
+                final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
+                networks.put(ident, iface);
+            }
+        }
+
+        // build list of rules and ifaces to enforce them against
+        final HashMap<NetworkPolicy, String[]> rules = Maps.newHashMap();
+        final ArrayList<String> ifaceList = Lists.newArrayList();
+        for (NetworkPolicy policy : mNetworkPolicy) {
+
+            // collect all active ifaces that match this template
+            ifaceList.clear();
+            for (NetworkIdentity ident : networks.keySet()) {
+                if (ident.matchesTemplate(policy.networkTemplate, policy.subscriberId)) {
+                    final String iface = networks.get(ident);
+                    ifaceList.add(iface);
+                }
+            }
+
+            if (ifaceList.size() > 0) {
+                final String[] ifaces = ifaceList.toArray(new String[ifaceList.size()]);
+                rules.put(policy, ifaces);
+            }
+        }
+
+        // try refreshing time source when stale
+        if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) {
+            mTime.forceRefresh();
+        }
+
+        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
+                : System.currentTimeMillis();
+
+        // apply each policy that we found ifaces for; compute remaining data
+        // based on current cycle and historical stats, and push to kernel.
+        for (NetworkPolicy policy : rules.keySet()) {
+            final String[] ifaces = rules.get(policy);
+
+            final long start = computeLastCycleBoundary(currentTime, policy);
+            final long end = currentTime;
+
+            final NetworkStats stats;
+            final long total;
+            try {
+                stats = mNetworkStats.getSummaryForNetwork(
+                        start, end, policy.networkTemplate, policy.subscriberId);
+                total = stats.rx[0] + stats.tx[0];
+            } catch (RemoteException e) {
+                Slog.w(TAG, "problem reading summary for template " + policy.networkTemplate);
+                continue;
+            }
+
+            if (LOGD) {
+                Slog.d(TAG, "applying policy " + policy.toString() + " to ifaces "
+                        + Arrays.toString(ifaces));
+            }
+
+            // TODO: register for warning notification trigger through NMS
+
+            if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) {
+                // remaining "quota" is based on usage in current cycle
+                final long quota = Math.max(0, policy.limitBytes - total);
+
+                // TODO: push quota rule down through NMS
+            }
+        }
+    }
+
+    /**
+     * Once any {@link #mNetworkPolicy} are loaded from disk, ensure that we
+     * have at least a default mobile policy defined.
+     */
+    private void ensureActiveMobilePolicyLocked() {
+        if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyLocked()");
+        final String subscriberId = getActiveSubscriberId();
+        if (subscriberId == null) {
+            if (LOGV) Slog.v(TAG, "no active mobile network, ignoring policy check");
+            return;
+        }
+
+        // examine to see if any policy is defined for active mobile
+        boolean mobileDefined = false;
+        for (NetworkPolicy policy : mNetworkPolicy) {
+            if (isNetworkTemplateMobile(policy.networkTemplate)
+                    && Objects.equal(subscriberId, policy.subscriberId)) {
+                mobileDefined = true;
+            }
+        }
+
+        if (!mobileDefined) {
+            Slog.i(TAG, "no policy for active mobile network; generating default policy");
+
+            // default mobile policy has combined 4GB warning, and assume usage
+            // cycle starts today today.
+
+            // TODO: move this policy definition to overlay or secure setting
+            final Time time = new Time(Time.TIMEZONE_UTC);
+            time.setToNow();
+            final int cycleDay = time.monthDay;
+
+            mNetworkPolicy.add(new NetworkPolicy(
+                    TEMPLATE_MOBILE_ALL, subscriberId, cycleDay, 4 * GB_IN_BYTES, LIMIT_DISABLED));
+        }
+    }
+
+    private void readPolicyLocked() {
+        if (LOGV) Slog.v(TAG, "readPolicyLocked()");
+
+        // clear any existing policy and read from disk
+        mNetworkPolicy.clear();
+        mUidPolicy.clear();
+
+        FileInputStream fis = null;
+        try {
+            fis = mPolicyFile.openRead();
+            final XmlPullParser in = Xml.newPullParser();
+            in.setInput(fis, null);
+
+            int type;
+            int version = VERSION_CURRENT;
+            while ((type = in.next()) != END_DOCUMENT) {
+                final String tag = in.getName();
+                if (type == START_TAG) {
+                    if (TAG_POLICY_LIST.equals(tag)) {
+                        version = readIntAttribute(in, ATTR_VERSION);
+
+                    } else if (TAG_NETWORK_POLICY.equals(tag)) {
+                        final int networkTemplate = readIntAttribute(in, ATTR_NETWORK_TEMPLATE);
+                        final String subscriberId = in.getAttributeValue(null, ATTR_SUBSCRIBER_ID);
+                        final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY);
+                        final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES);
+                        final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES);
+
+                        mNetworkPolicy.add(new NetworkPolicy(
+                                networkTemplate, subscriberId, cycleDay, warningBytes, limitBytes));
+
+                    } else if (TAG_UID_POLICY.equals(tag)) {
+                        final int uid = readIntAttribute(in, ATTR_UID);
+                        final int policy = readIntAttribute(in, ATTR_POLICY);
+
+                        mUidPolicy.put(uid, policy);
+                    }
+                }
+            }
+
+        } catch (FileNotFoundException e) {
+            // missing policy is okay, probably first boot
+        } catch (IOException e) {
+            Slog.e(TAG, "problem reading network stats", e);
+        } catch (XmlPullParserException e) {
+            Slog.e(TAG, "problem reading network stats", e);
+        } finally {
+            IoUtils.closeQuietly(fis);
+        }
+    }
+
+    private void writePolicyLocked() {
+        if (LOGV) Slog.v(TAG, "writePolicyLocked()");
+
+        FileOutputStream fos = null;
+        try {
+            fos = mPolicyFile.startWrite();
+
+            XmlSerializer out = new FastXmlSerializer();
+            out.setOutput(fos, "utf-8");
+            out.startDocument(null, true);
+
+            out.startTag(null, TAG_POLICY_LIST);
+            writeIntAttribute(out, ATTR_VERSION, VERSION_CURRENT);
+
+            // write all known network policies
+            for (NetworkPolicy policy : mNetworkPolicy) {
+                out.startTag(null, TAG_NETWORK_POLICY);
+                writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, policy.networkTemplate);
+                if (policy.subscriberId != null) {
+                    out.attribute(null, ATTR_SUBSCRIBER_ID, policy.subscriberId);
+                }
+                writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay);
+                writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes);
+                writeLongAttribute(out, ATTR_LIMIT_BYTES, policy.limitBytes);
+                out.endTag(null, TAG_NETWORK_POLICY);
+            }
+
+            // write all known uid policies
+            for (int i = 0; i < mUidPolicy.size(); i++) {
+                final int uid = mUidPolicy.keyAt(i);
+                final int policy = mUidPolicy.valueAt(i);
+
+                out.startTag(null, TAG_UID_POLICY);
+                writeIntAttribute(out, ATTR_UID, uid);
+                writeIntAttribute(out, ATTR_POLICY, policy);
+                out.endTag(null, TAG_UID_POLICY);
+            }
+
+            out.endTag(null, TAG_POLICY_LIST);
+            out.endDocument();
+
+            mPolicyFile.finishWrite(fos);
+        } catch (IOException e) {
+            if (fos != null) {
+                mPolicyFile.failWrite(fos);
+            }
+        }
+    }
+
     @Override
     public void setUidPolicy(int uid, int policy) {
-        // TODO: create permission for modifying data policy
-        mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG);
+        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
 
         final int oldPolicy;
         synchronized (mRulesLock) {
             oldPolicy = getUidPolicy(uid);
             mUidPolicy.put(uid, policy);
-            updateRulesForUidL(uid);
-        }
 
-        // TODO: consider dispatching BACKGROUND_DATA_SETTING broadcast
+            // uid policy changed, recompute rules and persist policy.
+            updateRulesForUidLocked(uid);
+            writePolicyLocked();
+        }
     }
 
     @Override
     public int getUidPolicy(int uid) {
+        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
         synchronized (mRulesLock) {
             return mUidPolicy.get(uid, POLICY_NONE);
         }
@@ -218,10 +565,40 @@
     }
 
     @Override
+    public void setNetworkPolicies(NetworkPolicy[] policies) {
+        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+        synchronized (mRulesLock) {
+            mNetworkPolicy.clear();
+            for (NetworkPolicy policy : policies) {
+                mNetworkPolicy.add(policy);
+            }
+
+            updateIfacesLocked();
+            writePolicyLocked();
+        }
+    }
+
+    @Override
+    public NetworkPolicy[] getNetworkPolicies() {
+        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+        mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG);
+
+        synchronized (mRulesLock) {
+            return mNetworkPolicy.toArray(new NetworkPolicy[mNetworkPolicy.size()]);
+        }
+    }
+
+    @Override
     protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
         mContext.enforceCallingOrSelfPermission(DUMP, TAG);
 
         synchronized (mRulesLock) {
+            fout.println("Network policies:");
+            for (NetworkPolicy policy : mNetworkPolicy) {
+                fout.print("  "); fout.println(policy.toString());
+            }
+
             fout.println("Policy status for known UIDs:");
 
             final SparseBooleanArray knownUids = new SparseBooleanArray();
@@ -274,9 +651,9 @@
 
     /**
      * Foreground for PID changed; recompute foreground at UID level. If
-     * changed, will trigger {@link #updateRulesForUidL(int)}.
+     * changed, will trigger {@link #updateRulesForUidLocked(int)}.
      */
-    private void computeUidForegroundL(int uid) {
+    private void computeUidForegroundLocked(int uid) {
         final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
 
         // current pid is dropping foreground; examine other pids
@@ -293,7 +670,7 @@
         if (oldUidForeground != uidForeground) {
             // foreground changed, push updated rules
             mUidForeground.put(uid, uidForeground);
-            updateRulesForUidL(uid);
+            updateRulesForUidLocked(uid);
         }
     }
 
@@ -303,25 +680,25 @@
                 mScreenOn = mPowerManager.isScreenOn();
             } catch (RemoteException e) {
             }
-            updateRulesForScreenL();
+            updateRulesForScreenLocked();
         }
     }
 
     /**
      * Update rules that might be changed by {@link #mScreenOn} value.
      */
-    private void updateRulesForScreenL() {
+    private void updateRulesForScreenLocked() {
         // only update rules for anyone with foreground activities
         final int size = mUidForeground.size();
         for (int i = 0; i < size; i++) {
             if (mUidForeground.valueAt(i)) {
                 final int uid = mUidForeground.keyAt(i);
-                updateRulesForUidL(uid);
+                updateRulesForUidLocked(uid);
             }
         }
     }
 
-    private void updateRulesForUidL(int uid) {
+    private void updateRulesForUidLocked(int uid) {
         final int uidPolicy = getUidPolicy(uid);
         final boolean uidForeground = isUidForeground(uid);
 
@@ -351,11 +728,10 @@
         mListeners.finishBroadcast();
     }
 
-    private static <T> T checkNotNull(T value, String message) {
-        if (value == null) {
-            throw new NullPointerException(message);
-        }
-        return value;
+    private String getActiveSubscriberId() {
+        final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService(
+                Context.TELEPHONY_SERVICE);
+        return telephony.getSubscriberId();
     }
 
     private static void collectKeys(SparseIntArray source, SparseBooleanArray target) {
@@ -381,4 +757,33 @@
         }
         fout.print("]");
     }
+
+    private static int readIntAttribute(XmlPullParser in, String name) throws IOException {
+        final String value = in.getAttributeValue(null, name);
+        try {
+            return Integer.parseInt(value);
+        } catch (NumberFormatException e) {
+            throw new ProtocolException("problem parsing " + name + "=" + value + " as int");
+        }
+    }
+
+    private static long readLongAttribute(XmlPullParser in, String name) throws IOException {
+        final String value = in.getAttributeValue(null, name);
+        try {
+            return Long.parseLong(value);
+        } catch (NumberFormatException e) {
+            throw new ProtocolException("problem parsing " + name + "=" + value + " as int");
+        }
+    }
+
+    private static void writeIntAttribute(XmlSerializer out, String name, int value)
+            throws IOException {
+        out.attribute(null, name, Integer.toString(value));
+    }
+
+    private static void writeLongAttribute(XmlSerializer out, String name, long value)
+            throws IOException {
+        out.attribute(null, name, Long.toString(value));
+    }
+
 }
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 8db2839..de69849 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -18,17 +18,17 @@
 
 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
 import static android.Manifest.permission.DUMP;
+import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
 import static android.Manifest.permission.SHUTDOWN;
-import static android.Manifest.permission.UPDATE_DEVICE_STATS;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.NetworkStats.IFACE_ALL;
 import static android.net.NetworkStats.UID_ALL;
-import static android.provider.Settings.Secure.NETSTATS_DETAIL_BUCKET_DURATION;
-import static android.provider.Settings.Secure.NETSTATS_DETAIL_MAX_HISTORY;
+import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION;
+import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY;
 import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD;
 import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL;
-import static android.provider.Settings.Secure.NETSTATS_SUMMARY_BUCKET_DURATION;
-import static android.provider.Settings.Secure.NETSTATS_SUMMARY_MAX_HISTORY;
+import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION;
+import static android.provider.Settings.Secure.NETSTATS_UID_MAX_HISTORY;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
@@ -38,6 +38,7 @@
 import android.app.IAlarmManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -86,8 +87,9 @@
  * other system services.
  */
 public class NetworkStatsService extends INetworkStatsService.Stub {
-    private static final String TAG = "NetworkStatsService";
+    private static final String TAG = "NetworkStats";
     private static final boolean LOGD = true;
+    private static final boolean LOGV = false;
 
     /** File header magic number: "ANET" */
     private static final int FILE_MAGIC = 0x414E4554;
@@ -97,6 +99,7 @@
     private final INetworkManagementService mNetworkManager;
     private final IAlarmManager mAlarmManager;
     private final TrustedTime mTime;
+    private final NetworkStatsSettings mSettings;
 
     private IConnectivityManager mConnManager;
 
@@ -112,22 +115,18 @@
     private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES;
     private static final long GB_IN_BYTES = 1024 * MB_IN_BYTES;
 
-    private LongSecureSetting mPollInterval = new LongSecureSetting(
-            NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS);
-    private LongSecureSetting mPersistThreshold = new LongSecureSetting(
-            NETSTATS_PERSIST_THRESHOLD, 16 * KB_IN_BYTES);
-
-    // TODO: adjust these timings for production builds
-    private LongSecureSetting mSummaryBucketDuration = new LongSecureSetting(
-            NETSTATS_SUMMARY_BUCKET_DURATION, 1 * HOUR_IN_MILLIS);
-    private LongSecureSetting mSummaryMaxHistory = new LongSecureSetting(
-            NETSTATS_SUMMARY_MAX_HISTORY, 90 * DAY_IN_MILLIS);
-    private LongSecureSetting mDetailBucketDuration = new LongSecureSetting(
-            NETSTATS_DETAIL_BUCKET_DURATION, 2 * HOUR_IN_MILLIS);
-    private LongSecureSetting mDetailMaxHistory = new LongSecureSetting(
-            NETSTATS_DETAIL_MAX_HISTORY, 90 * DAY_IN_MILLIS);
-
-    private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
+    /**
+     * Settings that can be changed externally.
+     */
+    public interface NetworkStatsSettings {
+        public long getPollInterval();
+        public long getPersistThreshold();
+        public long getNetworkBucketDuration();
+        public long getNetworkMaxHistory();
+        public long getUidBucketDuration();
+        public long getUidMaxHistory();
+        public long getTimeCacheMaxAge();
+    }
 
     private final Object mStatsLock = new Object();
 
@@ -135,19 +134,23 @@
     private HashMap<String, InterfaceIdentity> mActiveIface = Maps.newHashMap();
 
     /** Set of historical stats for known ifaces. */
-    private HashMap<InterfaceIdentity, NetworkStatsHistory> mSummaryStats = Maps.newHashMap();
+    private HashMap<InterfaceIdentity, NetworkStatsHistory> mNetworkStats = Maps.newHashMap();
     /** Set of historical stats for known UIDs. */
-    private SparseArray<NetworkStatsHistory> mDetailStats = new SparseArray<NetworkStatsHistory>();
+    private SparseArray<NetworkStatsHistory> mUidStats = new SparseArray<NetworkStatsHistory>();
 
-    private NetworkStats mLastSummaryPoll;
-    private NetworkStats mLastSummaryPersist;
+    /** Flag if {@link #mUidStats} have been loaded from disk. */
+    private boolean mUidStatsLoaded = false;
 
-    private NetworkStats mLastDetailPoll;
+    private NetworkStats mLastNetworkPoll;
+    private NetworkStats mLastNetworkPersist;
+
+    private NetworkStats mLastUidPoll;
 
     private final HandlerThread mHandlerThread;
     private final Handler mHandler;
 
-    private final AtomicFile mSummaryFile;
+    private final AtomicFile mNetworkFile;
+    private final AtomicFile mUidFile;
 
     // TODO: collect detailed uid stats, storing tag-granularity data until next
     // dropbox, and uid summary for a specific bucket count.
@@ -157,7 +160,8 @@
     public NetworkStatsService(
             Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) {
         // TODO: move to using cached NtpTrustedTime
-        this(context, networkManager, alarmManager, new NtpTrustedTime(), getSystemDir());
+        this(context, networkManager, alarmManager, new NtpTrustedTime(), getSystemDir(),
+                new DefaultNetworkStatsSettings(context));
     }
 
     private static File getSystemDir() {
@@ -165,33 +169,43 @@
     }
 
     public NetworkStatsService(Context context, INetworkManagementService networkManager,
-            IAlarmManager alarmManager, TrustedTime time, File systemDir) {
+            IAlarmManager alarmManager, TrustedTime time, File systemDir,
+            NetworkStatsSettings settings) {
         mContext = checkNotNull(context, "missing Context");
         mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService");
         mAlarmManager = checkNotNull(alarmManager, "missing IAlarmManager");
         mTime = checkNotNull(time, "missing TrustedTime");
+        mSettings = checkNotNull(settings, "missing NetworkStatsSettings");
 
         mHandlerThread = new HandlerThread(TAG);
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
 
-        mSummaryFile = new AtomicFile(new File(systemDir, "netstats.bin"));
+        mNetworkFile = new AtomicFile(new File(systemDir, "netstats.bin"));
+        mUidFile = new AtomicFile(new File(systemDir, "netstats_uid.bin"));
+    }
+
+    public void bindConnectivityManager(IConnectivityManager connManager) {
+        mConnManager = checkNotNull(connManager, "missing IConnectivityManager");
     }
 
     public void systemReady() {
         synchronized (mStatsLock) {
-            // read historical stats from disk
-            readStatsLocked();
+            // read historical network stats from disk, since policy service
+            // might need them right away. we delay loading detailed UID stats
+            // until actually needed.
+            readNetworkStatsLocked();
         }
 
-        // watch other system services that claim interfaces
+        // watch for network interfaces to be claimed
         final IntentFilter ifaceFilter = new IntentFilter();
         ifaceFilter.addAction(CONNECTIVITY_ACTION);
         mContext.registerReceiver(mIfaceReceiver, ifaceFilter, CONNECTIVITY_INTERNAL, mHandler);
 
         // listen for periodic polling events
+        // TODO: switch to stronger internal permission
         final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL);
-        mContext.registerReceiver(mPollReceiver, pollFilter, UPDATE_DEVICE_STATS, mHandler);
+        mContext.registerReceiver(mPollReceiver, pollFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
 
         // persist stats during clean shutdown
         final IntentFilter shutdownFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
@@ -204,23 +218,21 @@
         }
     }
 
-    public void bindConnectivityManager(IConnectivityManager connManager) {
-        mConnManager = checkNotNull(connManager, "missing IConnectivityManager");
-    }
-
     private void shutdownLocked() {
         mContext.unregisterReceiver(mIfaceReceiver);
         mContext.unregisterReceiver(mPollReceiver);
         mContext.unregisterReceiver(mShutdownReceiver);
 
-        writeStatsLocked();
-        mSummaryStats.clear();
-        mDetailStats.clear();
+        writeNetworkStatsLocked();
+        writeUidStatsLocked();
+        mNetworkStats.clear();
+        mUidStats.clear();
+        mUidStatsLoaded = false;
     }
 
     /**
      * Clear any existing {@link #ACTION_NETWORK_STATS_POLL} alarms, and
-     * reschedule based on current {@link #mPollInterval} value.
+     * reschedule based on current {@link NetworkStatsSettings#getPollInterval()}.
      */
     private void registerPollAlarmLocked() throws RemoteException {
         if (mPollIntent != null) {
@@ -231,22 +243,21 @@
                 mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0);
 
         final long currentRealtime = SystemClock.elapsedRealtime();
-        mAlarmManager.setInexactRepeating(
-                AlarmManager.ELAPSED_REALTIME, currentRealtime, mPollInterval.get(), mPollIntent);
+        mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime,
+                mSettings.getPollInterval(), mPollIntent);
     }
 
     @Override
     public NetworkStatsHistory getHistoryForNetwork(int networkTemplate) {
-        // TODO: create relaxed permission for reading stats
-        mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG);
+        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
 
         synchronized (mStatsLock) {
             // combine all interfaces that match template
             final String subscriberId = getActiveSubscriberId();
             final NetworkStatsHistory combined = new NetworkStatsHistory(
-                    mSummaryBucketDuration.get());
-            for (InterfaceIdentity ident : mSummaryStats.keySet()) {
-                final NetworkStatsHistory history = mSummaryStats.get(ident);
+                    mSettings.getNetworkBucketDuration(), estimateNetworkBuckets());
+            for (InterfaceIdentity ident : mNetworkStats.keySet()) {
+                final NetworkStatsHistory history = mNetworkStats.get(ident);
                 if (ident.matchesTemplate(networkTemplate, subscriberId)) {
                     combined.recordEntireHistory(history);
                 }
@@ -257,32 +268,61 @@
 
     @Override
     public NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate) {
-        // TODO: create relaxed permission for reading stats
-        mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG);
+        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
 
-        // TODO: return history for requested uid
-        return null;
+        synchronized (mStatsLock) {
+            // TODO: combine based on template, if we store that granularity
+            ensureUidStatsLoadedLocked();
+            return mUidStats.get(uid);
+        }
+    }
+
+    @Override
+    public NetworkStats getSummaryForNetwork(
+            long start, long end, int networkTemplate, String subscriberId) {
+        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+
+        synchronized (mStatsLock) {
+            long rx = 0;
+            long tx = 0;
+            long[] networkTotal = new long[2];
+
+            // combine total from all interfaces that match template
+            for (InterfaceIdentity ident : mNetworkStats.keySet()) {
+                final NetworkStatsHistory history = mNetworkStats.get(ident);
+                if (ident.matchesTemplate(networkTemplate, subscriberId)) {
+                    networkTotal = history.getTotalData(start, end, networkTotal);
+                    rx += networkTotal[0];
+                    tx += networkTotal[1];
+                }
+            }
+
+            final NetworkStats stats = new NetworkStats(end - start, 1);
+            stats.addEntry(IFACE_ALL, UID_ALL, tx, tx);
+            return stats;
+        }
     }
 
     @Override
     public NetworkStats getSummaryForAllUid(long start, long end, int networkTemplate) {
-        // TODO: create relaxed permission for reading stats
-        mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG);
+        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
 
         // TODO: apply networktemplate once granular uid stats are stored.
 
         synchronized (mStatsLock) {
-            final int size = mDetailStats.size();
-            final NetworkStats.Builder stats = new NetworkStats.Builder(end - start, size);
+            ensureUidStatsLoadedLocked();
 
-            final long[] total = new long[2];
+            final int size = mUidStats.size();
+            final NetworkStats stats = new NetworkStats(end - start, size);
+
+            long[] total = new long[2];
             for (int i = 0; i < size; i++) {
-                final int uid = mDetailStats.keyAt(i);
-                final NetworkStatsHistory history = mDetailStats.valueAt(i);
-                history.getTotalData(start, end, total);
+                final int uid = mUidStats.keyAt(i);
+                final NetworkStatsHistory history = mUidStats.valueAt(i);
+                total = history.getTotalData(start, end, total);
                 stats.addEntry(IFACE_ALL, uid, total[0], total[1]);
             }
-            return stats.build();
+            return stats;
         }
     }
 
@@ -309,7 +349,7 @@
             // permission above.
             synchronized (mStatsLock) {
                 // TODO: acquire wakelock while performing poll
-                performPollLocked();
+                performPollLocked(true);
             }
         }
     };
@@ -331,13 +371,12 @@
      * {@link InterfaceIdentity}.
      */
     private void updateIfacesLocked() {
-        if (LOGD) Slog.v(TAG, "updateIfacesLocked()");
+        if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
 
         // take one last stats snapshot before updating iface mapping. this
         // isn't perfect, since the kernel may already be counting traffic from
         // the updated network.
-        // TODO: verify that we only poll summary stats, not uid details
-        performPollLocked();
+        performPollLocked(false);
 
         final NetworkState[] states;
         try {
@@ -360,11 +399,18 @@
         }
     }
 
-    private void performPollLocked() {
-        if (LOGD) Slog.v(TAG, "performPollLocked()");
+    /**
+     * Periodic poll operation, reading current statistics and recording into
+     * {@link NetworkStatsHistory}.
+     *
+     * @param detailedPoll Indicate if detailed UID stats should be collected
+     *            during this poll operation.
+     */
+    private void performPollLocked(boolean detailedPoll) {
+        if (LOGV) Slog.v(TAG, "performPollLocked()");
 
         // try refreshing time source when stale
-        if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) {
+        if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) {
             mTime.forceRefresh();
         }
 
@@ -372,42 +418,45 @@
         final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
                 : System.currentTimeMillis();
 
-        final NetworkStats summary;
-        final NetworkStats detail;
+        final NetworkStats networkStats;
+        final NetworkStats uidStats;
         try {
-            summary = mNetworkManager.getNetworkStatsSummary();
-            detail = mNetworkManager.getNetworkStatsDetail();
+            networkStats = mNetworkManager.getNetworkStatsSummary();
+            uidStats = detailedPoll ? mNetworkManager.getNetworkStatsDetail() : null;
         } catch (RemoteException e) {
             Slog.w(TAG, "problem reading network stats");
             return;
         }
 
-        performSummaryPollLocked(summary, currentTime);
-        performDetailPollLocked(detail, currentTime);
+        performNetworkPollLocked(networkStats, currentTime);
+        if (detailedPoll) {
+            performUidPollLocked(uidStats, currentTime);
+        }
 
         // decide if enough has changed to trigger persist
-        final NetworkStats persistDelta = computeStatsDelta(mLastSummaryPersist, summary);
-        final long persistThreshold = mPersistThreshold.get();
+        final NetworkStats persistDelta = computeStatsDelta(mLastNetworkPersist, networkStats);
+        final long persistThreshold = mSettings.getPersistThreshold();
         for (String iface : persistDelta.getUniqueIfaces()) {
             final int index = persistDelta.findIndex(iface, UID_ALL);
             if (persistDelta.rx[index] > persistThreshold
                     || persistDelta.tx[index] > persistThreshold) {
-                writeStatsLocked();
-                mLastSummaryPersist = summary;
+                writeNetworkStatsLocked();
+                writeUidStatsLocked();
+                mLastNetworkPersist = networkStats;
                 break;
             }
         }
     }
 
     /**
-     * Update {@link #mSummaryStats} historical usage.
+     * Update {@link #mNetworkStats} historical usage.
      */
-    private void performSummaryPollLocked(NetworkStats summary, long currentTime) {
+    private void performNetworkPollLocked(NetworkStats networkStats, long currentTime) {
         final ArrayList<String> unknownIface = Lists.newArrayList();
 
-        final NetworkStats delta = computeStatsDelta(mLastSummaryPoll, summary);
+        final NetworkStats delta = computeStatsDelta(mLastNetworkPoll, networkStats);
         final long timeStart = currentTime - delta.elapsedRealtime;
-        final long maxHistory = mSummaryMaxHistory.get();
+        final long maxHistory = mSettings.getNetworkMaxHistory();
         for (String iface : delta.getUniqueIfaces()) {
             final InterfaceIdentity ident = mActiveIface.get(iface);
             if (ident == null) {
@@ -419,11 +468,11 @@
             final long rx = delta.rx[index];
             final long tx = delta.tx[index];
 
-            final NetworkStatsHistory history = findOrCreateSummaryLocked(ident);
+            final NetworkStatsHistory history = findOrCreateNetworkLocked(ident);
             history.recordData(timeStart, currentTime, rx, tx);
             history.removeBucketsBefore(currentTime - maxHistory);
         }
-        mLastSummaryPoll = summary;
+        mLastNetworkPoll = networkStats;
 
         if (LOGD && unknownIface.size() > 0) {
             Slog.w(TAG, "unknown interfaces " + unknownIface.toString() + ", ignoring those stats");
@@ -431,40 +480,71 @@
     }
 
     /**
-     * Update {@link #mDetailStats} historical usage.
+     * Update {@link #mUidStats} historical usage.
      */
-    private void performDetailPollLocked(NetworkStats detail, long currentTime) {
-        final NetworkStats delta = computeStatsDelta(mLastDetailPoll, detail);
+    private void performUidPollLocked(NetworkStats uidStats, long currentTime) {
+        ensureUidStatsLoadedLocked();
+
+        final NetworkStats delta = computeStatsDelta(mLastUidPoll, uidStats);
         final long timeStart = currentTime - delta.elapsedRealtime;
-        final long maxHistory = mDetailMaxHistory.get();
+        final long maxHistory = mSettings.getUidMaxHistory();
         for (int uid : delta.getUniqueUids()) {
+            // TODO: traverse all ifaces once surfaced in stats
             final int index = delta.findIndex(IFACE_ALL, uid);
-            final long rx = delta.rx[index];
-            final long tx = delta.tx[index];
+            if (index != -1) {
+                final long rx = delta.rx[index];
+                final long tx = delta.tx[index];
 
-            final NetworkStatsHistory history = findOrCreateDetailLocked(uid);
-            history.recordData(timeStart, currentTime, rx, tx);
-            history.removeBucketsBefore(currentTime - maxHistory);
+                final NetworkStatsHistory history = findOrCreateUidLocked(uid);
+                history.recordData(timeStart, currentTime, rx, tx);
+                history.removeBucketsBefore(currentTime - maxHistory);
+            }
         }
-        mLastDetailPoll = detail;
+        mLastUidPoll = uidStats;
     }
 
-    private NetworkStatsHistory findOrCreateSummaryLocked(InterfaceIdentity ident) {
-        NetworkStatsHistory stats = mSummaryStats.get(ident);
-        if (stats == null) {
-            stats = new NetworkStatsHistory(mSummaryBucketDuration.get());
-            mSummaryStats.put(ident, stats);
+    private NetworkStatsHistory findOrCreateNetworkLocked(InterfaceIdentity ident) {
+        final long bucketDuration = mSettings.getNetworkBucketDuration();
+        final NetworkStatsHistory existing = mNetworkStats.get(ident);
+
+        // update when no existing, or when bucket duration changed
+        NetworkStatsHistory updated = null;
+        if (existing == null) {
+            updated = new NetworkStatsHistory(bucketDuration, 10);
+        } else if (existing.bucketDuration != bucketDuration) {
+            updated = new NetworkStatsHistory(
+                    bucketDuration, estimateResizeBuckets(existing, bucketDuration));
+            updated.recordEntireHistory(existing);
         }
-        return stats;
+
+        if (updated != null) {
+            mNetworkStats.put(ident, updated);
+            return updated;
+        } else {
+            return existing;
+        }
     }
 
-    private NetworkStatsHistory findOrCreateDetailLocked(int uid) {
-        NetworkStatsHistory stats = mDetailStats.get(uid);
-        if (stats == null) {
-            stats = new NetworkStatsHistory(mDetailBucketDuration.get());
-            mDetailStats.put(uid, stats);
+    private NetworkStatsHistory findOrCreateUidLocked(int uid) {
+        final long bucketDuration = mSettings.getUidBucketDuration();
+        final NetworkStatsHistory existing = mUidStats.get(uid);
+
+        // update when no existing, or when bucket duration changed
+        NetworkStatsHistory updated = null;
+        if (existing == null) {
+            updated = new NetworkStatsHistory(bucketDuration, 10);
+        } else if (existing.bucketDuration != bucketDuration) {
+            updated = new NetworkStatsHistory(
+                    bucketDuration, estimateResizeBuckets(existing, bucketDuration));
+            updated.recordEntireHistory(existing);
         }
-        return stats;
+
+        if (updated != null) {
+            mUidStats.put(uid, updated);
+            return updated;
+        } else {
+            return existing;
+        }
     }
 
     private InterfaceIdentity findOrCreateInterfaceLocked(String iface) {
@@ -476,15 +556,15 @@
         return ident;
     }
 
-    private void readStatsLocked() {
-        if (LOGD) Slog.v(TAG, "readStatsLocked()");
+    private void readNetworkStatsLocked() {
+        if (LOGV) Slog.v(TAG, "readNetworkStatsLocked()");
 
         // clear any existing stats and read from disk
-        mSummaryStats.clear();
+        mNetworkStats.clear();
 
         FileInputStream fis = null;
         try {
-            fis = mSummaryFile.openRead();
+            fis = mNetworkFile.openRead();
             final DataInputStream in = new DataInputStream(fis);
 
             // verify file magic header intact
@@ -497,13 +577,14 @@
             switch (version) {
                 case VERSION_CURRENT: {
                     // file format is pairs of interfaces and stats:
-                    // summary := size *(InterfaceIdentity NetworkStatsHistory)
+                    // network := size *(InterfaceIdentity NetworkStatsHistory)
 
                     final int size = in.readInt();
                     for (int i = 0; i < size; i++) {
                         final InterfaceIdentity ident = new InterfaceIdentity(in);
                         final NetworkStatsHistory history = new NetworkStatsHistory(in);
-                        mSummaryStats.put(ident, history);
+
+                        mNetworkStats.put(ident, history);
                     }
                     break;
                 }
@@ -520,30 +601,113 @@
         }
     }
 
-    private void writeStatsLocked() {
-        if (LOGD) Slog.v(TAG, "writeStatsLocked()");
+    private void ensureUidStatsLoadedLocked() {
+        if (!mUidStatsLoaded) {
+            readUidStatsLocked();
+            mUidStatsLoaded = true;
+        }
+    }
+
+    private void readUidStatsLocked() {
+        if (LOGV) Slog.v(TAG, "readUidStatsLocked()");
+
+        // clear any existing stats and read from disk
+        mUidStats.clear();
+
+        FileInputStream fis = null;
+        try {
+            fis = mUidFile.openRead();
+            final DataInputStream in = new DataInputStream(fis);
+
+            // verify file magic header intact
+            final int magic = in.readInt();
+            if (magic != FILE_MAGIC) {
+                throw new ProtocolException("unexpected magic: " + magic);
+            }
+
+            final int version = in.readInt();
+            switch (version) {
+                case VERSION_CURRENT: {
+                    // file format is pairs of UIDs and stats:
+                    // uid := size *(UID NetworkStatsHistory)
+
+                    final int size = in.readInt();
+                    for (int i = 0; i < size; i++) {
+                        final int uid = in.readInt();
+                        final NetworkStatsHistory history = new NetworkStatsHistory(in);
+
+                        mUidStats.put(uid, history);
+                    }
+                    break;
+                }
+                default: {
+                    throw new ProtocolException("unexpected version: " + version);
+                }
+            }
+        } catch (FileNotFoundException e) {
+            // missing stats is okay, probably first boot
+        } catch (IOException e) {
+            Slog.e(TAG, "problem reading uid stats", e);
+        } finally {
+            IoUtils.closeQuietly(fis);
+        }
+    }
+
+    private void writeNetworkStatsLocked() {
+        if (LOGV) Slog.v(TAG, "writeNetworkStatsLocked()");
 
         // TODO: consider duplicating stats and releasing lock while writing
 
         FileOutputStream fos = null;
         try {
-            fos = mSummaryFile.startWrite();
+            fos = mNetworkFile.startWrite();
             final DataOutputStream out = new DataOutputStream(fos);
 
             out.writeInt(FILE_MAGIC);
             out.writeInt(VERSION_CURRENT);
 
-            out.writeInt(mSummaryStats.size());
-            for (InterfaceIdentity ident : mSummaryStats.keySet()) {
-                final NetworkStatsHistory history = mSummaryStats.get(ident);
+            out.writeInt(mNetworkStats.size());
+            for (InterfaceIdentity ident : mNetworkStats.keySet()) {
+                final NetworkStatsHistory history = mNetworkStats.get(ident);
                 ident.writeToStream(out);
                 history.writeToStream(out);
             }
 
-            mSummaryFile.finishWrite(fos);
+            mNetworkFile.finishWrite(fos);
         } catch (IOException e) {
             if (fos != null) {
-                mSummaryFile.failWrite(fos);
+                mNetworkFile.failWrite(fos);
+            }
+        }
+    }
+
+    private void writeUidStatsLocked() {
+        if (LOGV) Slog.v(TAG, "writeUidStatsLocked()");
+
+        // TODO: consider duplicating stats and releasing lock while writing
+
+        FileOutputStream fos = null;
+        try {
+            fos = mUidFile.startWrite();
+            final DataOutputStream out = new DataOutputStream(fos);
+
+            out.writeInt(FILE_MAGIC);
+            out.writeInt(VERSION_CURRENT);
+
+            final int size = mUidStats.size();
+
+            out.writeInt(size);
+            for (int i = 0; i < size; i++) {
+                final int uid = mUidStats.keyAt(i);
+                final NetworkStatsHistory history = mUidStats.valueAt(i);
+                out.writeInt(uid);
+                history.writeToStream(out);
+            }
+
+            mUidFile.finishWrite(fos);
+        } catch (IOException e) {
+            if (fos != null) {
+                mUidFile.failWrite(fos);
             }
         }
     }
@@ -566,7 +730,7 @@
             }
 
             if (argSet.contains("poll")) {
-                performPollLocked();
+                performPollLocked(true);
                 pw.println("Forced poll");
                 return;
             }
@@ -579,17 +743,20 @@
             }
 
             pw.println("Known historical stats:");
-            for (InterfaceIdentity ident : mSummaryStats.keySet()) {
-                final NetworkStatsHistory stats = mSummaryStats.get(ident);
+            for (InterfaceIdentity ident : mNetworkStats.keySet()) {
+                final NetworkStatsHistory stats = mNetworkStats.get(ident);
                 pw.print("  ident="); pw.println(ident.toString());
                 stats.dump("    ", pw);
             }
 
             if (argSet.contains("detail")) {
-                pw.println("Known detail stats:");
-                for (int i = 0; i < mDetailStats.size(); i++) {
-                    final int uid = mDetailStats.keyAt(i);
-                    final NetworkStatsHistory stats = mDetailStats.valueAt(i);
+                // since explicitly requested with argument, we're okay to load
+                // from disk if not already in memory.
+                ensureUidStatsLoadedLocked();
+                pw.println("Known UID stats:");
+                for (int i = 0; i < mUidStats.size(); i++) {
+                    final int uid = mUidStats.keyAt(i);
+                    final NetworkStatsHistory stats = mUidStats.valueAt(i);
                     pw.print("  UID="); pw.println(uid);
                     stats.dump("    ", pw);
                 }
@@ -603,47 +770,29 @@
     @Deprecated
     private void generateRandomLocked() {
         long end = System.currentTimeMillis();
-        long start = end - mSummaryMaxHistory.get();
+        long start = end - mSettings.getNetworkMaxHistory();
         long rx = 3 * GB_IN_BYTES;
         long tx = 2 * GB_IN_BYTES;
 
-        mSummaryStats.clear();
+        mNetworkStats.clear();
         for (InterfaceIdentity ident : mActiveIface.values()) {
-            final NetworkStatsHistory stats = findOrCreateSummaryLocked(ident);
+            final NetworkStatsHistory stats = findOrCreateNetworkLocked(ident);
             stats.generateRandom(start, end, rx, tx);
         }
 
         end = System.currentTimeMillis();
-        start = end - mDetailMaxHistory.get();
+        start = end - mSettings.getUidMaxHistory();
         rx = 500 * MB_IN_BYTES;
         tx = 100 * MB_IN_BYTES;
 
-        mDetailStats.clear();
+        mUidStats.clear();
         for (ApplicationInfo info : mContext.getPackageManager().getInstalledApplications(0)) {
             final int uid = info.uid;
-            final NetworkStatsHistory stats = findOrCreateDetailLocked(uid);
+            final NetworkStatsHistory stats = findOrCreateUidLocked(uid);
             stats.generateRandom(start, end, rx, tx);
         }
     }
 
-    private class LongSecureSetting {
-        private String mKey;
-        private long mDefaultValue;
-
-        public LongSecureSetting(String key, long defaultValue) {
-            mKey = key;
-            mDefaultValue = defaultValue;
-        }
-
-        public long get() {
-            if (mContext != null) {
-                return Settings.Secure.getLong(mContext.getContentResolver(), mKey, mDefaultValue);
-            } else {
-                return mDefaultValue;
-            }
-        }
-    }
-
     /**
      * Return the delta between two {@link NetworkStats} snapshots, where {@code
      * before} can be {@code null}.
@@ -662,4 +811,54 @@
         return telephony.getSubscriberId();
     }
 
+    private int estimateNetworkBuckets() {
+        return (int) (mSettings.getNetworkMaxHistory() / mSettings.getNetworkBucketDuration());
+    }
+
+    private int estimateUidBuckets() {
+        return (int) (mSettings.getUidMaxHistory() / mSettings.getUidBucketDuration());
+    }
+
+    private static int estimateResizeBuckets(NetworkStatsHistory existing, long newBucketDuration) {
+        return (int) (existing.bucketCount * existing.bucketDuration / newBucketDuration);
+    }
+
+    /**
+     * Default external settings that read from {@link Settings.Secure}.
+     */
+    private static class DefaultNetworkStatsSettings implements NetworkStatsSettings {
+        private final ContentResolver mResolver;
+
+        public DefaultNetworkStatsSettings(Context context) {
+            mResolver = checkNotNull(context.getContentResolver());
+            // TODO: adjust these timings for production builds
+        }
+
+        private long getSecureLong(String name, long def) {
+            return Settings.Secure.getLong(mResolver, name, def);
+        }
+
+        public long getPollInterval() {
+            return getSecureLong(NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS);
+        }
+        public long getPersistThreshold() {
+            return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 16 * KB_IN_BYTES);
+        }
+        public long getNetworkBucketDuration() {
+            return getSecureLong(NETSTATS_NETWORK_BUCKET_DURATION, HOUR_IN_MILLIS);
+        }
+        public long getNetworkMaxHistory() {
+            return getSecureLong(NETSTATS_NETWORK_MAX_HISTORY, 90 * DAY_IN_MILLIS);
+        }
+        public long getUidBucketDuration() {
+            return getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS);
+        }
+        public long getUidMaxHistory() {
+            return getSecureLong(NETSTATS_UID_MAX_HISTORY, 90 * DAY_IN_MILLIS);
+        }
+        public long getTimeCacheMaxAge() {
+            return DAY_IN_MILLIS;
+        }
+    }
+
 }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 86c899e..1c87f5b 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -428,7 +428,6 @@
     boolean mDisplayFrozen = false;
     boolean mWaitingForConfig = false;
     boolean mWindowsFreezingScreen = false;
-    long mFreezeGcPending = 0;
     int mAppsFreezingScreen = 0;
     int mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 
@@ -4975,9 +4974,11 @@
      * MUST CALL setNewConfiguration() TO UNFREEZE THE SCREEN.
      */
     public boolean setRotationUncheckedLocked(int rotation, int animFlags, boolean inTransaction) {
-        if (mDragState != null || mScreenRotationAnimation != null) {
-            // Potential rotation during a drag.  Don't do the rotation now, but make
-            // a note to perform the rotation later.
+        if (mDragState != null
+                || (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating())) {
+            // Potential rotation during a drag or while waiting for a previous orientation
+            // change to finish (rotation animation will be dismissed).
+            // Don't do the rotation now, but make a note to perform the rotation later.
             if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation.");
             if (rotation != WindowManagerPolicy.USE_LAST_ROTATION) {
                 mDeferredRotation = rotation;
@@ -6435,7 +6436,6 @@
                         if (mDisplayFrozen) {
                             return;
                         }
-                        mFreezeGcPending = 0;
                     }
                     Runtime.getRuntime().gc();
                     break;
@@ -8653,19 +8653,6 @@
 
         mScreenFrozenLock.acquire();
 
-        long now = SystemClock.uptimeMillis();
-        //Slog.i(TAG, "Freezing, gc pending: " + mFreezeGcPending + ", now " + now);
-        if (mFreezeGcPending != 0) {
-            if (now > (mFreezeGcPending+1000)) {
-                //Slog.i(TAG, "Gc!  " + now + " > " + (mFreezeGcPending+1000));
-                mH.removeMessages(H.FORCE_GC);
-                Runtime.getRuntime().gc();
-                mFreezeGcPending = now;
-            }
-        } else {
-            mFreezeGcPending = now;
-        }
-
         mDisplayFrozen = true;
         
         mInputMonitor.freezeInputDispatchingLw();
diff --git a/services/jni/com_android_server_connectivity_Vpn.cpp b/services/jni/com_android_server_connectivity_Vpn.cpp
index 374fd3b..b3d38dc 100644
--- a/services/jni/com_android_server_connectivity_Vpn.cpp
+++ b/services/jni/com_android_server_connectivity_Vpn.cpp
@@ -38,16 +38,10 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
-#include "android_util_Binder.h"
 
 namespace android
 {
 
-static inline void init_sockaddr(sockaddr *sa) {
-    ((sockaddr_in *)sa)->sin_family = AF_INET;
-    ((sockaddr_in *)sa)->sin_port = 0;
-}
-
 static inline in_addr_t *as_in_addr(sockaddr *sa) {
     return &((sockaddr_in *)sa)->sin_addr.s_addr;
 }
@@ -65,7 +59,7 @@
 #define SYSTEM_ERROR -1
 #define BAD_ARGUMENT -2
 
-static int create_interface(char *name, int *index)
+static int create_interface(int mtu, char *name, int *index)
 {
     int tun = open("/dev/tun", O_RDWR);
     int inet4 = socket(AF_INET, SOCK_DGRAM, 0);
@@ -74,7 +68,7 @@
     memset(&ifr4, 0, sizeof(ifr4));
 
     // Allocate interface.
-    ifr4.ifr_flags = IFF_TUN;
+    ifr4.ifr_flags = IFF_TUN | IFF_NO_PI;
     if (ioctl(tun, TUNSETIFF, &ifr4)) {
         LOGE("Cannot allocate TUN: %s", strerror(errno));
         goto error;
@@ -87,6 +81,13 @@
         goto error;
     }
 
+    // Set MTU if it is specified.
+    ifr4.ifr_mtu = mtu;
+    if (mtu > 0 && ioctl(inet4, SIOCSIFMTU, &ifr4)) {
+        LOGE("Cannot set MTU on %s: %s", ifr4.ifr_name, strerror(errno));
+        goto error;
+    }
+
     // Get interface index.
     if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
         LOGE("Cannot get index of %s: %s", ifr4.ifr_name, strerror(errno));
@@ -112,7 +113,7 @@
     ifreq ifr4;
     memset(&ifr4, 0, sizeof(ifr4));
     strcpy(ifr4.ifr_name, name);
-    init_sockaddr(&ifr4.ifr_addr);
+    ifr4.ifr_addr.sa_family = AF_INET;
 
     in6_ifreq ifr6;
     memset(&ifr6, 0, sizeof(ifr6));
@@ -190,9 +191,9 @@
     memset(&rt4, 0, sizeof(rt4));
     rt4.rt_dev = (char *)name;
     rt4.rt_flags = RTF_UP;
-    init_sockaddr(&rt4.rt_dst);
-    init_sockaddr(&rt4.rt_genmask);
-    init_sockaddr(&rt4.rt_gateway);
+    rt4.rt_dst.sa_family = AF_INET;
+    rt4.rt_genmask.sa_family = AF_INET;
+    rt4.rt_gateway.sa_family = AF_INET;
 
     in6_rtmsg rt6;
     memset(&rt6, 0, sizeof(rt6));
@@ -223,7 +224,7 @@
             if (memcmp(&rt6.rtmsg_gateway, &in6addr_any, sizeof(in6addr_any))) {
                 rt6.rtmsg_flags |= RTF_GATEWAY;
             }
-            if (ioctl(inet6, SIOCADDRT, &rt6)) {
+            if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) {
                 count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
                 break;
             }
@@ -241,7 +242,7 @@
             if (*as_in_addr(&rt4.rt_gateway)) {
                 rt4.rt_flags |= RTF_GATEWAY;
             }
-            if (ioctl(inet4, SIOCADDRT, &rt4)) {
+            if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) {
                 count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
                 break;
             }
@@ -299,10 +300,10 @@
 
     ifreq ifr4;
     strncpy(ifr4.ifr_name, name, IFNAMSIZ);
+    ifr4.ifr_flags = 0;
 
     if (ioctl(inet4, SIOCGIFFLAGS, &ifr4) && errno != ENODEV) {
         LOGE("Cannot check %s: %s", name, strerror(errno));
-        ifr4.ifr_flags = 0;
     }
     close(inet4);
     return ifr4.ifr_flags;
@@ -328,15 +329,15 @@
     }
 }
 
-static jobject configure(JNIEnv *env, jobject thiz,
-        jstring jAddresses, jstring jRoutes)
+static jint establish(JNIEnv *env, jobject thiz,
+        jint mtu, jstring jAddresses, jstring jRoutes)
 {
     char name[IFNAMSIZ];
     int index;
-    int tun = create_interface(name, &index);
+    int tun = create_interface(mtu, name, &index);
     if (tun < 0) {
         throwException(env, tun, "Cannot create interface");
-        return NULL;
+        return -1;
     }
     LOGD("%s is created", name);
 
@@ -370,12 +371,12 @@
         LOGD("Configured %d route(s) on %s", count, name);
     }
 
-    return newParcelFileDescriptor(env, jniCreateFileDescriptor(env, tun));
+    return tun;
 
 error:
     close(tun);
     LOGD("%s is destroyed", name);
-    return NULL;
+    return -1;
 }
 
 static jstring getName(JNIEnv *env, jobject thiz, jint fd)
@@ -434,7 +435,7 @@
 //------------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
-    {"nativeConfigure", "(Ljava/lang/String;Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;", (void *)configure},
+    {"nativeEstablish", "(ILjava/lang/String;Ljava/lang/String;)I", (void *)establish},
     {"nativeGetName", "(I)Ljava/lang/String;", (void *)getName},
     {"nativeReset", "(Ljava/lang/String;)V", (void *)reset},
     {"nativeCheck", "(Ljava/lang/String;)I", (void *)check},
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 9daaad8..c618263 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -2,18 +2,18 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-    clz.cpp.arm \
-    DisplayHardware/DisplayHardware.cpp \
+    Layer.cpp 								\
+    LayerBase.cpp 							\
+    LayerDim.cpp 							\
+    DisplayHardware/DisplayHardware.cpp 	\
     DisplayHardware/DisplayHardwareBase.cpp \
-    DisplayHardware/HWComposer.cpp \
-    GLExtensions.cpp \
-    Layer.cpp \
-    LayerBase.cpp \
-    LayerDim.cpp \
-    MessageQueue.cpp \
-    SurfaceFlinger.cpp \
-    TextureManager.cpp \
-    Transform.cpp
+    DisplayHardware/HWComposer.cpp 			\
+    GLExtensions.cpp 						\
+    MessageQueue.cpp 						\
+    SurfaceFlinger.cpp 						\
+    SurfaceTextureLayer.cpp 				\
+    Transform.cpp 							\
+    
 
 LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 8df2b92..2bab6a8 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -18,8 +18,9 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <cutils/properties.h>
+#include <cutils/compiler.h>
 #include <cutils/native_handle.h>
+#include <cutils/properties.h>
 
 #include <utils/Errors.h>
 #include <utils/Log.h>
@@ -31,12 +32,12 @@
 #include <surfaceflinger/Surface.h>
 
 #include "clz.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware/HWComposer.h"
 #include "GLExtensions.h"
 #include "Layer.h"
 #include "SurfaceFlinger.h"
-#include "DisplayHardware/DisplayHardware.h"
-#include "DisplayHardware/HWComposer.h"
-
+#include "SurfaceTextureLayer.h"
 
 #define DEBUG_RESIZE    0
 
@@ -52,102 +53,83 @@
 Layer::Layer(SurfaceFlinger* flinger,
         DisplayID display, const sp<Client>& client)
     :   LayerBaseClient(flinger, display, client),
+        mTextureName(-1U),
+        mQueuedFrames(0),
+        mCurrentTransform(0),
+        mCurrentOpacity(true),
         mFormat(PIXEL_FORMAT_NONE),
         mGLExtensions(GLExtensions::getInstance()),
-        mNeedsBlending(true),
+        mOpaqueLayer(true),
         mNeedsDithering(false),
         mSecure(false),
         mProtectedByApp(false),
-        mTextureManager(),
-        mBufferManager(mTextureManager),
-        mWidth(0), mHeight(0),
-        mNeedsScaling(false), mFixedSize(false)
+        mFixedSize(false)
 {
+    mCurrentCrop.makeInvalid();
+    glGenTextures(1, &mTextureName);
+}
+
+void Layer::destroy(RefBase const* base) {
+    mFlinger->destroyLayer(static_cast<LayerBase const*>(base));
+}
+
+void Layer::onFirstRef()
+{
+    LayerBaseClient::onFirstRef();
+    setDestroyer(this);
+
+    struct FrameQueuedListener : public SurfaceTexture::FrameAvailableListener {
+        FrameQueuedListener(Layer* layer) : mLayer(layer) { }
+    private:
+        wp<Layer> mLayer;
+        virtual void onFrameAvailable() {
+            sp<Layer> that(mLayer.promote());
+            if (that != 0) {
+                that->onFrameQueued();
+            }
+        }
+    };
+    mSurfaceTexture = new SurfaceTextureLayer(mTextureName, this);
+    mSurfaceTexture->setFrameAvailableListener(new FrameQueuedListener(this));
+    mSurfaceTexture->setSynchronousMode(true);
+    mSurfaceTexture->setBufferCountServer(2);
 }
 
 Layer::~Layer()
 {
-    // FIXME: must be called from the main UI thread
-    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
-    mBufferManager.destroy(dpy);
+    glDeleteTextures(1, &mTextureName);
+}
 
-    // we can use getUserClientUnsafe here because we know we're
-    // single-threaded at that point.
-    sp<UserClient> ourClient(mUserClientRef.getUserClientUnsafe());
-    if (ourClient != 0) {
-        ourClient->detachLayer(this);
+void Layer::onFrameQueued() {
+    if (android_atomic_or(1, &mQueuedFrames) == 0) {
+        mFlinger->signalEvent();
     }
 }
 
-void Layer::destroy() const {
-    mFlinger->destroyLayer(this);
-}
-
-status_t Layer::setToken(const sp<UserClient>& userClient,
-        SharedClient* sharedClient, int32_t token)
-{
-    sp<SharedBufferServer> lcblk = new SharedBufferServer(
-            sharedClient, token, mBufferManager.getDefaultBufferCount(),
-            getIdentity());
-
-
-    sp<UserClient> ourClient(mUserClientRef.getClient());
-
-    /*
-     *  Here it is guaranteed that userClient != ourClient
-     *  (see UserClient::getTokenForSurface()).
-     *
-     *  We release the token used by this surface in ourClient below.
-     *  This should be safe to do so now, since this layer won't be attached
-     *  to this client, it should be okay to reuse that id.
-     *
-     *  If this causes problems, an other solution would be to keep a list
-     *  of all the {UserClient, token} ever used and release them when the
-     *  Layer is destroyed.
-     *
-     */
-
-    if (ourClient != 0) {
-        ourClient->detachLayer(this);
-    }
-
-    status_t err = mUserClientRef.setToken(userClient, lcblk, token);
-    LOGE_IF(err != NO_ERROR,
-            "ClientRef::setToken(%p, %p, %u) failed",
-            userClient.get(), lcblk.get(), token);
-
-    if (err == NO_ERROR) {
-        // we need to free the buffers associated with this surface
-    }
-
-    return err;
-}
-
-int32_t Layer::getToken() const
-{
-    return mUserClientRef.getToken();
-}
-
-sp<UserClient> Layer::getClient() const
-{
-    return mUserClientRef.getClient();
-}
-
 // called with SurfaceFlinger::mStateLock as soon as the layer is entered
 // in the purgatory list
 void Layer::onRemoved()
 {
-    ClientRef::Access sharedClient(mUserClientRef);
-    SharedBufferServer* lcblk(sharedClient.get());
-    if (lcblk) {
-        // wake up the condition
-        lcblk->setStatus(NO_INIT);
-    }
 }
 
-sp<LayerBaseClient::Surface> Layer::createSurface() const
+sp<ISurface> Layer::createSurface()
 {
-    sp<Surface> sur(new SurfaceLayer(mFlinger, const_cast<Layer *>(this)));
+    class BSurface : public BnSurface, public LayerCleaner {
+        wp<const Layer> mOwner;
+        virtual sp<ISurfaceTexture> getSurfaceTexture() const {
+            sp<ISurfaceTexture> res;
+            sp<const Layer> that( mOwner.promote() );
+            if (that != NULL) {
+                res = that->mSurfaceTexture;
+            }
+            return res;
+        }
+    public:
+        BSurface(const sp<SurfaceFlinger>& flinger,
+                const sp<Layer>& layer)
+            : LayerCleaner(flinger, layer), mOwner(layer) { }
+    };
+    sp<ISurface> sur(new BSurface(mFlinger, this));
     return sur;
 }
 
@@ -175,17 +157,14 @@
     const uint32_t hwFlags = hw.getFlags();
     
     mFormat = format;
-    mWidth  = w;
-    mHeight = h;
-
-    mReqFormat = format;
-    mReqWidth = w;
-    mReqHeight = h;
 
     mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
     mProtectedByApp = (flags & ISurfaceComposer::eProtectedByApp) ? true : false;
-    mNeedsBlending = (info.h_alpha - info.l_alpha) > 0 &&
-            (flags & ISurfaceComposer::eOpaque) == 0;
+    mOpaqueLayer = (flags & ISurfaceComposer::eOpaque);
+    mCurrentOpacity = getOpacityForFormat(format);
+
+    mSurfaceTexture->setDefaultBufferSize(w, h);
+    mSurfaceTexture->setDefaultBufferFormat(format);
 
     // we use the red index
     int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED);
@@ -216,10 +195,12 @@
         return;
     }
 
-    Transform tr(Transform(mOrientation) * Transform(mBufferTransform));
+    // FIXME: shouldn't we take the state's transform into account here?
+
+    Transform tr(Transform(mOrientation) * Transform(mCurrentTransform));
     hwcl->transform = tr.getOrientation();
 
-    if (needsBlending()) {
+    if (!isOpaque()) {
         hwcl->blending = mPremultipliedAlpha ?
                 HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
     }
@@ -236,7 +217,7 @@
 }
 
 void Layer::setPerFrameData(hwc_layer_t* hwcl) {
-    sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
+    const sp<GraphicBuffer>& buffer(mActiveBuffer);
     if (buffer == NULL) {
         // this can happen if the client never drew into this layer yet,
         // or if we ran out of memory. In that case, don't let
@@ -247,11 +228,11 @@
     }
     hwcl->handle = buffer->handle;
 
-    if (!mBufferCrop.isEmpty()) {
-        hwcl->sourceCrop.left   = mBufferCrop.left;
-        hwcl->sourceCrop.top    = mBufferCrop.top;
-        hwcl->sourceCrop.right  = mBufferCrop.right;
-        hwcl->sourceCrop.bottom = mBufferCrop.bottom;
+    if (isCropped()) {
+        hwcl->sourceCrop.left   = mCurrentCrop.left;
+        hwcl->sourceCrop.top    = mCurrentCrop.top;
+        hwcl->sourceCrop.right  = mCurrentCrop.right;
+        hwcl->sourceCrop.bottom = mCurrentCrop.bottom;
     } else {
         hwcl->sourceCrop.left   = 0;
         hwcl->sourceCrop.top    = 0;
@@ -260,51 +241,12 @@
     }
 }
 
-void Layer::reloadTexture(const Region& dirty)
-{
-    sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
-    if (buffer == NULL) {
-        // this situation can happen if we ran out of memory for instance.
-        // not much we can do. continue to use whatever texture was bound
-        // to this context.
-        return;
-    }
-
-    if (mGLExtensions.haveDirectTexture()) {
-        EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
-        if (mBufferManager.initEglImage(dpy, buffer) != NO_ERROR) {
-            // not sure what we can do here...
-            goto slowpath;
-        }
-    } else {
-slowpath:
-        GGLSurface t;
-        if (buffer->usage & GRALLOC_USAGE_SW_READ_MASK) {
-            status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);
-            LOGE_IF(res, "error %d (%s) locking buffer %p",
-                    res, strerror(res), buffer.get());
-            if (res == NO_ERROR) {
-                mBufferManager.loadTexture(dirty, t);
-                buffer->unlock();
-            }
-        } else {
-            // we can't do anything
-        }
-    }
+static inline uint16_t pack565(int r, int g, int b) {
+    return (r<<11)|(g<<5)|b;
 }
-
-void Layer::drawForSreenShot() const
-{
-    const bool currentFiltering = mNeedsFiltering;
-    const_cast<Layer*>(this)->mNeedsFiltering = true;
-    LayerBase::drawForSreenShot();
-    const_cast<Layer*>(this)->mNeedsFiltering = currentFiltering;
-}
-
 void Layer::onDraw(const Region& clip) const
 {
-    Texture tex(mBufferManager.getActiveTexture());
-    if (tex.name == -1LU) {
+    if (CC_UNLIKELY(mActiveBuffer == 0)) {
         // the texture has not been created yet, this Layer has
         // in fact never been drawn into. This happens frequently with
         // SurfaceView because the WindowManager can't know when the client
@@ -330,7 +272,25 @@
         }
         return;
     }
-    drawWithOpenGL(clip, tex);
+
+    GLenum target = mSurfaceTexture->getCurrentTextureTarget();
+    glBindTexture(target, mTextureName);
+    if (getFiltering() || needsFiltering() || isFixedSize() || isCropped()) {
+        // TODO: we could be more subtle with isFixedSize()
+        glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    } else {
+        glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    }
+    glEnable(target);
+    glMatrixMode(GL_TEXTURE);
+    glLoadMatrixf(mTextureMatrix);
+    glMatrixMode(GL_MODELVIEW);
+
+    drawWithOpenGL(clip);
+
+    glDisable(target);
 }
 
 // As documented in libhardware header, formats in the range
@@ -340,186 +300,37 @@
 // hardware.h, instead of using hard-coded values here.
 #define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
 
-bool Layer::needsBlending(const sp<GraphicBuffer>& buffer) const
+bool Layer::getOpacityForFormat(uint32_t format)
 {
-    // If buffers where set with eOpaque flag, all buffers are known to
-    // be opaque without having to check their actual format
-    if (mNeedsBlending && buffer != NULL) {
-        PixelFormat format = buffer->getPixelFormat();
-
-        if (HARDWARE_IS_DEVICE_FORMAT(format)) {
-            return false;
-        }
-
-        PixelFormatInfo info;
-        status_t err = getPixelFormatInfo(format, &info);
-        if (!err && info.h_alpha <= info.l_alpha) {
-            return false;
-        }
+    if (HARDWARE_IS_DEVICE_FORMAT(format)) {
+        return true;
     }
-
-    // Return opacity as determined from flags and format options
-    // passed to setBuffers()
-    return mNeedsBlending;
+    PixelFormatInfo info;
+    status_t err = getPixelFormatInfo(PixelFormat(format), &info);
+    // in case of error (unknown format), we assume no blending
+    return (err || info.h_alpha <= info.l_alpha);
 }
 
-bool Layer::needsBlending() const
-{
-    if (mBufferManager.hasActiveBuffer()) {
-        return needsBlending(mBufferManager.getActiveBuffer());
-    }
 
-    return mNeedsBlending;
-}
-
-bool Layer::needsFiltering() const
+bool Layer::isOpaque() const
 {
-    if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
-        // if our buffer is not the same size than ourselves,
-        // we need filtering.
-        Mutex::Autolock _l(mLock);
-        if (mNeedsScaling)
-            return true;
-    }
-    return LayerBase::needsFiltering();
+    // if we don't have a buffer yet, we're translucent regardless of the
+    // layer's opaque flag.
+    if (mActiveBuffer == 0)
+        return false;
+
+    // if the layer has the opaque flag, then we're always opaque,
+    // otherwise we use the current buffer's format.
+    return mOpaqueLayer || mCurrentOpacity;
 }
 
 bool Layer::isProtected() const
 {
-    sp<GraphicBuffer> activeBuffer(mBufferManager.getActiveBuffer());
+    const sp<GraphicBuffer>& activeBuffer(mActiveBuffer);
     return (activeBuffer != 0) &&
             (activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
 }
 
-status_t Layer::setBufferCount(int bufferCount)
-{
-    ClientRef::Access sharedClient(mUserClientRef);
-    SharedBufferServer* lcblk(sharedClient.get());
-    if (!lcblk) {
-        // oops, the client is already gone
-        return DEAD_OBJECT;
-    }
-
-    // NOTE: lcblk->resize() is protected by an internal lock
-    status_t err = lcblk->resize(bufferCount);
-    if (err == NO_ERROR) {
-        EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
-        mBufferManager.resize(bufferCount, mFlinger, dpy);
-    }
-
-    return err;
-}
-
-sp<GraphicBuffer> Layer::requestBuffer(int index,
-        uint32_t reqWidth, uint32_t reqHeight, uint32_t reqFormat,
-        uint32_t usage)
-{
-    sp<GraphicBuffer> buffer;
-
-    if (int32_t(reqWidth | reqHeight | reqFormat) < 0)
-        return buffer;
-
-    if ((!reqWidth && reqHeight) || (reqWidth && !reqHeight))
-        return buffer;
-
-    // this ensures our client doesn't go away while we're accessing
-    // the shared area.
-    ClientRef::Access sharedClient(mUserClientRef);
-    SharedBufferServer* lcblk(sharedClient.get());
-    if (!lcblk) {
-        // oops, the client is already gone
-        return buffer;
-    }
-
-    /*
-     * This is called from the client's Surface::dequeue(). This can happen
-     * at any time, especially while we're in the middle of using the
-     * buffer 'index' as our front buffer.
-     */
-
-    status_t err = NO_ERROR;
-    uint32_t w, h, f;
-    { // scope for the lock
-        Mutex::Autolock _l(mLock);
-
-        // zero means default
-        const bool fixedSize = reqWidth && reqHeight;
-        if (!reqFormat) reqFormat = mFormat;
-        if (!reqWidth)  reqWidth = mWidth;
-        if (!reqHeight) reqHeight = mHeight;
-
-        w = reqWidth;
-        h = reqHeight;
-        f = reqFormat;
-
-        if ((reqWidth != mReqWidth) || (reqHeight != mReqHeight) ||
-                (reqFormat != mReqFormat)) {
-            mReqWidth  = reqWidth;
-            mReqHeight = reqHeight;
-            mReqFormat = reqFormat;
-            mFixedSize = fixedSize;
-            mNeedsScaling = mWidth != mReqWidth || mHeight != mReqHeight;
-
-            lcblk->reallocateAllExcept(index);
-        }
-    }
-
-    // here we have to reallocate a new buffer because the buffer could be
-    // used as the front buffer, or by a client in our process
-    // (eg: status bar), and we can't release the handle under its feet.
-    const uint32_t effectiveUsage = getEffectiveUsage(usage);
-    buffer = new GraphicBuffer(w, h, f, effectiveUsage);
-    err = buffer->initCheck();
-
-    if (err || buffer->handle == 0) {
-        GraphicBuffer::dumpAllocationsToSystemLog();
-        LOGE_IF(err || buffer->handle == 0,
-                "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d failed (%s)",
-                this, index, w, h, strerror(-err));
-    } else {
-        LOGD_IF(DEBUG_RESIZE,
-                "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d, handle=%p",
-                this, index, w, h, buffer->handle);
-    }
-
-    if (err == NO_ERROR && buffer->handle != 0) {
-        Mutex::Autolock _l(mLock);
-        mBufferManager.attachBuffer(index, buffer);
-    }
-    return buffer;
-}
-
-uint32_t Layer::getEffectiveUsage(uint32_t usage) const
-{
-    /*
-     *  buffers used for software rendering, but h/w composition
-     *  are allocated with SW_READ_OFTEN | SW_WRITE_OFTEN | HW_TEXTURE
-     *
-     *  buffers used for h/w rendering and h/w composition
-     *  are allocated with  HW_RENDER | HW_TEXTURE
-     *
-     *  buffers used with h/w rendering and either NPOT or no egl_image_ext
-     *  are allocated with SW_READ_RARELY | HW_RENDER
-     *
-     */
-
-    if (mSecure) {
-        // secure buffer, don't store it into the GPU
-        usage = GraphicBuffer::USAGE_SW_READ_OFTEN |
-                GraphicBuffer::USAGE_SW_WRITE_OFTEN;
-    } else {
-        // it's allowed to modify the usage flags here, but generally
-        // the requested flags should be honored.
-        // request EGLImage for all buffers
-        usage |= GraphicBuffer::USAGE_HW_TEXTURE;
-    }
-    if (mProtectedByApp) {
-        // need a hardware-protected path to external video sink
-        usage |= GraphicBuffer::USAGE_PROTECTED;
-    }
-    return usage;
-}
-
 uint32_t Layer::doTransaction(uint32_t flags)
 {
     const Layer::State& front(drawingState());
@@ -531,10 +342,12 @@
     if (sizeChanged) {
         // the size changed, we need to ask our client to request a new buffer
         LOGD_IF(DEBUG_RESIZE,
-                "resize (layer=%p), requested (%dx%d), drawing (%d,%d)",
+                "resize (layer=%p), requested (%dx%d), drawing (%d,%d), "
+                "fixedSize=%d",
                 this,
                 int(temp.requested_w), int(temp.requested_h),
-                int(front.requested_w), int(front.requested_h));
+                int(front.requested_w), int(front.requested_h),
+                isFixedSize());
 
         if (!isFixedSize()) {
             // we're being resized and there is a freeze display request,
@@ -557,17 +370,7 @@
 
             // record the new size, form this point on, when the client request
             // a buffer, it'll get the new size.
-            setBufferSize(temp.requested_w, temp.requested_h);
-
-            ClientRef::Access sharedClient(mUserClientRef);
-            SharedBufferServer* lcblk(sharedClient.get());
-            if (lcblk) {
-                // all buffers need reallocation
-                lcblk->reallocateAll();
-            }
-        } else {
-            // record the new size
-            setBufferSize(temp.requested_w, temp.requested_h);
+            mSurfaceTexture->setDefaultBufferSize(temp.requested_w, temp.requested_h);
         }
     }
 
@@ -582,79 +385,69 @@
     return LayerBase::doTransaction(flags);
 }
 
-void Layer::setBufferSize(uint32_t w, uint32_t h) {
-    Mutex::Autolock _l(mLock);
-    mWidth = w;
-    mHeight = h;
-    mNeedsScaling = mWidth != mReqWidth || mHeight != mReqHeight;
-}
-
 bool Layer::isFixedSize() const {
     Mutex::Autolock _l(mLock);
     return mFixedSize;
 }
 
+void Layer::setFixedSize(bool fixedSize)
+{
+    Mutex::Autolock _l(mLock);
+    mFixedSize = fixedSize;
+}
+
+bool Layer::isCropped() const {
+    return !mCurrentCrop.isEmpty();
+}
+
 // ----------------------------------------------------------------------------
 // pageflip handling...
 // ----------------------------------------------------------------------------
 
 void Layer::lockPageFlip(bool& recomputeVisibleRegions)
 {
-    ClientRef::Access sharedClient(mUserClientRef);
-    SharedBufferServer* lcblk(sharedClient.get());
-    if (!lcblk) {
-        // client died
-        recomputeVisibleRegions = true;
-        return;
-    }
+    if (android_atomic_and(0, &mQueuedFrames)) {
+        if (mSurfaceTexture->updateTexImage() < NO_ERROR) {
+            // something happened!
+            recomputeVisibleRegions = true;
+            return;
+        }
 
-    ssize_t buf = lcblk->retireAndLock();
-    if (buf == NOT_ENOUGH_DATA) {
-        // NOTE: This is not an error, it simply means there is nothing to
-        // retire. The buffer is locked because we will use it
-        // for composition later in the loop
-        return;
-    }
+        // signal another event if we have more frames waiting
+        if (mSurfaceTexture->getQueuedCount()) {
+            if (android_atomic_or(1, &mQueuedFrames) == 0) {
+                mFlinger->signalEvent();
+            }
+        }
 
-    if (buf < NO_ERROR) {
-        LOGE("retireAndLock() buffer index (%d) out of range", int(buf));
-        mPostedDirtyRegion.clear();
-        return;
-    }
+        mActiveBuffer = mSurfaceTexture->getCurrentBuffer();
+        mSurfaceTexture->getTransformMatrix(mTextureMatrix);
 
-    // we retired a buffer, which becomes the new front buffer
+        const Rect crop(mSurfaceTexture->getCurrentCrop());
+        const uint32_t transform(mSurfaceTexture->getCurrentTransform());
+        if ((crop != mCurrentCrop) || (transform != mCurrentTransform)) {
+            mCurrentCrop = crop;
+            mCurrentTransform = transform;
+            mFlinger->invalidateHwcGeometry();
+        }
 
-    const bool noActiveBuffer = !mBufferManager.hasActiveBuffer();
-    const bool activeBlending =
-            noActiveBuffer ? true : needsBlending(mBufferManager.getActiveBuffer());
-
-    if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) {
-        LOGE("retireAndLock() buffer index (%d) out of range", int(buf));
-        mPostedDirtyRegion.clear();
-        return;
-    }
-
-    if (noActiveBuffer) {
-        // we didn't have an active buffer, we need to recompute
-        // our visible region
-        recomputeVisibleRegions = true;
-    }
-
-    sp<GraphicBuffer> newFrontBuffer(getBuffer(buf));
-    if (newFrontBuffer != NULL) {
-        if (!noActiveBuffer && activeBlending != needsBlending(newFrontBuffer)) {
-            // new buffer has different opacity than previous active buffer, need
-            // to recompute visible regions accordingly
+        const bool opacity(getOpacityForFormat(mActiveBuffer->format));
+        if (opacity != mCurrentOpacity) {
+            mCurrentOpacity = opacity;
             recomputeVisibleRegions = true;
         }
 
-        // get the dirty region
-        // compute the posted region
-        const Region dirty(lcblk->getDirtyRegion(buf));
-        mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() );
+        const GLenum target(mSurfaceTexture->getCurrentTextureTarget());
+        glTexParameterx(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameterx(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
         // update the layer size and release freeze-lock
         const Layer::State& front(drawingState());
+
+        // FIXME: mPostedDirtyRegion = dirty & bounds
+        mPostedDirtyRegion.set(front.w, front.h);
+
+        sp<GraphicBuffer> newFrontBuffer(mActiveBuffer);
         if ((newFrontBuffer->getWidth()  == front.requested_w &&
             newFrontBuffer->getHeight() == front.requested_h) ||
             isFixedSize())
@@ -685,35 +478,7 @@
             // we now have the correct size, unfreeze the screen
             mFreezeLock.clear();
         }
-
-        // get the crop region
-        setBufferCrop( lcblk->getCrop(buf) );
-
-        // get the transformation
-        setBufferTransform( lcblk->getTransform(buf) );
-
-    } else {
-        // this should not happen unless we ran out of memory while
-        // allocating the buffer. we're hoping that things will get back
-        // to normal the next time the app tries to draw into this buffer.
-        // meanwhile, pretend the screen didn't update.
-        mPostedDirtyRegion.clear();
     }
-
-    if (lcblk->getQueuedCount()) {
-        // signal an event if we have more buffers waiting
-        mFlinger->signalEvent();
-    }
-
-    /* a buffer was posted, so we need to call reloadTexture(), which
-     * will update our internal data structures (eg: EGLImageKHR or
-     * texture names). we need to do this even if mPostedDirtyRegion is
-     * empty -- it's orthogonal to the fact that a new buffer was posted,
-     * for instance, a degenerate case could be that the user did an empty
-     * update but repainted the buffer with appropriate content (after a
-     * resize for instance).
-     */
-    reloadTexture( mPostedDirtyRegion );
 }
 
 void Layer::unlockPageFlip(
@@ -746,329 +511,36 @@
 {
     LayerBaseClient::dump(result, buffer, SIZE);
 
-    ClientRef::Access sharedClient(mUserClientRef);
-    SharedBufferServer* lcblk(sharedClient.get());
-    uint32_t totalTime = 0;
-    if (lcblk) {
-        SharedBufferStack::Statistics stats = lcblk->getStats();
-        totalTime= stats.totalTime;
-        result.append( lcblk->dump("      ") );
-    }
-
-    sp<const GraphicBuffer> buf0(getBuffer(0));
-    sp<const GraphicBuffer> buf1(getBuffer(1));
-    uint32_t w0=0, h0=0, s0=0;
-    uint32_t w1=0, h1=0, s1=0;
+    sp<const GraphicBuffer> buf0(mActiveBuffer);
+    uint32_t w0=0, h0=0, s0=0, f0=0;
     if (buf0 != 0) {
         w0 = buf0->getWidth();
         h0 = buf0->getHeight();
         s0 = buf0->getStride();
-    }
-    if (buf1 != 0) {
-        w1 = buf1->getWidth();
-        h1 = buf1->getHeight();
-        s1 = buf1->getStride();
+        f0 = buf0->format;
     }
     snprintf(buffer, SIZE,
             "      "
-            "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
-            " freezeLock=%p, dq-q-time=%u us\n",
-            mFormat, w0, h0, s0, w1, h1, s1,
-            getFreezeLock().get(), totalTime);
+            "format=%2d, activeBuffer=[%3ux%3u:%3u,%3u],"
+            " freezeLock=%p, queued-frames=%d\n",
+            mFormat, w0, h0, s0,f0,
+            getFreezeLock().get(), mQueuedFrames);
 
     result.append(buffer);
-}
 
-// ---------------------------------------------------------------------------
-
-Layer::ClientRef::ClientRef()
-    : mControlBlock(0), mToken(-1) {
-}
-
-Layer::ClientRef::~ClientRef() {
-}
-
-int32_t Layer::ClientRef::getToken() const {
-    Mutex::Autolock _l(mLock);
-    return mToken;
-}
-
-sp<UserClient> Layer::ClientRef::getClient() const {
-    Mutex::Autolock _l(mLock);
-    return mUserClient.promote();
-}
-
-status_t Layer::ClientRef::setToken(const sp<UserClient>& uc,
-        const sp<SharedBufferServer>& sharedClient, int32_t token) {
-    Mutex::Autolock _l(mLock);
-
-    { // scope for strong mUserClient reference
-        sp<UserClient> userClient(mUserClient.promote());
-        if (userClient != 0 && mControlBlock != 0) {
-            mControlBlock->setStatus(NO_INIT);
-        }
+    if (mSurfaceTexture != 0) {
+        mSurfaceTexture->dump(result, "            ", buffer, SIZE);
     }
-
-    mUserClient = uc;
-    mToken = token;
-    mControlBlock = sharedClient;
-    return NO_ERROR;
 }
 
-sp<UserClient> Layer::ClientRef::getUserClientUnsafe() const {
-    return mUserClient.promote();
-}
-
-// this class gives us access to SharedBufferServer safely
-// it makes sure the UserClient (and its associated shared memory)
-// won't go away while we're accessing it.
-Layer::ClientRef::Access::Access(const ClientRef& ref)
-    : mControlBlock(0)
+uint32_t Layer::getEffectiveUsage(uint32_t usage) const
 {
-    Mutex::Autolock _l(ref.mLock);
-    mUserClientStrongRef = ref.mUserClient.promote();
-    if (mUserClientStrongRef != 0)
-        mControlBlock = ref.mControlBlock;
-}
-
-Layer::ClientRef::Access::~Access()
-{
-}
-
-// ---------------------------------------------------------------------------
-
-Layer::BufferManager::BufferManager(TextureManager& tm)
-    : mNumBuffers(NUM_BUFFERS), mTextureManager(tm),
-      mActiveBufferIndex(-1), mFailover(false)
-{
-}
-
-Layer::BufferManager::~BufferManager()
-{
-}
-
-status_t Layer::BufferManager::resize(size_t size,
-        const sp<SurfaceFlinger>& flinger, EGLDisplay dpy)
-{
-    Mutex::Autolock _l(mLock);
-
-    if (size < mNumBuffers) {
-        // If there is an active texture, move it into slot 0 if needed
-        if (mActiveBufferIndex > 0) {
-            BufferData activeBufferData = mBufferData[mActiveBufferIndex];
-            mBufferData[mActiveBufferIndex] = mBufferData[0];
-            mBufferData[0] = activeBufferData;
-            mActiveBufferIndex = 0;
-        }
-
-        // Free the buffers that are no longer needed.
-        for (size_t i = size; i < mNumBuffers; i++) {
-            mBufferData[i].buffer = 0;
-
-            // Create a message to destroy the textures on SurfaceFlinger's GL
-            // thread.
-            class MessageDestroyTexture : public MessageBase {
-                Image mTexture;
-                EGLDisplay mDpy;
-             public:
-                MessageDestroyTexture(const Image& texture, EGLDisplay dpy)
-                    : mTexture(texture), mDpy(dpy) { }
-                virtual bool handler() {
-                    status_t err = Layer::BufferManager::destroyTexture(
-                            &mTexture, mDpy);
-                    LOGE_IF(err<0, "error destroying texture: %d (%s)",
-                            mTexture.name, strerror(-err));
-                    return true; // XXX: err == 0;  ????
-                }
-            };
-
-            MessageDestroyTexture *msg = new MessageDestroyTexture(
-                    mBufferData[i].texture, dpy);
-
-            // Don't allow this texture to be cleaned up by
-            // BufferManager::destroy.
-            mBufferData[i].texture.name = -1U;
-            mBufferData[i].texture.image = EGL_NO_IMAGE_KHR;
-
-            // Post the message to the SurfaceFlinger object.
-            flinger->postMessageAsync(msg);
-        }
+    // TODO: should we do something special if mSecure is set?
+    if (mProtectedByApp) {
+        // need a hardware-protected path to external video sink
+        usage |= GraphicBuffer::USAGE_PROTECTED;
     }
-
-    mNumBuffers = size;
-    return NO_ERROR;
-}
-
-// only for debugging
-sp<GraphicBuffer> Layer::BufferManager::getBuffer(size_t index) const {
-    return mBufferData[index].buffer;
-}
-
-status_t Layer::BufferManager::setActiveBufferIndex(size_t index) {
-    BufferData const * const buffers = mBufferData;
-    Mutex::Autolock _l(mLock);
-    mActiveBuffer = buffers[index].buffer;
-    mActiveBufferIndex = index;
-    return NO_ERROR;
-}
-
-size_t Layer::BufferManager::getActiveBufferIndex() const {
-    return mActiveBufferIndex;
-}
-
-Texture Layer::BufferManager::getActiveTexture() const {
-    Texture res;
-    if (mFailover || mActiveBufferIndex<0) {
-        res = mFailoverTexture;
-    } else {
-        static_cast<Image&>(res) = mBufferData[mActiveBufferIndex].texture;
-    }
-    return res;
-}
-
-sp<GraphicBuffer> Layer::BufferManager::getActiveBuffer() const {
-    return mActiveBuffer;
-}
-
-bool Layer::BufferManager::hasActiveBuffer() const {
-    return mActiveBufferIndex >= 0;
-}
-
-sp<GraphicBuffer> Layer::BufferManager::detachBuffer(size_t index)
-{
-    BufferData* const buffers = mBufferData;
-    sp<GraphicBuffer> buffer;
-    Mutex::Autolock _l(mLock);
-    buffer = buffers[index].buffer;
-    buffers[index].buffer = 0;
-    return buffer;
-}
-
-status_t Layer::BufferManager::attachBuffer(size_t index,
-        const sp<GraphicBuffer>& buffer)
-{
-    BufferData* const buffers = mBufferData;
-    Mutex::Autolock _l(mLock);
-    buffers[index].buffer = buffer;
-    buffers[index].texture.dirty = true;
-    return NO_ERROR;
-}
-
-status_t Layer::BufferManager::destroy(EGLDisplay dpy)
-{
-    BufferData* const buffers = mBufferData;
-    size_t num;
-    { // scope for the lock
-        Mutex::Autolock _l(mLock);
-        num = mNumBuffers;
-        for (size_t i=0 ; i<num ; i++) {
-            buffers[i].buffer = 0;
-        }
-    }
-    for (size_t i=0 ; i<num ; i++) {
-        destroyTexture(&buffers[i].texture, dpy);
-    }
-    destroyTexture(&mFailoverTexture, dpy);
-    return NO_ERROR;
-}
-
-status_t Layer::BufferManager::initEglImage(EGLDisplay dpy,
-        const sp<GraphicBuffer>& buffer)
-{
-    status_t err = NO_INIT;
-    ssize_t index = mActiveBufferIndex;
-    if (index >= 0) {
-        if (!mFailover) {
-            {
-               // Without that lock, there is a chance of race condition
-               // where while composing a specific index, requestBuf
-               // with the same index can be executed and touch the same data
-               // that is being used in initEglImage.
-               // (e.g. dirty flag in texture)
-               Mutex::Autolock _l(mLock);
-               Image& texture(mBufferData[index].texture);
-               err = mTextureManager.initEglImage(&texture, dpy, buffer);
-            }
-            // if EGLImage fails, we switch to regular texture mode, and we
-            // free all resources associated with using EGLImages.
-            if (err == NO_ERROR) {
-                mFailover = false;
-                destroyTexture(&mFailoverTexture, dpy);
-            } else {
-                mFailover = true;
-                const size_t num = mNumBuffers;
-                for (size_t i=0 ; i<num ; i++) {
-                    destroyTexture(&mBufferData[i].texture, dpy);
-                }
-            }
-        } else {
-            // we failed once, don't try again
-            err = BAD_VALUE;
-        }
-    }
-    return err;
-}
-
-status_t Layer::BufferManager::loadTexture(
-        const Region& dirty, const GGLSurface& t)
-{
-    return mTextureManager.loadTexture(&mFailoverTexture, dirty, t);
-}
-
-status_t Layer::BufferManager::destroyTexture(Image* tex, EGLDisplay dpy)
-{
-    if (tex->name != -1U) {
-        glDeleteTextures(1, &tex->name);
-        tex->name = -1U;
-    }
-    if (tex->image != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(dpy, tex->image);
-        tex->image = EGL_NO_IMAGE_KHR;
-    }
-    return NO_ERROR;
-}
-
-// ---------------------------------------------------------------------------
-
-Layer::SurfaceLayer::SurfaceLayer(const sp<SurfaceFlinger>& flinger,
-        const sp<Layer>& owner)
-    : Surface(flinger, owner->getIdentity(), owner)
-{
-}
-
-Layer::SurfaceLayer::~SurfaceLayer()
-{
-}
-
-sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index,
-        uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
-{
-    sp<GraphicBuffer> buffer;
-    sp<Layer> owner(getOwner());
-    if (owner != 0) {
-        /*
-         * requestBuffer() cannot be called from the main thread
-         * as it could cause a dead-lock, since it may have to wait
-         * on conditions updated my the main thread.
-         */
-        buffer = owner->requestBuffer(index, w, h, format, usage);
-    }
-    return buffer;
-}
-
-status_t Layer::SurfaceLayer::setBufferCount(int bufferCount)
-{
-    status_t err = DEAD_OBJECT;
-    sp<Layer> owner(getOwner());
-    if (owner != 0) {
-        /*
-         * setBufferCount() cannot be called from the main thread
-         * as it could cause a dead-lock, since it may have to wait
-         * on conditions updated my the main thread.
-         */
-        err = owner->setBufferCount(bufferCount);
-    }
-    return err;
+    return usage;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 278d64e..e3fc13d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -20,9 +20,11 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <gui/SurfaceTexture.h>
+
+#include <pixelflinger/pixelflinger.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/PixelFormat.h>
-#include <pixelflinger/pixelflinger.h>
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
@@ -30,8 +32,8 @@
 #include <GLES/glext.h>
 
 #include "LayerBase.h"
+#include "SurfaceTextureLayer.h"
 #include "Transform.h"
-#include "TextureManager.h"
 
 namespace android {
 
@@ -40,11 +42,10 @@
 class FreezeLock;
 class Client;
 class GLExtensions;
-class UserClient;
 
 // ---------------------------------------------------------------------------
 
-class Layer : public LayerBaseClient
+class Layer : public LayerBaseClient, private RefBase::Destroyer
 {
 public:
             Layer(SurfaceFlinger* flinger, DisplayID display,
@@ -58,164 +59,59 @@
     status_t setBuffers(uint32_t w, uint32_t h, 
             PixelFormat format, uint32_t flags=0);
 
-    // associate a UserClient to this Layer
-    status_t setToken(const sp<UserClient>& uc, SharedClient* sc, int32_t idx);
-    int32_t getToken() const;
-    sp<UserClient> getClient() const;
-
     // Set this Layer's buffers size
-    void setBufferSize(uint32_t w, uint32_t h);
     bool isFixedSize() const;
 
     // LayerBase interface
     virtual void setGeometry(hwc_layer_t* hwcl);
     virtual void setPerFrameData(hwc_layer_t* hwcl);
-    virtual void drawForSreenShot() const;
     virtual void onDraw(const Region& clip) const;
     virtual uint32_t doTransaction(uint32_t transactionFlags);
     virtual void lockPageFlip(bool& recomputeVisibleRegions);
     virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
-    virtual bool needsBlending(const sp<GraphicBuffer>& buffer) const;
-    virtual bool needsBlending() const;
+    virtual bool isOpaque() const;
     virtual bool needsDithering() const     { return mNeedsDithering; }
-    virtual bool needsFiltering() const;
     virtual bool isSecure() const           { return mSecure; }
     virtual bool isProtected() const;
-    virtual sp<Surface> createSurface() const;
     virtual void onRemoved();
 
     // only for debugging
-    inline sp<GraphicBuffer> getBuffer(int i) const {
-        return mBufferManager.getBuffer(i); }
-    // only for debugging
-    inline const sp<FreezeLock>&  getFreezeLock() const {
-        return mFreezeLock; }
+    inline const sp<FreezeLock>&  getFreezeLock() const { return mFreezeLock; }
 
 protected:
-    virtual void destroy() const;
+    virtual void destroy(RefBase const* base);
+    virtual void onFirstRef();
     virtual void dump(String8& result, char* scratch, size_t size) const;
 
 private:
-    void reloadTexture(const Region& dirty);
+    friend class SurfaceTextureLayer;
+    void onFrameQueued();
+    virtual sp<ISurface> createSurface();
     uint32_t getEffectiveUsage(uint32_t usage) const;
-    sp<GraphicBuffer> requestBuffer(int bufferIdx,
-            uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
-    status_t setBufferCount(int bufferCount);
+    void setFixedSize(bool fixedSize);
+    bool isCropped() const;
+    static bool getOpacityForFormat(uint32_t format);
 
     // -----------------------------------------------------------------------
 
-    class SurfaceLayer : public LayerBaseClient::Surface {
-    public:
-        SurfaceLayer(const sp<SurfaceFlinger>& flinger, const sp<Layer>& owner);
-        ~SurfaceLayer();
-    private:
-        virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
-                uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
-        virtual status_t setBufferCount(int bufferCount);
-        sp<Layer> getOwner() const {
-            return static_cast<Layer*>(Surface::getOwner().get());
-        }
-    };
-    friend class SurfaceLayer;
-
-    // -----------------------------------------------------------------------
-
-    class ClientRef {
-        ClientRef(const ClientRef& rhs);
-        ClientRef& operator = (const ClientRef& rhs);
-        mutable Mutex mLock;
-        // binder thread, page-flip thread
-        sp<SharedBufferServer> mControlBlock;
-        wp<UserClient> mUserClient;
-        int32_t mToken;
-    public:
-        ClientRef();
-        ~ClientRef();
-        int32_t getToken() const;
-        sp<UserClient> getClient() const;
-        status_t setToken(const sp<UserClient>& uc,
-                const sp<SharedBufferServer>& sharedClient, int32_t token);
-        sp<UserClient> getUserClientUnsafe() const;
-        class Access {
-            Access(const Access& rhs);
-            Access& operator = (const Access& rhs);
-            sp<UserClient> mUserClientStrongRef;
-            sp<SharedBufferServer> mControlBlock;
-        public:
-            Access(const ClientRef& ref);
-            ~Access();
-            inline SharedBufferServer* get() const { return mControlBlock.get(); }
-        };
-        friend class Access;
-    };
-
-    // -----------------------------------------------------------------------
-
-    class BufferManager {
-        static const size_t NUM_BUFFERS = 2;
-        struct BufferData {
-            sp<GraphicBuffer>   buffer;
-            Image               texture;
-        };
-        // this lock protect mBufferData[].buffer but since there
-        // is very little contention, we have only one like for
-        // the whole array, we also use it to protect mNumBuffers.
-        mutable Mutex mLock;
-        BufferData          mBufferData[SharedBufferStack::NUM_BUFFER_MAX];
-        size_t              mNumBuffers;
-        Texture             mFailoverTexture;
-        TextureManager&     mTextureManager;
-        ssize_t             mActiveBufferIndex;
-        sp<GraphicBuffer>   mActiveBuffer;
-        bool                mFailover;
-        static status_t destroyTexture(Image* tex, EGLDisplay dpy);
-
-    public:
-        static size_t getDefaultBufferCount() { return NUM_BUFFERS; }
-        BufferManager(TextureManager& tm);
-        ~BufferManager();
-
-        // detach/attach buffer from/to given index
-        sp<GraphicBuffer> detachBuffer(size_t index);
-        status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer);
-        // resize the number of active buffers
-        status_t resize(size_t size, const sp<SurfaceFlinger>& flinger,
-                EGLDisplay dpy);
-
-        // ----------------------------------------------
-        // must be called from GL thread
-
-        // set/get active buffer index
-        status_t setActiveBufferIndex(size_t index);
-        size_t getActiveBufferIndex() const;
-        // return the active buffer
-        sp<GraphicBuffer> getActiveBuffer() const;
-        // return wether we have an active buffer
-        bool hasActiveBuffer() const;
-        // return the active texture (or fail-over)
-        Texture getActiveTexture() const;
-        // frees resources associated with all buffers
-        status_t destroy(EGLDisplay dpy);
-        // load bitmap data into the active buffer
-        status_t loadTexture(const Region& dirty, const GGLSurface& t);
-        // make active buffer an EGLImage if needed
-        status_t initEglImage(EGLDisplay dpy,
-                const sp<GraphicBuffer>& buffer);
-
-        // ----------------------------------------------
-        // only for debugging
-        sp<GraphicBuffer> getBuffer(size_t index) const;
-    };
-
-    // -----------------------------------------------------------------------
+    // constants
+    sp<SurfaceTextureLayer> mSurfaceTexture;
+    GLuint mTextureName;
 
     // thread-safe
-    ClientRef mUserClientRef;
+    volatile int32_t mQueuedFrames;
+
+    // main thread
+    sp<GraphicBuffer> mActiveBuffer;
+    GLfloat mTextureMatrix[16];
+    Rect mCurrentCrop;
+    uint32_t mCurrentTransform;
+    bool mCurrentOpacity;
 
     // constants
     PixelFormat mFormat;
     const GLExtensions& mGLExtensions;
-    bool mNeedsBlending;
+    bool mOpaqueLayer;
     bool mNeedsDithering;
 
     // page-flip thread (currently main thread)
@@ -226,18 +122,8 @@
     // page-flip thread and transaction thread (currently main thread)
     sp<FreezeLock>  mFreezeLock;
 
-    // see threading usage in declaration
-    TextureManager mTextureManager;
-    BufferManager mBufferManager;
-
     // binder thread, transaction thread
     mutable Mutex mLock;
-    uint32_t mWidth;
-    uint32_t mHeight;
-    uint32_t mReqWidth;
-    uint32_t mReqHeight;
-    uint32_t mReqFormat;
-    bool mNeedsScaling;
     bool mFixedSize;
 };
 
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 022f251..bcd8c83 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -32,8 +32,6 @@
 #include "LayerBase.h"
 #include "SurfaceFlinger.h"
 #include "DisplayHardware/DisplayHardware.h"
-#include "TextureManager.h"
-
 
 namespace android {
 
@@ -44,7 +42,7 @@
 LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
     : dpy(display), contentDirty(false),
       sequence(uint32_t(android_atomic_inc(&sSequence))),
-      mFlinger(flinger),
+      mFlinger(flinger), mFiltering(false),
       mNeedsFiltering(false),
       mOrientation(0),
       mLeft(0), mTop(0),
@@ -54,8 +52,6 @@
 {
     const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
     mFlags = hw.getFlags();
-    mBufferCrop.makeInvalid();
-    mBufferTransform = 0;
 }
 
 LayerBase::~LayerBase()
@@ -310,6 +306,16 @@
     hwcl->handle = NULL;
 }
 
+void LayerBase::setFiltering(bool filtering)
+{
+    mFiltering = filtering;
+}
+
+bool LayerBase::getFiltering() const
+{
+    return mFiltering;
+}
+
 void LayerBase::draw(const Region& clip) const
 {
     // reset GL state
@@ -318,10 +324,12 @@
     onDraw(clip);
 }
 
-void LayerBase::drawForSreenShot() const
+void LayerBase::drawForSreenShot()
 {
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    setFiltering(true);
     onDraw( Region(hw.bounds()) );
+    setFiltering(false);
 }
 
 void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red,
@@ -332,8 +340,12 @@
     const uint32_t fbHeight = hw.getHeight();
     glColor4f(red,green,blue,alpha);
 
-    TextureManager::deactivateTextures();
-
+#if defined(GL_OES_EGL_image_external)
+        if (GLExtensions::getInstance().haveTextureExternal()) {
+            glDisable(GL_TEXTURE_EXTERNAL_OES);
+        }
+#endif
+    glDisable(GL_TEXTURE_2D);
     glDisable(GL_BLEND);
     glDisable(GL_DITHER);
 
@@ -354,24 +366,11 @@
     clearWithOpenGL(clip,0,0,0,0);
 }
 
-template <typename T>
-static inline
-void swap(T& a, T& b) {
-    T t(a);
-    a = b;
-    b = t;
-}
-
-void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
+void LayerBase::drawWithOpenGL(const Region& clip) const
 {
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     const uint32_t fbHeight = hw.getHeight();
     const State& s(drawingState());
-    
-    // bind our texture
-    TextureManager::activateTexture(texture, needsFiltering());
-    uint32_t width  = texture.width; 
-    uint32_t height = texture.height;
 
     GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
     if (UNLIKELY(s.alpha < 0xFF)) {
@@ -387,7 +386,7 @@
     } else {
         glColor4f(1, 1, 1, 1);
         glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-        if (needsBlending()) {
+        if (!isOpaque()) {
             glEnable(GL_BLEND);
             glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
         } else {
@@ -395,86 +394,20 @@
         }
     }
 
-    /*
-     *  compute texture coordinates
-     *  here, we handle NPOT, cropping and buffer transformations
-     */
-
-    GLfloat cl, ct, cr, cb;
-    if (!mBufferCrop.isEmpty()) {
-        // source is cropped
-        const GLfloat us = (texture.NPOTAdjust ? texture.wScale : 1.0f) / width;
-        const GLfloat vs = (texture.NPOTAdjust ? texture.hScale : 1.0f) / height;
-        cl = mBufferCrop.left   * us;
-        ct = mBufferCrop.top    * vs;
-        cr = mBufferCrop.right  * us;
-        cb = mBufferCrop.bottom * vs;
-    } else {
-        cl = 0;
-        ct = 0;
-        cr = (texture.NPOTAdjust ? texture.wScale : 1.0f);
-        cb = (texture.NPOTAdjust ? texture.hScale : 1.0f);
-    }
-
-    /*
-     * For the buffer transformation, we apply the rotation last.
-     * Since we're transforming the texture-coordinates, we need
-     * to apply the inverse of the buffer transformation:
-     *   inverse( FLIP_V -> FLIP_H -> ROT_90 )
-     *   <=> inverse( ROT_90 * FLIP_H * FLIP_V )
-     *    =  inverse(FLIP_V) * inverse(FLIP_H) * inverse(ROT_90)
-     *    =  FLIP_V * FLIP_H * ROT_270
-     *   <=> ROT_270 -> FLIP_H -> FLIP_V
-     *
-     * The rotation is performed first, in the texture coordinate space.
-     *
-     */
-
     struct TexCoords {
         GLfloat u;
         GLfloat v;
     };
 
-    enum {
-        // name of the corners in the texture map
-        LB = 0, // left-bottom
-        LT = 1, // left-top
-        RT = 2, // right-top
-        RB = 3  // right-bottom
-    };
-
-    // vertices in screen space
-    int vLT = LB;
-    int vLB = LT;
-    int vRB = RT;
-    int vRT = RB;
-
-    // the texture's source is rotated
-    uint32_t transform = mBufferTransform;
-    if (transform & HAL_TRANSFORM_ROT_90) {
-        vLT = RB;
-        vLB = LB;
-        vRB = LT;
-        vRT = RT;
-    }
-    if (transform & HAL_TRANSFORM_FLIP_V) {
-        swap(vLT, vLB);
-        swap(vRT, vRB);
-    }
-    if (transform & HAL_TRANSFORM_FLIP_H) {
-        swap(vLT, vRT);
-        swap(vLB, vRB);
-    }
-
     TexCoords texCoords[4];
-    texCoords[vLT].u = cl;
-    texCoords[vLT].v = ct;
-    texCoords[vLB].u = cl;
-    texCoords[vLB].v = cb;
-    texCoords[vRB].u = cr;
-    texCoords[vRB].v = cb;
-    texCoords[vRT].u = cr;
-    texCoords[vRT].v = ct;
+    texCoords[0].u = 0;
+    texCoords[0].v = 1;
+    texCoords[1].u = 0;
+    texCoords[1].v = 0;
+    texCoords[2].u = 1;
+    texCoords[2].v = 0;
+    texCoords[3].u = 1;
+    texCoords[3].v = 1;
 
     if (needsDithering()) {
         glEnable(GL_DITHER);
@@ -497,20 +430,6 @@
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 }
 
-void LayerBase::setBufferCrop(const Rect& crop) {
-    if (mBufferCrop != crop) {
-        mBufferCrop = crop;
-        mFlinger->invalidateHwcGeometry();
-    }
-}
-
-void LayerBase::setBufferTransform(uint32_t transform) {
-    if (mBufferTransform != transform) {
-        mBufferTransform = transform;
-        mFlinger->invalidateHwcGeometry();
-    }
-}
-
 void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
 {
     const Layer::State& s(drawingState());
@@ -518,10 +437,10 @@
             "+ %s %p\n"
             "      "
             "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), "
-            "needsBlending=%1d, needsDithering=%1d, invalidate=%1d, "
+            "isOpaque=%1d, needsDithering=%1d, invalidate=%1d, "
             "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
             getTypeId(), this, s.z, tx(), ty(), s.w, s.h,
-            needsBlending(), needsDithering(), contentDirty,
+            isOpaque(), needsDithering(), contentDirty,
             s.alpha, s.flags,
             s.transform[0][0], s.transform[0][1],
             s.transform[1][0], s.transform[1][1]);
@@ -555,9 +474,22 @@
     }
 }
 
-sp<LayerBaseClient::Surface> LayerBaseClient::getSurface()
+sp<ISurface> LayerBaseClient::createSurface()
 {
-    sp<Surface> s;
+    class BSurface : public BnSurface, public LayerCleaner {
+        virtual sp<ISurfaceTexture> getSurfaceTexture() const { return 0; }
+    public:
+        BSurface(const sp<SurfaceFlinger>& flinger,
+                const sp<LayerBaseClient>& layer)
+            : LayerCleaner(flinger, layer) { }
+    };
+    sp<ISurface> sur(new BSurface(mFlinger, this));
+    return sur;
+}
+
+sp<ISurface> LayerBaseClient::getSurface()
+{
+    sp<ISurface> s;
     Mutex::Autolock _l(mLock);
 
     LOG_ALWAYS_FATAL_IF(mHasSurface,
@@ -573,12 +505,6 @@
     return mClientSurfaceBinder;
 }
 
-sp<LayerBaseClient::Surface> LayerBaseClient::createSurface() const
-{
-    return new Surface(mFlinger, mIdentity,
-            const_cast<LayerBaseClient *>(this));
-}
-
 void LayerBaseClient::dump(String8& result, char* buffer, size_t SIZE) const
 {
     LayerBase::dump(result, buffer, SIZE);
@@ -601,44 +527,14 @@
 
 // ---------------------------------------------------------------------------
 
-LayerBaseClient::Surface::Surface(
-        const sp<SurfaceFlinger>& flinger,
-        int identity,
-        const sp<LayerBaseClient>& owner) 
-    : mFlinger(flinger), mIdentity(identity), mOwner(owner)
-{
+LayerBaseClient::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger,
+        const sp<LayerBaseClient>& layer)
+    : mFlinger(flinger), mLayer(layer) {
 }
 
-LayerBaseClient::Surface::~Surface() 
-{
-    /*
-     * This is a good place to clean-up all client resources 
-     */
-
+LayerBaseClient::LayerCleaner::~LayerCleaner() {
     // destroy client resources
-    mFlinger->destroySurface(mOwner);
-}
-
-sp<LayerBaseClient> LayerBaseClient::Surface::getOwner() const {
-    sp<LayerBaseClient> owner(mOwner.promote());
-    return owner;
-}
-
-status_t LayerBaseClient::Surface::onTransact(
-        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    return BnSurface::onTransact(code, data, reply, flags);
-}
-
-sp<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int bufferIdx,
-        uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
-{
-    return NULL; 
-}
-
-status_t LayerBaseClient::Surface::setBufferCount(int bufferCount)
-{
-    return INVALID_OPERATION;
+    mFlinger->destroySurface(mLayer);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 6c49a19..faf71dd 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -29,7 +29,6 @@
 #include <ui/Region.h>
 
 #include <surfaceflinger/ISurfaceComposerClient.h>
-#include <private/surfaceflinger/SharedBufferStack.h>
 #include <private/surfaceflinger/LayerState.h>
 
 #include <pixelflinger/pixelflinger.h>
@@ -43,13 +42,12 @@
 
 // ---------------------------------------------------------------------------
 
-class DisplayHardware;
 class Client;
+class DisplayHardware;
 class GraphicBuffer;
 class GraphicPlane;
 class LayerBaseClient;
 class SurfaceFlinger;
-class Texture;
 
 // ---------------------------------------------------------------------------
 
@@ -121,7 +119,7 @@
      * to perform the actual drawing.  
      */
     virtual void draw(const Region& clip) const;
-    virtual void drawForSreenShot() const;
+    virtual void drawForSreenShot();
     
     /**
      * onDraw - draws the surface.
@@ -174,9 +172,9 @@
     virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
     
     /**
-     * needsBlending - true if this surface needs blending
+     * isOpaque - true if this surface is opaque
      */
-    virtual bool needsBlending() const  { return false; }
+    virtual bool isOpaque() const  { return true; }
 
     /**
      * needsDithering - true if this surface needs dithering
@@ -184,11 +182,9 @@
     virtual bool needsDithering() const { return false; }
 
     /**
-     * needsLinearFiltering - true if this surface needs filtering
+     * needsLinearFiltering - true if this surface's state requires filtering
      */
-    virtual bool needsFiltering() const {
-        return (!(mFlags & DisplayHardware::SLOW_CONFIG)) && mNeedsFiltering;
-    }
+    virtual bool needsFiltering() const { return mNeedsFiltering; }
 
     /**
      * isSecure - true if this surface is secure, that is if it prevents
@@ -231,21 +227,25 @@
           void clearWithOpenGL(const Region& clip, GLclampf r, GLclampf g,
                                GLclampf b, GLclampf alpha) const;
           void clearWithOpenGL(const Region& clip) const;
-          void drawWithOpenGL(const Region& clip, const Texture& texture) const;
-          
-          // these must be called from the post/drawing thread
-          void setBufferCrop(const Rect& crop);
-          void setBufferTransform(uint32_t transform);
+          void drawWithOpenGL(const Region& clip) const;
+
+          void setFiltering(bool filtering);
+          bool getFiltering() const;
 
                 sp<SurfaceFlinger> mFlinger;
                 uint32_t        mFlags;
 
-                // post/drawing thread
-                Rect mBufferCrop;
-                uint32_t mBufferTransform;
+private:
+                // accessed only in the main thread
+                // Whether filtering is forced on or not
+                bool            mFiltering;
 
                 // cached during validateVisibility()
+                // Whether filtering is needed b/c of the drawingstate
                 bool            mNeedsFiltering;
+
+protected:
+                // cached during validateVisibility()
                 int32_t         mOrientation;
                 GLfloat         mVertices[4][2];
                 Rect            mTransformedBounds;
@@ -281,52 +281,38 @@
 class LayerBaseClient : public LayerBase
 {
 public:
-    class Surface;
-
             LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
                         const sp<Client>& client);
-    virtual ~LayerBaseClient();
 
-            sp<Surface> getSurface();
+            virtual ~LayerBaseClient();
+
+            sp<ISurface> getSurface();
             wp<IBinder> getSurfaceBinder() const;
-    virtual sp<Surface> createSurface() const;
+
     virtual sp<LayerBaseClient> getLayerBaseClient() const {
         return const_cast<LayerBaseClient*>(this); }
+
     virtual const char* getTypeId() const { return "LayerBaseClient"; }
 
     uint32_t getIdentity() const { return mIdentity; }
 
-    class Surface : public BnSurface  {
-    public:
-        int32_t getIdentity() const { return mIdentity; }
-        
-    protected:
-        Surface(const sp<SurfaceFlinger>& flinger, int identity,
-                const sp<LayerBaseClient>& owner);
-        virtual ~Surface();
-        virtual status_t onTransact(uint32_t code, const Parcel& data,
-                Parcel* reply, uint32_t flags);
-        sp<LayerBaseClient> getOwner() const;
-
-    private:
-        virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
-                uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
-        virtual status_t setBufferCount(int bufferCount);
-
-    protected:
-        friend class LayerBaseClient;
-        sp<SurfaceFlinger>  mFlinger;
-        int32_t             mIdentity;
-        wp<LayerBaseClient> mOwner;
-    };
-
-    friend class Surface;
-
 protected:
     virtual void dump(String8& result, char* scratch, size_t size) const;
     virtual void shortDump(String8& result, char* scratch, size_t size) const;
 
+    class LayerCleaner {
+        sp<SurfaceFlinger> mFlinger;
+        wp<LayerBaseClient> mLayer;
+    protected:
+        ~LayerCleaner();
+    public:
+        LayerCleaner(const sp<SurfaceFlinger>& flinger,
+                const sp<LayerBaseClient>& layer);
+    };
+
 private:
+    virtual sp<ISurface> createSurface();
+
     mutable Mutex mLock;
     mutable bool mHasSurface;
     wp<IBinder> mClientSurfaceBinder;
diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp
index f79166d..654817d 100644
--- a/services/surfaceflinger/LayerDim.cpp
+++ b/services/surfaceflinger/LayerDim.cpp
@@ -65,8 +65,6 @@
             glDisable(GL_TEXTURE_EXTERNAL_OES);
         }
 #endif
-        glDisable(GL_TEXTURE_2D);
-
         glVertexPointer(2, GL_FLOAT, 0, mVertices);
 
         while (it != end) {
diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h
index 75f9a89..8770e6d 100644
--- a/services/surfaceflinger/LayerDim.h
+++ b/services/surfaceflinger/LayerDim.h
@@ -37,7 +37,7 @@
         virtual ~LayerDim();
 
     virtual void onDraw(const Region& clip) const;
-    virtual bool needsBlending() const    { return true; }
+    virtual bool isOpaque() const         { return false; }
     virtual bool isSecure() const         { return false; }
     virtual bool isProtectedByApp() const { return false; }
     virtual bool isProtectedByDRM() const { return false; }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b7a51a4..97edfee 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -53,6 +53,8 @@
 #include "DisplayHardware/DisplayHardware.h"
 #include "DisplayHardware/HWComposer.h"
 
+#include <private/surfaceflinger/SharedBufferStack.h>
+
 /* ideally AID_GRAPHICS would be in a semi-public header
  * or there would be a way to map a user/group name to its id
  */
@@ -133,17 +135,6 @@
     return bclient;
 }
 
-sp<ISurfaceComposerClient> SurfaceFlinger::createClientConnection()
-{
-    sp<ISurfaceComposerClient> bclient;
-    sp<UserClient> client(new UserClient(this));
-    status_t err = client->initCheck();
-    if (err == NO_ERROR) {
-        bclient = client;
-    }
-    return bclient;
-}
-
 sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
 {
     sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
@@ -322,11 +313,6 @@
     mEventQueue.invalidate();
 }
 
-void SurfaceFlinger::signal() const {
-    // this is the IPC call
-    const_cast<SurfaceFlinger*>(this)->signalEvent();
-}
-
 bool SurfaceFlinger::authenticateSurface(const sp<ISurface>& surface) const {
     Mutex::Autolock _l(mStateLock);
     sp<IBinder> surfBinder(surface->asBinder());
@@ -658,7 +644,7 @@
 
         // handle hidden surfaces by setting the visible region to empty
         if (LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) {
-            const bool translucent = layer->needsBlending();
+            const bool translucent = !layer->isOpaque();
             const Rect bounds(layer->visibleBounds());
             visibleRegion.set(bounds);
             visibleRegion.andSelf(screenRegion);
@@ -921,7 +907,7 @@
             for (size_t i=0 ; i<count ; i++) {
                 if (cur[i].hints & HWC_HINT_CLEAR_FB) {
                     const sp<LayerBase>& layer(layers[i]);
-                    if (!(layer->needsBlending())) {
+                    if (layer->isOpaque()) {
                         transparent.orSelf(layer->visibleRegionScreen);
                     }
                 }
@@ -979,8 +965,6 @@
         composeSurfaces(repaint);
     }
 
-    TextureManager::deactivateTextures();
-
     glDisable(GL_BLEND);
     glDisable(GL_DITHER);
     glDisable(GL_SCISSOR_TEST);
@@ -1070,6 +1054,7 @@
             glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
         }
         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+        glDisable(GL_TEXTURE_2D);
         glLoadIdentity();
         glMatrixMode(GL_MODELVIEW);
     }
@@ -1269,7 +1254,7 @@
         uint32_t flags)
 {
     sp<LayerBaseClient> layer;
-    sp<LayerBaseClient::Surface> surfaceHandle;
+    sp<ISurface> surfaceHandle;
 
     if (int32_t(w|h) < 0) {
         LOGE("createSurface() failed, w or h is negative (w=%d, h=%d)",
@@ -1300,13 +1285,13 @@
         surfaceHandle = layer->getSurface();
         if (surfaceHandle != 0) {
             params->token = token;
-            params->identity = surfaceHandle->getIdentity();
+            params->identity = layer->getIdentity();
             params->width = w;
             params->height = h;
             params->format = format;
             if (normalLayer != 0) {
                 Mutex::Autolock _l(mStateLock);
-                mLayerMap.add(surfaceHandle->asBinder(), normalLayer);
+                mLayerMap.add(layer->getSurfaceBinder(), normalLayer);
             }
         }
 
@@ -1782,7 +1767,6 @@
 
     GLfloat vtx[8];
     const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
-    glEnable(GL_TEXTURE_2D);
     glBindTexture(GL_TEXTURE_2D, tname);
     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -1900,6 +1884,7 @@
     glEnable(GL_SCISSOR_TEST);
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
     glDeleteTextures(1, &tname);
+    glDisable(GL_TEXTURE_2D);
     return NO_ERROR;
 }
 
@@ -1930,7 +1915,6 @@
 
     GLfloat vtx[8];
     const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
-    glEnable(GL_TEXTURE_2D);
     glBindTexture(GL_TEXTURE_2D, tname);
     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -2044,6 +2028,7 @@
     glEnable(GL_SCISSOR_TEST);
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
     glDeleteTextures(1, &tname);
+    glDisable(GL_TEXTURE_2D);
 
     return NO_ERROR;
 }
@@ -2408,20 +2393,72 @@
     return lbc;
 }
 
-sp<IMemoryHeap> Client::getControlBlock() const {
-    return 0;
+
+status_t Client::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    // these must be checked
+     IPCThreadState* ipc = IPCThreadState::self();
+     const int pid = ipc->getCallingPid();
+     const int uid = ipc->getCallingUid();
+     const int self_pid = getpid();
+     if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) {
+         // we're called from a different process, do the real check
+         if (!checkCallingPermission(
+                 String16("android.permission.ACCESS_SURFACE_FLINGER")))
+         {
+             LOGE("Permission Denial: "
+                     "can't openGlobalTransaction pid=%d, uid=%d", pid, uid);
+             return PERMISSION_DENIED;
+         }
+     }
+     return BnSurfaceComposerClient::onTransact(code, data, reply, flags);
 }
-ssize_t Client::getTokenForSurface(const sp<ISurface>& sur) const {
-    return -1;
-}
+
+
 sp<ISurface> Client::createSurface(
         ISurfaceComposerClient::surface_data_t* params,
         const String8& name,
         DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
         uint32_t flags)
 {
-    return mFlinger->createSurface(params, name, this,
-            display, w, h, format, flags);
+    /*
+     * createSurface must be called from the GL thread so that it can
+     * have access to the GL context.
+     */
+
+    class MessageCreateSurface : public MessageBase {
+        sp<ISurface> result;
+        SurfaceFlinger* flinger;
+        ISurfaceComposerClient::surface_data_t* params;
+        Client* client;
+        const String8& name;
+        DisplayID display;
+        uint32_t w, h;
+        PixelFormat format;
+        uint32_t flags;
+    public:
+        MessageCreateSurface(SurfaceFlinger* flinger,
+                ISurfaceComposerClient::surface_data_t* params,
+                const String8& name, Client* client,
+                DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
+                uint32_t flags)
+            : flinger(flinger), params(params), client(client), name(name),
+              display(display), w(w), h(h), format(format), flags(flags)
+        {
+        }
+        sp<ISurface> getResult() const { return result; }
+        virtual bool handler() {
+            result = flinger->createSurface(params, name, client,
+                    display, w, h, format, flags);
+            return true;
+        }
+    };
+
+    sp<MessageBase> msg = new MessageCreateSurface(mFlinger.get(),
+            params, name, this, display, w, h, format, flags);
+    mFlinger->postMessageSync(msg);
+    return static_cast<MessageCreateSurface*>( msg.get() )->getResult();
 }
 status_t Client::destroySurface(SurfaceID sid) {
     return mFlinger->removeSurface(this, sid);
@@ -2432,113 +2469,6 @@
 
 // ---------------------------------------------------------------------------
 
-UserClient::UserClient(const sp<SurfaceFlinger>& flinger)
-    : ctrlblk(0), mBitmap(0), mFlinger(flinger)
-{
-    const int pgsize = getpagesize();
-    const int cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1));
-
-    mCblkHeap = new MemoryHeapBase(cblksize, 0,
-            "SurfaceFlinger Client control-block");
-
-    ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase());
-    if (ctrlblk) { // construct the shared structure in-place.
-        new(ctrlblk) SharedClient;
-    }
-}
-
-UserClient::~UserClient()
-{
-    if (ctrlblk) {
-        ctrlblk->~SharedClient();  // destroy our shared-structure.
-    }
-
-    /*
-     * When a UserClient dies, it's unclear what to do exactly.
-     * We could go ahead and destroy all surfaces linked to that client
-     * however, it wouldn't be fair to the main Client
-     * (usually the the window-manager), which might want to re-target
-     * the layer to another UserClient.
-     * I think the best is to do nothing, or not much; in most cases the
-     * WM itself will go ahead and clean things up when it detects a client of
-     * his has died.
-     * The remaining question is what to display? currently we keep
-     * just keep the current buffer.
-     */
-}
-
-status_t UserClient::initCheck() const {
-    return ctrlblk == 0 ? NO_INIT : NO_ERROR;
-}
-
-void UserClient::detachLayer(const Layer* layer)
-{
-    int32_t name = layer->getToken();
-    if (name >= 0) {
-        int32_t mask = 1LU<<name;
-        if ((android_atomic_and(~mask, &mBitmap) & mask) == 0) {
-            LOGW("token %d wasn't marked as used %08x", name, int(mBitmap));
-        }
-    }
-}
-
-sp<IMemoryHeap> UserClient::getControlBlock() const {
-    return mCblkHeap;
-}
-
-ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const
-{
-    int32_t name = NAME_NOT_FOUND;
-    sp<Layer> layer(mFlinger->getLayer(sur));
-    if (layer == 0) {
-        return name;
-    }
-
-    // if this layer already has a token, just return it
-    name = layer->getToken();
-    if ((name >= 0) && (layer->getClient() == this)) {
-        return name;
-    }
-
-    name = 0;
-    do {
-        int32_t mask = 1LU<<name;
-        if ((android_atomic_or(mask, &mBitmap) & mask) == 0) {
-            // we found and locked that name
-            status_t err = layer->setToken(
-                    const_cast<UserClient*>(this), ctrlblk, name);
-            if (err != NO_ERROR) {
-                // free the name
-                android_atomic_and(~mask, &mBitmap);
-                name = err;
-            }
-            break;
-        }
-        if (++name >= int32_t(SharedBufferStack::NUM_LAYERS_MAX))
-            name = NO_MEMORY;
-    } while(name >= 0);
-
-    //LOGD("getTokenForSurface(%p) => %d (client=%p, bitmap=%08lx)",
-    //        sur->asBinder().get(), name, this, mBitmap);
-    return name;
-}
-
-sp<ISurface> UserClient::createSurface(
-        ISurfaceComposerClient::surface_data_t* params,
-        const String8& name,
-        DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
-        uint32_t flags) {
-    return 0;
-}
-status_t UserClient::destroySurface(SurfaceID sid) {
-    return INVALID_OPERATION;
-}
-status_t UserClient::setState(int32_t count, const layer_state_t* states) {
-    return INVALID_OPERATION;
-}
-
-// ---------------------------------------------------------------------------
-
 GraphicBufferAlloc::GraphicBufferAlloc() {}
 
 GraphicBufferAlloc::~GraphicBufferAlloc() {}
@@ -2547,11 +2477,11 @@
         PixelFormat format, uint32_t usage) {
     sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
     status_t err = graphicBuffer->initCheck();
-    if (err != 0) {
-        LOGE("createGraphicBuffer: init check failed: %d", err);
-        return 0;
-    } else if (graphicBuffer->handle == 0) {
-        LOGE("createGraphicBuffer: unable to create GraphicBuffer");
+    if (err != 0 || graphicBuffer->handle == 0) {
+        GraphicBuffer::dumpAllocationsToSystemLog();
+        LOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) "
+             "failed (%s), handle=%p",
+                w, h, strerror(-err), graphicBuffer->handle);
         return 0;
     }
     return graphicBuffer;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 992861a..af1ef04 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -50,6 +50,7 @@
 class FreezeLock;
 class Layer;
 class LayerDim;
+struct surface_flinger_cblk_t;
 
 #define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
 #define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
@@ -72,14 +73,14 @@
 private:
 
     // ISurfaceComposerClient interface
-    virtual sp<IMemoryHeap> getControlBlock() const;
-    virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const;
     virtual sp<ISurface> createSurface(
             surface_data_t* params, const String8& name,
             DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
             uint32_t flags);
     virtual status_t destroySurface(SurfaceID surfaceId);
     virtual status_t setState(int32_t count, const layer_state_t* states);
+    virtual status_t onTransact(
+        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
 
     // constant
     sp<SurfaceFlinger> mFlinger;
@@ -92,40 +93,6 @@
     mutable Mutex mLock;
 };
 
-class UserClient : public BnSurfaceComposerClient
-{
-public:
-    // pointer to this client's control block
-    SharedClient* ctrlblk;
-
-public:
-        UserClient(const sp<SurfaceFlinger>& flinger);
-        ~UserClient();
-
-    status_t initCheck() const;
-
-    // protected by SurfaceFlinger::mStateLock
-    void detachLayer(const Layer* layer);
-
-private:
-
-    // ISurfaceComposerClient interface
-    virtual sp<IMemoryHeap> getControlBlock() const;
-    virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const;
-    virtual sp<ISurface> createSurface(
-            surface_data_t* params, const String8& name,
-            DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
-            uint32_t flags);
-    virtual status_t destroySurface(SurfaceID surfaceId);
-    virtual status_t setState(int32_t count, const layer_state_t* states);
-
-    // atomic-ops
-    mutable volatile int32_t mBitmap;
-
-    sp<IMemoryHeap> mCblkHeap;
-    sp<SurfaceFlinger> mFlinger;
-};
-
 class GraphicBufferAlloc : public BnGraphicBufferAlloc
 {
 public:
@@ -199,7 +166,6 @@
 
     // ISurfaceComposer interface
     virtual sp<ISurfaceComposerClient>  createConnection();
-    virtual sp<ISurfaceComposerClient>  createClientConnection();
     virtual sp<IGraphicBufferAlloc>     createGraphicBufferAlloc();
     virtual sp<IMemoryHeap>             getCblk() const;
     virtual void                        bootFinished();
@@ -208,7 +174,6 @@
     virtual status_t                    freezeDisplay(DisplayID dpy, uint32_t flags);
     virtual status_t                    unfreezeDisplay(DisplayID dpy, uint32_t flags);
     virtual int                         setOrientation(DisplayID dpy, int orientation, uint32_t flags);
-    virtual void                        signal() const;
     virtual bool                        authenticateSurface(const sp<ISurface>& surface) const;
 
     virtual status_t captureScreen(DisplayID dpy,
@@ -235,7 +200,6 @@
     friend class Client;
     friend class LayerBase;
     friend class LayerBaseClient;
-    friend class LayerBaseClient::Surface;
     friend class Layer;
     friend class LayerDim;
 
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
new file mode 100644
index 0000000..60fa965
--- /dev/null
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include "Layer.h"
+#include "SurfaceTextureLayer.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+
+SurfaceTextureLayer::SurfaceTextureLayer(GLuint tex, const sp<Layer>& layer)
+    : SurfaceTexture(tex), mLayer(layer) {
+}
+
+SurfaceTextureLayer::~SurfaceTextureLayer() {
+}
+
+
+status_t SurfaceTextureLayer::setDefaultBufferSize(uint32_t w, uint32_t h)
+{
+    //LOGD("%s, w=%u, h=%u", __PRETTY_FUNCTION__, w, h);
+    return SurfaceTexture::setDefaultBufferSize(w, h);
+}
+
+status_t SurfaceTextureLayer::setDefaultBufferFormat(uint32_t format)
+{
+    mDefaultFormat = format;
+    return NO_ERROR;
+}
+
+status_t SurfaceTextureLayer::setBufferCount(int bufferCount) {
+    status_t res = SurfaceTexture::setBufferCount(bufferCount);
+    return res;
+}
+
+status_t SurfaceTextureLayer::dequeueBuffer(int *buf,
+        uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
+
+    status_t res(NO_INIT);
+    sp<Layer> layer(mLayer.promote());
+    if (layer != NULL) {
+        if (format == 0)
+            format = mDefaultFormat;
+        uint32_t effectiveUsage = layer->getEffectiveUsage(usage);
+        //LOGD("%s, w=%u, h=%u, format=%u, usage=%08x, effectiveUsage=%08x",
+        //        __PRETTY_FUNCTION__, w, h, format, usage, effectiveUsage);
+        res = SurfaceTexture::dequeueBuffer(buf, w, h, format, effectiveUsage);
+        if (res == NO_ERROR) {
+            layer->setFixedSize(w && h);
+        }
+    }
+    return res;
+}
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/services/surfaceflinger/SurfaceTextureLayer.h b/services/surfaceflinger/SurfaceTextureLayer.h
new file mode 100644
index 0000000..7faff54
--- /dev/null
+++ b/services/surfaceflinger/SurfaceTextureLayer.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SURFACE_TEXTURE_LAYER_H
+#define ANDROID_SURFACE_TEXTURE_LAYER_H
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <gui/SurfaceTexture.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class Layer;
+
+class SurfaceTextureLayer : public SurfaceTexture
+{
+    wp<Layer> mLayer;
+    uint32_t mDefaultFormat;
+
+public:
+    SurfaceTextureLayer(GLuint tex, const sp<Layer>& layer);
+    ~SurfaceTextureLayer();
+
+    status_t setDefaultBufferSize(uint32_t w, uint32_t h);
+    status_t setDefaultBufferFormat(uint32_t format);
+
+public:
+    virtual status_t setBufferCount(int bufferCount);
+
+protected:
+    virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
+            uint32_t format, uint32_t usage);
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SURFACE_TEXTURE_LAYER_H
diff --git a/services/surfaceflinger/clz.h b/services/surfaceflinger/clz.h
index 0ddf986..ca445553 100644
--- a/services/surfaceflinger/clz.h
+++ b/services/surfaceflinger/clz.h
@@ -20,18 +20,10 @@
 
 namespace android {
 
-int clz_impl(int32_t x);
-
-int inline clz(int32_t x)
-{
-#if defined(__arm__) && !defined(__thumb__)
+int inline clz(int32_t x) {
     return __builtin_clz(x);
-#else
-    return clz_impl(x);
-#endif
 }
 
-
 }; // namespace android
 
 #endif /* ANDROID_SURFACE_FLINGER_CLZ_H */
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 295d569..151fde7 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -26,6 +26,8 @@
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
     <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
+    <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
+    <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 6552cdf..476aded 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -16,10 +16,15 @@
 
 package com.android.server;
 
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_PAID_BACKGROUND;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_PAID;
+import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
+import static android.net.NetworkStats.UID_ALL;
+import static android.net.TrafficStats.TEMPLATE_WIFI;
 import static org.easymock.EasyMock.capture;
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.eq;
@@ -31,20 +36,30 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
+import android.net.IConnectivityManager;
 import android.net.INetworkPolicyListener;
 import android.net.INetworkStatsService;
+import android.net.LinkProperties;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkPolicy;
+import android.net.NetworkState;
+import android.net.NetworkStats;
 import android.os.Binder;
 import android.os.IPowerManager;
 import android.test.AndroidTestCase;
 import android.test.mock.MockPackageManager;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.Suppress;
+import android.text.format.Time;
+import android.util.TrustedTime;
 
 import com.android.server.net.NetworkPolicyManagerService;
 
 import org.easymock.Capture;
 import org.easymock.EasyMock;
 
+import java.io.File;
 import java.util.concurrent.Future;
 
 /**
@@ -54,12 +69,18 @@
 public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
     private static final String TAG = "NetworkPolicyManagerServiceTest";
 
+    private static final long TEST_START = 1194220800000L;
+    private static final String TEST_IFACE = "test0";
+
     private BroadcastInterceptingContext mServiceContext;
+    private File mPolicyDir;
 
     private IActivityManager mActivityManager;
     private IPowerManager mPowerManager;
     private INetworkStatsService mStatsService;
     private INetworkPolicyListener mPolicyListener;
+    private TrustedTime mTime;
+    private IConnectivityManager mConnManager;
 
     private NetworkPolicyManagerService mService;
     private IProcessObserver mProcessObserver;
@@ -90,13 +111,18 @@
             }
         };
 
+        mPolicyDir = getContext().getFilesDir();
+
         mActivityManager = createMock(IActivityManager.class);
         mPowerManager = createMock(IPowerManager.class);
         mStatsService = createMock(INetworkStatsService.class);
         mPolicyListener = createMock(INetworkPolicyListener.class);
+        mTime = createMock(TrustedTime.class);
+        mConnManager = createMock(IConnectivityManager.class);
 
         mService = new NetworkPolicyManagerService(
-                mServiceContext, mActivityManager, mPowerManager, mStatsService);
+                mServiceContext, mActivityManager, mPowerManager, mStatsService, mTime, mPolicyDir);
+        mService.bindConnectivityManager(mConnManager);
 
         // RemoteCallbackList needs a binder to use as key
         expect(mPolicyListener.asBinder()).andReturn(mStubBinder).atLeastOnce();
@@ -122,12 +148,18 @@
 
     @Override
     public void tearDown() throws Exception {
+        for (File file : mPolicyDir.listFiles()) {
+            file.delete();
+        }
+
         mServiceContext = null;
+        mPolicyDir = null;
 
         mActivityManager = null;
         mPowerManager = null;
         mStatsService = null;
         mPolicyListener = null;
+        mTime = null;
 
         mService = null;
         mProcessObserver = null;
@@ -260,17 +292,124 @@
         verifyAndReset();
     }
 
+    public void testLastCycleBoundaryThisMonth() throws Exception {
+        // assume cycle day of "5th", which should be in same month
+        final long currentTime = parseTime("2007-11-14T00:00:00.000Z");
+        final long expectedCycle = parseTime("2007-11-05T00:00:00.000Z");
+
+        final NetworkPolicy policy = new NetworkPolicy(TEMPLATE_WIFI, null, 5, 1024L, 1024L);
+        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
+        assertEquals(expectedCycle, actualCycle);
+    }
+
+    public void testLastCycleBoundaryLastMonth() throws Exception {
+        // assume cycle day of "20th", which should be in last month
+        final long currentTime = parseTime("2007-11-14T00:00:00.000Z");
+        final long expectedCycle = parseTime("2007-10-20T00:00:00.000Z");
+
+        final NetworkPolicy policy = new NetworkPolicy(TEMPLATE_WIFI, null, 20, 1024L, 1024L);
+        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
+        assertEquals(expectedCycle, actualCycle);
+    }
+
+    public void testLastCycleBoundaryThisMonthFebruary() throws Exception {
+        // assume cycle day of "30th" in february; should go to january
+        final long currentTime = parseTime("2007-02-14T00:00:00.000Z");
+        final long expectedCycle = parseTime("2007-01-30T00:00:00.000Z");
+
+        final NetworkPolicy policy = new NetworkPolicy(TEMPLATE_WIFI, null, 30, 1024L, 1024L);
+        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
+        assertEquals(expectedCycle, actualCycle);
+    }
+
+    public void testLastCycleBoundaryLastMonthFebruary() throws Exception {
+        // assume cycle day of "30th" in february, which should clamp
+        final long currentTime = parseTime("2007-03-14T00:00:00.000Z");
+        final long expectedCycle = parseTime("2007-03-01T00:00:00.000Z");
+
+        final NetworkPolicy policy = new NetworkPolicy(TEMPLATE_WIFI, null, 30, 1024L, 1024L);
+        final long actualCycle = computeLastCycleBoundary(currentTime, policy);
+        assertEquals(expectedCycle, actualCycle);
+    }
+
+    public void testNetworkPolicyAppliedCycleLastMonth() throws Exception {
+        long elapsedRealtime = 0;
+        NetworkState[] state = null;
+        NetworkStats stats = null;
+
+        final long TIME_FEB_15 = 1171497600000L;
+        final long TIME_MAR_10 = 1173484800000L;
+        final int CYCLE_DAY = 15;
+
+        // first, pretend that wifi network comes online. no policy active,
+        // which means we shouldn't push limit to interface.
+        state = new NetworkState[] { buildWifi() };
+        expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
+        expectTime(TIME_MAR_10 + elapsedRealtime);
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+        verifyAndReset();
+
+        // now change cycle to be on 15th, and test in early march, to verify we
+        // pick cycle day in previous month.
+        expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
+        expectTime(TIME_MAR_10 + elapsedRealtime);
+
+        // pretend that 512 bytes total have happened
+        stats = new NetworkStats(elapsedRealtime, 1)
+                .addEntry(TEST_IFACE, UID_ALL, 256L, 256L);
+        expect(mStatsService.getSummaryForNetwork(TIME_FEB_15, TIME_MAR_10, TEMPLATE_WIFI, null))
+                .andReturn(stats).atLeastOnce();
+
+        // expect that quota remaining should be 1536 bytes
+        // TODO: write up NetworkManagementService mock
+
+        replay();
+        setNetworkPolicies(new NetworkPolicy(TEMPLATE_WIFI, null, CYCLE_DAY, 1024L, 2048L));
+        verifyAndReset();
+    }
+
+    private static long parseTime(String time) {
+        final Time result = new Time();
+        result.parse3339(time);
+        return result.toMillis(true);
+    }
+
+    private void setNetworkPolicies(NetworkPolicy... policies) {
+        mService.setNetworkPolicies(policies);
+    }
+
+    private static NetworkState buildWifi() {
+        final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
+        info.setDetailedState(DetailedState.CONNECTED, null, null);
+        final LinkProperties prop = new LinkProperties();
+        prop.setInterfaceName(TEST_IFACE);
+        return new NetworkState(info, prop, null);
+    }
+
+    public void expectTime(long currentTime) throws Exception {
+        expect(mTime.forceRefresh()).andReturn(false).anyTimes();
+        expect(mTime.hasCache()).andReturn(true).anyTimes();
+        expect(mTime.currentTimeMillis()).andReturn(currentTime).anyTimes();
+        expect(mTime.getCacheAge()).andReturn(0L).anyTimes();
+        expect(mTime.getCacheCertainty()).andReturn(0L).anyTimes();
+    }
+
     private void expectRulesChanged(int uid, int policy) throws Exception {
         mPolicyListener.onRulesChanged(eq(uid), eq(policy));
         expectLastCall().atLeastOnce();
     }
 
     private void replay() {
-        EasyMock.replay(mActivityManager, mPowerManager, mStatsService, mPolicyListener);
+        EasyMock.replay(mActivityManager, mPowerManager, mStatsService, mPolicyListener, mTime,
+                mConnManager);
     }
 
     private void verifyAndReset() {
-        EasyMock.verify(mActivityManager, mPowerManager, mStatsService, mPolicyListener);
-        EasyMock.reset(mActivityManager, mPowerManager, mStatsService, mPolicyListener);
+        EasyMock.verify(mActivityManager, mPowerManager, mStatsService, mPolicyListener, mTime,
+                mConnManager);
+        EasyMock.reset(mActivityManager, mPowerManager, mStatsService, mPolicyListener, mTime,
+                mConnManager);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 9846372..2457ff3 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -18,10 +18,13 @@
 
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
 import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.NetworkStats.IFACE_ALL;
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.TrafficStats.TEMPLATE_WIFI;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+import static android.text.format.DateUtils.WEEK_IN_MILLIS;
 import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
 import static org.easymock.EasyMock.anyLong;
 import static org.easymock.EasyMock.createMock;
@@ -47,6 +50,7 @@
 import android.util.TrustedTime;
 
 import com.android.server.net.NetworkStatsService;
+import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
 
 import org.easymock.EasyMock;
 
@@ -62,12 +66,16 @@
     private static final String TEST_IFACE = "test0";
     private static final long TEST_START = 1194220800000L;
 
+    private static final int TEST_UID_1 = 1001;
+    private static final int TEST_UID_2 = 1002;
+
     private BroadcastInterceptingContext mServiceContext;
     private File mStatsDir;
 
     private INetworkManagementService mNetManager;
     private IAlarmManager mAlarmManager;
     private TrustedTime mTime;
+    private NetworkStatsSettings mSettings;
     private IConnectivityManager mConnManager;
 
     private NetworkStatsService mService;
@@ -82,12 +90,14 @@
         mNetManager = createMock(INetworkManagementService.class);
         mAlarmManager = createMock(IAlarmManager.class);
         mTime = createMock(TrustedTime.class);
+        mSettings = createMock(NetworkStatsSettings.class);
         mConnManager = createMock(IConnectivityManager.class);
 
         mService = new NetworkStatsService(
-                mServiceContext, mNetManager, mAlarmManager, mTime, mStatsDir);
+                mServiceContext, mNetManager, mAlarmManager, mTime, mStatsDir, mSettings);
         mService.bindConnectivityManager(mConnManager);
 
+        expectDefaultSettings();
         expectSystemReady();
 
         replay();
@@ -114,115 +124,93 @@
         super.tearDown();
     }
 
-    private static NetworkState buildWifi() {
-        final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
-        info.setDetailedState(DetailedState.CONNECTED, null, null);
-        final LinkProperties prop = new LinkProperties();
-        prop.setInterfaceName(TEST_IFACE);
-        return new NetworkState(info, prop, null);
-    }
-
-    public void testHistoryForWifi() throws Exception {
+    public void testSummaryStatsWifi() throws Exception {
         long elapsedRealtime = 0;
-        NetworkState[] state = null;
-        NetworkStats stats = null;
-        NetworkStats detail = null;
 
         // pretend that wifi network comes online; service should ask about full
         // network state, and poll any existing interfaces before updating.
-        state = new NetworkState[] { buildWifi() };
-        stats = new NetworkStats.Builder(elapsedRealtime, 0).build();
-        detail = new NetworkStats.Builder(elapsedRealtime, 0).build();
-
-        expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
-        expect(mNetManager.getNetworkStatsSummary()).andReturn(stats).atLeastOnce();
-        expect(mNetManager.getNetworkStatsDetail()).andReturn(detail).atLeastOnce();
         expectTime(TEST_START + elapsedRealtime);
+        expectDefaultSettings();
+        expectNetworkState(buildWifiState());
+        expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
 
         replay();
         mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
-        verifyAndReset();
 
         // verify service has empty history for wifi
         assertNetworkTotal(TEMPLATE_WIFI, 0L, 0L);
+        verifyAndReset();
 
         // modify some number on wifi, and trigger poll event
         elapsedRealtime += HOUR_IN_MILLIS;
-        stats = new NetworkStats.Builder(elapsedRealtime, 1).addEntry(
-                TEST_IFACE, UID_ALL, 1024L, 2048L).build();
-
-        expect(mNetManager.getNetworkStatsSummary()).andReturn(stats).atLeastOnce();
-        expect(mNetManager.getNetworkStatsDetail()).andReturn(detail).atLeastOnce();
         expectTime(TEST_START + elapsedRealtime);
+        expectDefaultSettings();
+        expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
+                .addEntry(TEST_IFACE, UID_ALL, 1024L, 2048L));
+        expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime));
 
         replay();
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
-        verifyAndReset();
 
         // verify service recorded history
         assertNetworkTotal(TEMPLATE_WIFI, 1024L, 2048L);
+        verifyAndReset();
 
         // and bump forward again, with counters going higher. this is
         // important, since polling should correctly subtract last snapshot.
         elapsedRealtime += DAY_IN_MILLIS;
-        stats = new NetworkStats.Builder(elapsedRealtime, 1).addEntry(
-                TEST_IFACE, UID_ALL, 4096L, 8192L).build();
-
-        expect(mNetManager.getNetworkStatsSummary()).andReturn(stats).atLeastOnce();
-        expect(mNetManager.getNetworkStatsDetail()).andReturn(detail).atLeastOnce();
         expectTime(TEST_START + elapsedRealtime);
+        expectDefaultSettings();
+        expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
+                .addEntry(TEST_IFACE, UID_ALL, 4096L, 8192L));
+        expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime));
 
         replay();
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
-        verifyAndReset();
 
         // verify service recorded history
         assertNetworkTotal(TEMPLATE_WIFI, 4096L, 8192L);
+        verifyAndReset();
+
     }
 
-    public void testHistoryForRebootPersist() throws Exception {
+    public void testStatsRebootPersist() throws Exception {
         long elapsedRealtime = 0;
-        NetworkState[] state = null;
-        NetworkStats stats = null;
-        NetworkStats detail = null;
-
-        // assert that no stats file exists
-        final File statsFile = new File(mStatsDir, "netstats.bin");
-        assertFalse(statsFile.exists());
+        assertStatsFilesExist(false);
 
         // pretend that wifi network comes online; service should ask about full
         // network state, and poll any existing interfaces before updating.
-        state = new NetworkState[] { buildWifi() };
-        stats = new NetworkStats.Builder(elapsedRealtime, 0).build();
-        detail = new NetworkStats.Builder(elapsedRealtime, 0).build();
-
-        expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
-        expect(mNetManager.getNetworkStatsSummary()).andReturn(stats).atLeastOnce();
-        expect(mNetManager.getNetworkStatsDetail()).andReturn(detail).atLeastOnce();
         expectTime(TEST_START + elapsedRealtime);
+        expectDefaultSettings();
+        expectNetworkState(buildWifiState());
+        expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
 
         replay();
         mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
-        verifyAndReset();
 
         // verify service has empty history for wifi
         assertNetworkTotal(TEMPLATE_WIFI, 0L, 0L);
+        verifyAndReset();
 
         // modify some number on wifi, and trigger poll event
         elapsedRealtime += HOUR_IN_MILLIS;
-        stats = new NetworkStats.Builder(elapsedRealtime, 1).addEntry(
-                TEST_IFACE, UID_ALL, 1024L, 2048L).build();
-
-        expect(mNetManager.getNetworkStatsSummary()).andReturn(stats).atLeastOnce();
-        expect(mNetManager.getNetworkStatsDetail()).andReturn(detail).atLeastOnce();
         expectTime(TEST_START + elapsedRealtime);
+        expectDefaultSettings();
+        expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
+                .addEntry(TEST_IFACE, UID_ALL, 1024L, 2048L));
+        // TODO: switch these stats to specific iface
+        expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 2)
+                .addEntry(IFACE_ALL, TEST_UID_1, 512L, 256L)
+                .addEntry(IFACE_ALL, TEST_UID_2, 128L, 128L));
 
         replay();
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
-        verifyAndReset();
 
         // verify service recorded history
         assertNetworkTotal(TEMPLATE_WIFI, 1024L, 2048L);
+        assertUidTotal(TEST_UID_1, TEMPLATE_WIFI, 512L, 256L);
+        assertUidTotal(TEST_UID_2, TEMPLATE_WIFI, 128L, 128L);
+        verifyAndReset();
 
         // graceful shutdown system, which should trigger persist of stats, and
         // clear any values in memory.
@@ -230,18 +218,84 @@
 
         // talk with zombie service to assert stats have gone; and assert that
         // we persisted them to file.
+        expectDefaultSettings();
+        replay();
         assertNetworkTotal(TEMPLATE_WIFI, 0L, 0L);
-        assertTrue(statsFile.exists());
+        verifyAndReset();
+
+        assertStatsFilesExist(true);
 
         // boot through serviceReady() again
+        expectDefaultSettings();
         expectSystemReady();
 
         replay();
         mService.systemReady();
-        verifyAndReset();
 
         // after systemReady(), we should have historical stats loaded again
         assertNetworkTotal(TEMPLATE_WIFI, 1024L, 2048L);
+        assertUidTotal(TEST_UID_1, TEMPLATE_WIFI, 512L, 256L);
+        assertUidTotal(TEST_UID_2, TEMPLATE_WIFI, 128L, 128L);
+        verifyAndReset();
+
+    }
+
+    public void testStatsBucketResize() throws Exception {
+        long elapsedRealtime = 0;
+        NetworkStatsHistory history = null;
+        long[] total = null;
+
+        assertStatsFilesExist(false);
+
+        // pretend that wifi network comes online; service should ask about full
+        // network state, and poll any existing interfaces before updating.
+        expectTime(TEST_START + elapsedRealtime);
+        expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
+        expectNetworkState(buildWifiState());
+        expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+        verifyAndReset();
+
+        // modify some number on wifi, and trigger poll event
+        elapsedRealtime += 2 * HOUR_IN_MILLIS;
+        expectTime(TEST_START + elapsedRealtime);
+        expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
+        expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
+                .addEntry(TEST_IFACE, UID_ALL, 512L, 512L));
+        expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime));
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+
+        // verify service recorded history
+        history = mService.getHistoryForNetwork(TEMPLATE_WIFI);
+        total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null);
+        assertEquals(512L, total[0]);
+        assertEquals(512L, total[1]);
+        assertEquals(HOUR_IN_MILLIS, history.bucketDuration);
+        assertEquals(2, history.bucketCount);
+        verifyAndReset();
+
+        // now change bucket duration setting and trigger another poll with
+        // exact same values, which should resize existing buckets.
+        expectTime(TEST_START + elapsedRealtime);
+        expectSettings(0L, 30 * MINUTE_IN_MILLIS, WEEK_IN_MILLIS);
+        expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
+        expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime));
+
+        replay();
+        mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+
+        // verify identical stats, but spread across 4 buckets now
+        history = mService.getHistoryForNetwork(TEMPLATE_WIFI);
+        total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null);
+        assertEquals(512L, total[0]);
+        assertEquals(512L, total[1]);
+        assertEquals(30 * MINUTE_IN_MILLIS, history.bucketDuration);
+        assertEquals(4, history.bucketCount);
+        verifyAndReset();
 
     }
 
@@ -252,6 +306,13 @@
         assertEquals(tx, total[1]);
     }
 
+    private void assertUidTotal(int uid, int template, long rx, long tx) {
+        final NetworkStatsHistory history = mService.getHistoryForUid(uid, template);
+        final long[] total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null);
+        assertEquals(rx, total[0]);
+        assertEquals(tx, total[1]);
+    }
+
     private void expectSystemReady() throws Exception {
         mAlarmManager.remove(isA(PendingIntent.class));
         expectLastCall().anyTimes();
@@ -261,7 +322,34 @@
         expectLastCall().atLeastOnce();
     }
 
-    public void expectTime(long currentTime) throws Exception {
+    private void expectNetworkState(NetworkState... state) throws Exception {
+        expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
+    }
+
+    private void expectNetworkStatsSummary(NetworkStats summary) throws Exception {
+        expect(mNetManager.getNetworkStatsSummary()).andReturn(summary).atLeastOnce();
+    }
+
+    private void expectNetworkStatsDetail(NetworkStats detail) throws Exception {
+        expect(mNetManager.getNetworkStatsDetail()).andReturn(detail).atLeastOnce();
+    }
+
+    private void expectDefaultSettings() throws Exception {
+        expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
+    }
+
+    private void expectSettings(long persistThreshold, long bucketDuration, long maxHistory)
+            throws Exception {
+        expect(mSettings.getPollInterval()).andReturn(HOUR_IN_MILLIS).anyTimes();
+        expect(mSettings.getPersistThreshold()).andReturn(persistThreshold).anyTimes();
+        expect(mSettings.getNetworkBucketDuration()).andReturn(bucketDuration).anyTimes();
+        expect(mSettings.getNetworkMaxHistory()).andReturn(maxHistory).anyTimes();
+        expect(mSettings.getUidBucketDuration()).andReturn(bucketDuration).anyTimes();
+        expect(mSettings.getUidMaxHistory()).andReturn(maxHistory).anyTimes();
+        expect(mSettings.getTimeCacheMaxAge()).andReturn(DAY_IN_MILLIS).anyTimes();
+    }
+
+    private void expectTime(long currentTime) throws Exception {
         expect(mTime.forceRefresh()).andReturn(false).anyTimes();
         expect(mTime.hasCache()).andReturn(true).anyTimes();
         expect(mTime.currentTimeMillis()).andReturn(currentTime).anyTimes();
@@ -269,12 +357,36 @@
         expect(mTime.getCacheCertainty()).andReturn(0L).anyTimes();
     }
 
+    private void assertStatsFilesExist(boolean exist) {
+        final File summaryFile = new File(mStatsDir, "netstats.bin");
+        final File detailFile = new File(mStatsDir, "netstats_uid.bin");
+        if (exist) {
+            assertTrue(summaryFile.exists());
+            assertTrue(detailFile.exists());
+        } else {
+            assertFalse(summaryFile.exists());
+            assertFalse(detailFile.exists());
+        }
+    }
+
+    private static NetworkState buildWifiState() {
+        final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
+        info.setDetailedState(DetailedState.CONNECTED, null, null);
+        final LinkProperties prop = new LinkProperties();
+        prop.setInterfaceName(TEST_IFACE);
+        return new NetworkState(info, prop, null);
+    }
+
+    private static NetworkStats buildEmptyStats(long elapsedRealtime) {
+        return new NetworkStats(elapsedRealtime, 0);
+    }
+
     private void replay() {
-        EasyMock.replay(mNetManager, mAlarmManager, mTime, mConnManager);
+        EasyMock.replay(mNetManager, mAlarmManager, mTime, mSettings, mConnManager);
     }
 
     private void verifyAndReset() {
-        EasyMock.verify(mNetManager, mAlarmManager, mTime, mConnManager);
-        EasyMock.reset(mNetManager, mAlarmManager, mTime, mConnManager);
+        EasyMock.verify(mNetManager, mAlarmManager, mTime, mSettings, mConnManager);
+        EasyMock.reset(mNetManager, mAlarmManager, mTime, mSettings, mConnManager);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
index d1ee4f6..30afdd8 100644
--- a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
@@ -288,11 +288,10 @@
      */
     public void expectGetInterfaceCounter(long rx, long tx) throws Exception {
         // TODO: provide elapsedRealtime mock to match TimeAuthority
-        final NetworkStats.Builder stats = new NetworkStats.Builder(
-                SystemClock.elapsedRealtime(), 1);
+        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
         stats.addEntry(TEST_IFACE, NetworkStats.UID_ALL, rx, tx);
 
-        expect(mMockNMService.getNetworkStatsSummary()).andReturn(stats.build()).atLeastOnce();
+        expect(mMockNMService.getNetworkStatsSummary()).andReturn(stats).atLeastOnce();
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 7abae09..171b371 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -1803,33 +1803,33 @@
         Call call;
         StringBuilder b = new StringBuilder();
 
-        b.append("########### Dump CallManager ############");
-        b.append("\nCallManager state = " + getState());
+        b.append("CallManager {");
+        b.append("\nstate = " + getState());
         call = getActiveFgCall();
-        b.append("\n   - Foreground: " + getActiveFgCallState());
+        b.append("\n- Foreground: " + getActiveFgCallState());
         b.append(" from " + call.getPhone());
-        b.append("\n     Conn: ").append(getFgCallConnections());
+        b.append("\n  Conn: ").append(getFgCallConnections());
         call = getFirstActiveBgCall();
-        b.append("\n   - Background: " + call.getState());
+        b.append("\n- Background: " + call.getState());
         b.append(" from " + call.getPhone());
-        b.append("\n     Conn: ").append(getBgCallConnections());
+        b.append("\n  Conn: ").append(getBgCallConnections());
         call = getFirstActiveRingingCall();
-        b.append("\n   - Ringing: " +call.getState());
+        b.append("\n- Ringing: " +call.getState());
         b.append(" from " + call.getPhone());
 
         for (Phone phone : getAllPhones()) {
             if (phone != null) {
-                b.append("\n Phone: " + phone + ", name = " + phone.getPhoneName()
+                b.append("\nPhone: " + phone + ", name = " + phone.getPhoneName()
                         + ", state = " + phone.getState());
                 call = phone.getForegroundCall();
-                b.append("\n   - Foreground: ").append(call);
+                b.append("\n- Foreground: ").append(call);
                 call = phone.getBackgroundCall();
                 b.append(" Background: ").append(call);
                 call = phone.getRingingCall();
                 b.append(" Ringing: ").append(call);
             }
         }
-        b.append("\n########## End Dump CallManager ##########");
+        b.append("\n}");
         return b.toString();
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index 014901d..457fa7aa 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.database.Cursor;
 import android.graphics.drawable.Drawable;
+import android.location.CountryDetector;
 import android.net.Uri;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.Data;
@@ -29,6 +30,13 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.google.i18n.phonenumbers.NumberParseException;
+import com.google.i18n.phonenumbers.PhoneNumberOfflineGeocoder;
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
+
+import java.util.Locale;
+
 
 /**
  * Looks up caller information for the given phone number.
@@ -72,7 +80,8 @@
      */
     public String name;
     public String phoneNumber;
-    public String nomalizedNumber;
+    public String normalizedNumber;
+    public String geoDescription;
 
     public String cnapName;
     public int numberPresentation;
@@ -131,7 +140,7 @@
         info.isCachedPhotoCurrent = false;
         info.contactExists = false;
 
-        if (VDBG) Log.v(TAG, "construct callerInfo from cursor");
+        if (VDBG) Log.v(TAG, "getCallerInfo() based on cursor...");
 
         if (cursor != null) {
             if (cursor.moveToFirst()) {
@@ -156,7 +165,7 @@
                 // Look for the normalized number
                 columnIndex = cursor.getColumnIndex(PhoneLookup.NORMALIZED_NUMBER);
                 if (columnIndex != -1) {
-                    info.nomalizedNumber = cursor.getString(columnIndex);
+                    info.normalizedNumber = cursor.getString(columnIndex);
                 }
 
                 // Look for the label/type combo
@@ -236,6 +245,8 @@
      * with all relevant fields empty or null.
      */
     public static CallerInfo getCallerInfo(Context context, String number) {
+        if (VDBG) Log.v(TAG, "getCallerInfo() based on number...");
+
         if (TextUtils.isEmpty(number)) {
             return null;
         }
@@ -473,6 +484,66 @@
     }
 
     /**
+     * Updates this CallerInfo's geoDescription field, based on the raw
+     * phone number in the phoneNumber field.
+     *
+     * (Note that the various getCallerInfo() methods do *not* set the
+     * geoDescription automatically; you need to call this method
+     * explicitly to get it.)
+     *
+     * @param context the context used to look up the current locale / country
+     * @param fallbackNumber if this CallerInfo's phoneNumber field is empty,
+     *        this specifies a fallback number to use instead.
+     */
+    public void updateGeoDescription(Context context, String fallbackNumber) {
+        String number = TextUtils.isEmpty(phoneNumber) ? fallbackNumber : phoneNumber;
+        geoDescription = getGeoDescription(context, number);
+    }
+
+    /**
+     * @return a geographical description string for the specified number.
+     * @see com.google.i18n.phonenumbers.PhoneNumberOfflineGeocoder
+     */
+    private static String getGeoDescription(Context context, String number) {
+        if (VDBG) Log.v(TAG, "getGeoDescription('" + number + "')...");
+
+        if (TextUtils.isEmpty(number)) {
+            return null;
+        }
+
+        PhoneNumberUtil util = PhoneNumberUtil.getInstance();
+        PhoneNumberOfflineGeocoder geocoder = PhoneNumberOfflineGeocoder.getInstance();
+
+        String countryIso;
+        Locale locale = context.getResources().getConfiguration().locale;
+        CountryDetector detector = (CountryDetector) context.getSystemService(
+                Context.COUNTRY_DETECTOR);
+        if (detector != null) {
+            countryIso = detector.detectCountry().getCountryIso();
+        } else {
+            countryIso = locale.getCountry();
+            Log.w(TAG, "No CountryDetector; falling back to countryIso based on locale: "
+                  + countryIso);
+        }
+
+        PhoneNumber pn = null;
+        try {
+            pn = util.parse(number, countryIso);
+            if (VDBG) Log.v(TAG, "- parsed number: " + pn);
+        } catch (NumberParseException e) {
+            Log.w(TAG, "getGeoDescription: NumberParseException for incoming number '" + number + "'");
+        }
+
+        if (pn != null) {
+            String description = geocoder.getDescriptionForNumber(pn, locale);
+            if (VDBG) Log.v(TAG, "- got description: '" + description + "'");
+            return description;
+        } else {
+            return null;
+        }
+    }
+
+    /**
      * @return a string debug representation of this instance.
      */
     public String toString() {
@@ -482,8 +553,11 @@
 
         if (VERBOSE_DEBUG) {
             return new StringBuilder(384)
+                    .append(super.toString() + " { ")
                     .append("\nname: " + name)
                     .append("\nphoneNumber: " + phoneNumber)
+                    .append("\nnormalizedNumber: " + normalizedNumber)
+                    .append("\ngeoDescription: " + geoDescription)
                     .append("\ncnapName: " + cnapName)
                     .append("\nnumberPresentation: " + numberPresentation)
                     .append("\nnamePresentation: " + namePresentation)
@@ -502,10 +576,11 @@
                     .append("\nemergency: " + mIsEmergency)
                     .append("\nvoicemail " + mIsVoiceMail)
                     .append("\ncontactExists " + contactExists)
+                    .append(" }")
                     .toString();
         } else {
             return new StringBuilder(128)
-                    .append("CallerInfo { ")
+                    .append(super.toString() + " { ")
                     .append("name " + ((name == null) ? "null" : "non-null"))
                     .append(", phoneNumber " + ((phoneNumber == null) ? "null" : "non-null"))
                     .append(" }")
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index c47e076..bbd4232 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -34,9 +34,11 @@
 import android.util.Log;
 
 /**
- * ASYNCHRONOUS QUERY API
+ * Helper class to make it easier to run asynchronous caller-id lookup queries.
+ * @see CallerInfo
+ *
+ * {@hide}
  */
-
 public class CallerInfoAsyncQuery {
     private static final boolean DBG = false;
     private static final String LOG_TAG = "CallerInfoAsyncQuery";
@@ -239,12 +241,31 @@
                                 + mCallerInfo);
                     }
 
+                    // Final step: look up the geocoded description.
+                    //
+                    // For now, do this only if we *don't* have a valid name (i.e. if
+                    // no contacts matched the phone number of the incoming call),
+                    // since that's the only case where the incoming-call UI cares
+                    // about this field.
+                    // (TODO: But if we ever want the UI to show the geoDescription
+                    // even when we *do* match a contact, we'll need to either call
+                    // updateGeoDescription() unconditionally here, or possibly add a
+                    // new parameter to CallerInfoAsyncQuery.startQuery() to force
+                    // the geoDescription field to be populated.)
+                    if (TextUtils.isEmpty(mCallerInfo.name)) {
+                        // Actually when no contacts match the incoming phone number,
+                        // the CallerInfo object is totally blank here (i.e. no name
+                        // *or* phoneNumber).  So we need to pass in cw.number as
+                        // a fallback number.
+                        mCallerInfo.updateGeoDescription(mQueryContext, cw.number);
+                    }
+
                     // Use the number entered by the user for display.
                     if (!TextUtils.isEmpty(cw.number)) {
                         CountryDetector detector = (CountryDetector) mQueryContext.getSystemService(
                                 Context.COUNTRY_DETECTOR);
                         mCallerInfo.phoneNumber = PhoneNumberUtils.formatNumber(cw.number,
-                                mCallerInfo.nomalizedNumber,
+                                mCallerInfo.normalizedNumber,
                                 detector.detectCountry().getCountryIso());
                     }
                 }
@@ -412,7 +433,7 @@
      * Method to create a new CallerInfoAsyncQueryHandler object, ensuring correct
      * state of context and uri.
      */
-    private void allocate (Context context, Uri contactRef) {
+    private void allocate(Context context, Uri contactRef) {
         if ((context == null) || (contactRef == null)){
             throw new QueryPoolException("Bad context or query uri.");
         }
@@ -424,7 +445,7 @@
     /**
      * Releases the relevant data.
      */
-    private void release () {
+    private void release() {
         mHandler.mQueryContext = null;
         mHandler.mQueryUri = null;
         mHandler.mCallerInfo = null;
diff --git a/telephony/java/com/android/internal/telephony/IccCardApplication.java b/telephony/java/com/android/internal/telephony/IccCardApplication.java
index 4cf21ee..434c484 100644
--- a/telephony/java/com/android/internal/telephony/IccCardApplication.java
+++ b/telephony/java/com/android/internal/telephony/IccCardApplication.java
@@ -177,4 +177,15 @@
         return newSubState;
     }
 
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("{").append(app_type).append(",").append(app_state);
+        if (app_state == AppState.APPSTATE_SUBSCRIPTION_PERSO) {
+            sb.append(",").append(perso_substate);
+        }
+        sb.append("}");
+        return sb.toString();
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/IccCardStatus.java b/telephony/java/com/android/internal/telephony/IccCardStatus.java
index 7199616..e9de922 100644
--- a/telephony/java/com/android/internal/telephony/IccCardStatus.java
+++ b/telephony/java/com/android/internal/telephony/IccCardStatus.java
@@ -144,4 +144,33 @@
         return mApplications.get(index);
     }
 
+    @Override
+    public String toString() {
+        IccCardApplication app;
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("IccCardState {").append(mCardState).append(",")
+        .append(mUniversalPinState)
+        .append(",num_apps=").append(mNumApplications)
+        .append(",gsm_id=").append(mGsmUmtsSubscriptionAppIndex);
+        if (mGsmUmtsSubscriptionAppIndex >=0
+                && mGsmUmtsSubscriptionAppIndex <CARD_MAX_APPS) {
+            app = getApplication(mGsmUmtsSubscriptionAppIndex);
+            sb.append(app == null ? "null" : app);
+        }
+
+        sb.append(",cmda_id=").append(mCdmaSubscriptionAppIndex);
+        if (mCdmaSubscriptionAppIndex >=0
+                && mCdmaSubscriptionAppIndex <CARD_MAX_APPS) {
+            app = getApplication(mCdmaSubscriptionAppIndex);
+            sb.append(app == null ? "null" : app);
+        }
+
+        sb.append(",ism_id=").append(mImsSubscriptionAppIndex);
+
+        sb.append("}");
+
+        return sb.toString();
+    }
+
 }
diff --git a/tests/BiDiTests/AndroidManifest.xml b/tests/BiDiTests/AndroidManifest.xml
index 135c5dd..4a687f2 100644
--- a/tests/BiDiTests/AndroidManifest.xml
+++ b/tests/BiDiTests/AndroidManifest.xml
@@ -29,118 +29,6 @@
             </intent-filter>
         </activity>
 
-        <activity android:name=".BiDiTestBasicActivity"
-                android:windowSoftInputMode="stateAlwaysHidden">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".BiDiTestCanvasActivity"
-                  android:windowSoftInputMode="stateAlwaysHidden">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".BiDiTestLinearLayoutLtrActivity"
-                  android:windowSoftInputMode="stateAlwaysHidden">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".BiDiTestLinearLayoutRtlActivity"
-                  android:windowSoftInputMode="stateAlwaysHidden">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".BiDiTestLinearLayoutLocaleActivity"
-                  android:windowSoftInputMode="stateAlwaysHidden">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".BiDiTestFrameLayoutLtrActivity"
-                  android:windowSoftInputMode="stateAlwaysHidden">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".BiDiTestFrameLayoutRtlActivity"
-                  android:windowSoftInputMode="stateAlwaysHidden">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".BiDiTestFrameLayoutLocaleActivity"
-                  android:windowSoftInputMode="stateAlwaysHidden">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".BiDiTestRelativeLayoutLtrActivity"
-                  android:windowSoftInputMode="stateAlwaysHidden">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".BiDiTestRelativeLayoutRtlActivity"
-                  android:windowSoftInputMode="stateAlwaysHidden">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".BiDiTestRelativeLayoutLtrActivity2"
-                  android:windowSoftInputMode="stateAlwaysHidden">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".BiDiTestRelativeLayoutRtlActivity2"
-                  android:windowSoftInputMode="stateAlwaysHidden">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".BiDiTestRelativeLayoutLocaleActivity2"
-                  android:windowSoftInputMode="stateAlwaysHidden">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".BiDiTestTableLayoutLtrActivity"
-                  android:windowSoftInputMode="stateAlwaysHidden">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".BiDiTestTableLayoutRtlActivity"
-                  android:windowSoftInputMode="stateAlwaysHidden">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
-        <activity android:name=".BiDiTestTableLayoutLocaleActivity"
-                  android:windowSoftInputMode="stateAlwaysHidden">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
     </application>
 
 </manifest>
diff --git a/tests/BiDiTests/res/layout/basic.xml b/tests/BiDiTests/res/layout/basic.xml
index d5f5ba7..d438b2c 100644
--- a/tests/BiDiTests/res/layout/basic.xml
+++ b/tests/BiDiTests/res/layout/basic.xml
@@ -14,36 +14,41 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:orientation="vertical"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent">
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/basic"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
 
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="vertical"
+    <LinearLayout android:orientation="vertical"
                   android:layout_width="match_parent"
-                  android:layout_height="wrap_content">
+                  android:layout_height="match_parent">
 
-        <Button android:id="@+id/button"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button_text"
-                android:textSize="32dip"
-                />
+        <LinearLayout android:orientation="vertical"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content">
 
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="32dip"
-                  android:text="@string/textview_text"
-                />
+            <Button android:id="@+id/button"
+                    android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button_text"
+                    android:textSize="32dip"
+                    />
 
-        <EditText android:id="@+id/edittext"
-                  android:layout_height="wrap_content"
-                  android:layout_width="match_parent"
-                  android:textSize="32dip"
-                />
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="32dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <EditText android:id="@+id/edittext"
+                      android:layout_height="wrap_content"
+                      android:layout_width="match_parent"
+                      android:textSize="32dip"
+                    />
+
+        </LinearLayout>
 
     </LinearLayout>
 
-</LinearLayout>
\ No newline at end of file
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/layout/canvas.xml b/tests/BiDiTests/res/layout/canvas.xml
index 03b1bb2..0319a83 100644
--- a/tests/BiDiTests/res/layout/canvas.xml
+++ b/tests/BiDiTests/res/layout/canvas.xml
@@ -14,21 +14,27 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:orientation="vertical"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/canvas"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
+
+    <LinearLayout android:orientation="vertical"
+                  android:layout_width="match_parent"
+                  android:layout_height="match_parent">
+
+        <SeekBar android:id="@+id/seekbar"
+                 android:layout_height="wrap_content"
+                 android:layout_width="match_parent"
+                />
+
+        <view class="com.android.bidi.BiDiTestView"
+              android:id="@+id/testview"
               android:layout_width="match_parent"
-              android:layout_height="match_parent">
+              android:layout_height="wrap_content"
+              android:background="#FF0000"
+                />
 
-    <SeekBar android:id="@+id/seekbar"
-             android:layout_height="wrap_content"
-             android:layout_width="match_parent"
-            />
+    </LinearLayout>
 
-    <view class="com.android.bidi.BiDiTestView"
-          android:id="@+id/testview"
-          android:layout_width="match_parent"
-          android:layout_height="wrap_content"
-          android:background="#FF0000"
-            />
-
-</LinearLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/layout/custom_list_item.xml b/tests/BiDiTests/res/layout/custom_list_item.xml
new file mode 100644
index 0000000..069424e
--- /dev/null
+++ b/tests/BiDiTests/res/layout/custom_list_item.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:textAppearance="?android:attr/textAppearanceLarge"
+    android:gravity="center_vertical"
+    android:paddingLeft="6dip"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:background="?android:attr/activatedBackgroundIndicator"
+/>
diff --git a/tests/BiDiTests/res/layout/frame_layout_locale.xml b/tests/BiDiTests/res/layout/frame_layout_locale.xml
index 812e0dc..3382234 100644
--- a/tests/BiDiTests/res/layout/frame_layout_locale.xml
+++ b/tests/BiDiTests/res/layout/frame_layout_locale.xml
@@ -15,74 +15,78 @@
 -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             android:id="@+id/frame_layout_ltr"
-             android:layout_width="match_parent"
-             android:layout_height="match_parent"
-             android:layoutDirection="locale"
-             android:background="#FF000000">
+        android:id="@+id/frame_layout_locale"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="right|center_vertical"
-            android:background="#FFFF0000">
-    </FrameLayout>
+    <FrameLayout android:layout_width="match_parent"
+                 android:layout_height="match_parent"
+                 android:layoutDirection="locale"
+                 android:background="#FF000000">
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="left|center_vertical"
-            android:background="#FF00FF00">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="right|center_vertical"
+                android:background="#FFFF0000">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="top|center_horizontal"
-            android:background="#FF0000FF">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="left|center_vertical"
+                android:background="#FF00FF00">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="bottom|center_horizontal"
-            android:background="#FF00FFFF">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="top|center_horizontal"
+                android:background="#FF0000FF">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="top|start"
-            android:background="#FFFFFFFF">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="bottom|center_horizontal"
+                android:background="#FF00FFFF">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="top|end"
-            android:background="#FFFFFF00">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="top|start"
+                android:background="#FFFFFFFF">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="bottom|start"
-            android:background="#FFFFFFFF">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="top|end"
+                android:background="#FFFFFF00">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="bottom|end"
-            android:background="#FFFFFF00">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="bottom|start"
+                android:background="#FFFFFFFF">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="center_horizontal|center_vertical"
-            android:background="#FF888888">
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="bottom|end"
+                android:background="#FFFFFF00">
+        </FrameLayout>
+
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="center_horizontal|center_vertical"
+                android:background="#FF888888">
+        </FrameLayout>
+
     </FrameLayout>
 
 </FrameLayout>
-
diff --git a/tests/BiDiTests/res/layout/frame_layout_ltr.xml b/tests/BiDiTests/res/layout/frame_layout_ltr.xml
index 79effe6..a8ae9144 100644
--- a/tests/BiDiTests/res/layout/frame_layout_ltr.xml
+++ b/tests/BiDiTests/res/layout/frame_layout_ltr.xml
@@ -15,74 +15,78 @@
 -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             android:id="@+id/frame_layout_ltr"
-             android:layout_width="match_parent"
-             android:layout_height="match_parent"
-             android:layoutDirection="ltr"
-             android:background="#FF000000">
+        android:id="@+id/frame_layout_ltr"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="right|center_vertical"
-            android:background="#FFFF0000">
-    </FrameLayout>
+    <FrameLayout android:layout_width="match_parent"
+                 android:layout_height="match_parent"
+                 android:layoutDirection="ltr"
+                 android:background="#FF000000">
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="left|center_vertical"
-            android:background="#FF00FF00">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="right|center_vertical"
+                android:background="#FFFF0000">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="top|center_horizontal"
-            android:background="#FF0000FF">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="left|center_vertical"
+                android:background="#FF00FF00">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="bottom|center_horizontal"
-            android:background="#FF00FFFF">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="top|center_horizontal"
+                android:background="#FF0000FF">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="top|start"
-            android:background="#FFFFFFFF">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="bottom|center_horizontal"
+                android:background="#FF00FFFF">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="top|end"
-            android:background="#FFFFFF00">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="top|start"
+                android:background="#FFFFFFFF">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="bottom|start"
-            android:background="#FFFFFFFF">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="top|end"
+                android:background="#FFFFFF00">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="bottom|end"
-            android:background="#FFFFFF00">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="bottom|start"
+                android:background="#FFFFFFFF">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="center_horizontal|center_vertical"
-            android:background="#FF888888">
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="bottom|end"
+                android:background="#FFFFFF00">
+        </FrameLayout>
+
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="center_horizontal|center_vertical"
+                android:background="#FF888888">
+        </FrameLayout>
+
     </FrameLayout>
 
 </FrameLayout>
-
diff --git a/tests/BiDiTests/res/layout/frame_layout_rtl.xml b/tests/BiDiTests/res/layout/frame_layout_rtl.xml
index a793862..258d44a 100644
--- a/tests/BiDiTests/res/layout/frame_layout_rtl.xml
+++ b/tests/BiDiTests/res/layout/frame_layout_rtl.xml
@@ -15,74 +15,78 @@
 -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             android:id="@+id/frame_layout_ltr"
-             android:layout_width="match_parent"
-             android:layout_height="match_parent"
-             android:layoutDirection="rtl"
-             android:background="#FF000000">
+        android:id="@+id/frame_layout_rtl"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="right|center_vertical"
-            android:background="#FFFF0000">
-    </FrameLayout>
+    <FrameLayout android:layout_width="match_parent"
+                 android:layout_height="match_parent"
+                 android:layoutDirection="ltr"
+                 android:background="#FF000000">
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="left|center_vertical"
-            android:background="#FF00FF00">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="right|center_vertical"
+                android:background="#FFFF0000">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="top|center_horizontal"
-            android:background="#FF0000FF">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="left|center_vertical"
+                android:background="#FF00FF00">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="bottom|center_horizontal"
-            android:background="#FF00FFFF">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="top|center_horizontal"
+                android:background="#FF0000FF">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="top|start"
-            android:background="#FFFFFFFF">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="bottom|center_horizontal"
+                android:background="#FF00FFFF">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="top|end"
-            android:background="#FFFFFF00">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="top|start"
+                android:background="#FFFFFFFF">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="bottom|start"
-            android:background="#FFFFFFFF">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="top|end"
+                android:background="#FFFFFF00">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="bottom|end"
-            android:background="#FFFFFF00">
-    </FrameLayout>
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="bottom|start"
+                android:background="#FFFFFFFF">
+        </FrameLayout>
 
-    <FrameLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="center_horizontal|center_vertical"
-            android:background="#FF888888">
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="bottom|end"
+                android:background="#FFFFFF00">
+        </FrameLayout>
+
+        <FrameLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="center_horizontal|center_vertical"
+                android:background="#FF888888">
+        </FrameLayout>
+
     </FrameLayout>
 
 </FrameLayout>
-
diff --git a/tests/BiDiTests/res/layout/linear_layout_locale.xml b/tests/BiDiTests/res/layout/linear_layout_locale.xml
index 72046cb..bddb458 100644
--- a/tests/BiDiTests/res/layout/linear_layout_locale.xml
+++ b/tests/BiDiTests/res/layout/linear_layout_locale.xml
@@ -14,244 +14,240 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:id="@+id/linear_layout_rtl"
-              android:orientation="vertical"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:layoutDirection="locale">
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="horizontal"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/linear_layout_locale"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
+        
+    <LinearLayout android:orientation="vertical"
                   android:layout_width="match_parent"
-                  android:layout_height="wrap_content">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="horizontal"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="inherit">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="horizontal"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="ltr">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="horizontal"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="rtl">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="horizontal"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
+                  android:layout_height="match_parent"
                   android:layoutDirection="locale">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
+    
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="inherit">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="ltr">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="rtl">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="locale">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="vertical"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="inherit">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="vertical"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="ltr">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="vertical"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="rtl">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="vertical"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="locale">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
     </LinearLayout>
 
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="vertical"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="inherit">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="vertical"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="ltr">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="vertical"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="rtl">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="vertical"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="locale">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-</LinearLayout>
\ No newline at end of file
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/layout/linear_layout_ltr.xml b/tests/BiDiTests/res/layout/linear_layout_ltr.xml
index bea087e..060112d 100644
--- a/tests/BiDiTests/res/layout/linear_layout_ltr.xml
+++ b/tests/BiDiTests/res/layout/linear_layout_ltr.xml
@@ -14,244 +14,240 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:id="@+id/linear_layout_ltr"
-              android:orientation="vertical"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:layoutDirection="ltr">
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="horizontal"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/linear_layout_ltr"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
+        
+    <LinearLayout android:orientation="vertical"
                   android:layout_width="match_parent"
-                  android:layout_height="wrap_content">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="horizontal"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="inherit">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="horizontal"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
+                  android:layout_height="match_parent"
                   android:layoutDirection="ltr">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
+    
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="inherit">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="ltr">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="rtl">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="locale">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="vertical"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="inherit">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="vertical"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="ltr">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="vertical"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="rtl">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="vertical"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="locale">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
     </LinearLayout>
 
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="horizontal"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="rtl">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="horizontal"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="locale">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="vertical"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="inherit">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="vertical"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="ltr">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="vertical"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="rtl">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="vertical"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="locale">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-</LinearLayout>
\ No newline at end of file
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/layout/linear_layout_rtl.xml b/tests/BiDiTests/res/layout/linear_layout_rtl.xml
index 12f14ef..53ecbcc 100644
--- a/tests/BiDiTests/res/layout/linear_layout_rtl.xml
+++ b/tests/BiDiTests/res/layout/linear_layout_rtl.xml
@@ -14,244 +14,240 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:id="@+id/linear_layout_rtl"
-              android:orientation="vertical"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:layoutDirection="rtl">
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="horizontal"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/linear_layout_rtl"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
+        
+    <LinearLayout android:orientation="vertical"
                   android:layout_width="match_parent"
-                  android:layout_height="wrap_content">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="horizontal"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="inherit">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="horizontal"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="ltr">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="horizontal"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
+                  android:layout_height="match_parent"
                   android:layoutDirection="rtl">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
+    
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="inherit">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="ltr">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="rtl">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="horizontal"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="locale">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="vertical"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="inherit">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="vertical"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="ltr">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="vertical"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="rtl">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
+        <LinearLayout android:orientation="vertical"
+                      android:layout_width="match_parent"
+                      android:layout_height="wrap_content"
+                      android:layoutDirection="locale">
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button1_text"
+                    android:textSize="24dip"
+                    />
+    
+            <TextView android:id="@+id/textview"
+                      android:layout_height="wrap_content"
+                      android:layout_width="wrap_content"
+                      android:textSize="24dip"
+                      android:text="@string/textview_text"
+                    />
+    
+            <Button android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:text="@string/button2_text"
+                    android:textSize="24dip"
+                    />
+        </LinearLayout>
+    
     </LinearLayout>
 
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="horizontal"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="locale">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="vertical"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="inherit">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="vertical"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="ltr">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="vertical"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="rtl">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:orientation="vertical"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layoutDirection="locale">
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button1_text"
-                android:textSize="24dip"
-                />
-
-        <TextView android:id="@+id/textview"
-                  android:layout_height="wrap_content"
-                  android:layout_width="wrap_content"
-                  android:textSize="24dip"
-                  android:text="@string/textview_text"
-                />
-
-        <Button android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:text="@string/button2_text"
-                android:textSize="24dip"
-                />
-    </LinearLayout>
-
-</LinearLayout>
\ No newline at end of file
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/layout/main.xml b/tests/BiDiTests/res/layout/main.xml
index eb73d44..3543eb7 100644
--- a/tests/BiDiTests/res/layout/main.xml
+++ b/tests/BiDiTests/res/layout/main.xml
@@ -14,28 +14,20 @@
      limitations under the License.
 -->
 
-<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
-         android:id="@android:id/tabhost"
-         android:layout_width="fill_parent"
-         android:layout_height="fill_parent">
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
 
-    <LinearLayout
-            android:orientation="vertical"
-            android:layout_width="fill_parent"
-            android:layout_height="fill_parent"
-            android:padding="5dp">
+    <ListView android:id="@+id/testlist"
+        android:layout_width="0px" 
+        android:layout_height="fill_parent"
+        android:layout_weight="1"/>
 
-        <TabWidget
-                android:id="@android:id/tabs"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content"/>
+    <FrameLayout android:id="@+id/testframe"
+        android:layout_width="0px" 
+        android:layout_height="fill_parent"
+        android:layout_weight="6">
+    </FrameLayout>
 
-        <FrameLayout
-                android:id="@android:id/tabcontent"
-                android:layout_width="fill_parent"
-                android:layout_height="fill_parent"
-                android:padding="5dp"/>
-
-    </LinearLayout>
-
-</TabHost>
+</LinearLayout>
diff --git a/tests/BiDiTests/res/layout/relative_layout_2_locale.xml b/tests/BiDiTests/res/layout/relative_layout_2_locale.xml
index c99a99b..ff5bf7b 100644
--- a/tests/BiDiTests/res/layout/relative_layout_2_locale.xml
+++ b/tests/BiDiTests/res/layout/relative_layout_2_locale.xml
@@ -14,170 +14,170 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:id="@+id/relative_layout_ltr"
-              android:orientation="vertical"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:layoutDirection="locale">
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/relative_layout_2_locale"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
 
-    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                    android:layout_width="fill_parent"
+    <LinearLayout android:orientation="vertical"
+                  android:layout_width="match_parent"
+                  android:layout_height="match_parent"
+                  android:layoutDirection="locale">
+
+        <RelativeLayout android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:background="#FF000000"
+                        android:padding="10px">
+
+            <TextView android:id="@+id/label_1"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:text="Type here:"/>
+
+            <EditText android:id="@+id/entry_1"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_below="@id/label_1"/>
+
+            <Button android:id="@+id/ok_1"
+                    android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:background="#FF000000"
-                    android:padding="10px">
+                    android:layout_below="@id/entry_1"
+                    android:layout_alignParentRight="true"
+                    android:layout_marginLeft="10px"
+                    android:text="OK"/>
 
-        <TextView android:id="@+id/label_1"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:text="Type here:"/>
-
-        <EditText android:id="@+id/entry_1"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:layout_below="@id/label_1"/>
-
-        <Button android:id="@+id/ok_1"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/entry_1"
-                android:layout_alignParentRight="true"
-                android:layout_marginLeft="10px"
-                android:text="OK"/>
-
-        <Button android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_toLeftOf="@id/ok_1"
-                android:layout_alignTop="@id/ok_1"
-                android:text="Cancel"/>
-    </RelativeLayout>
-
-    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                    android:layout_width="fill_parent"
+            <Button android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:background="#FF000000"
-                    android:padding="10px"
-                    android:layoutDirection="ltr">
+                    android:layout_toLeftOf="@id/ok_1"
+                    android:layout_alignTop="@id/ok_1"
+                    android:text="Cancel"/>
+        </RelativeLayout>
 
-        <TextView android:id="@+id/label_2"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:text="Type here:"/>
+        <RelativeLayout android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:background="#FF000000"
+                        android:padding="10px"
+                        android:layoutDirection="ltr">
 
-        <EditText android:id="@+id/entry_2"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:layout_below="@id/label_2"/>
+            <TextView android:id="@+id/label_2"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:text="Type here:"/>
 
-        <Button android:id="@+id/ok_2"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/entry_2"
-                android:layout_alignParentRight="true"
-                android:layout_marginLeft="10px"
-                android:text="OK"/>
+            <EditText android:id="@+id/entry_2"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_below="@id/label_2"/>
 
-        <Button android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_toLeftOf="@id/ok_2"
-                android:layout_alignTop="@id/ok_2"
-                android:text="Cancel"/>
-    </RelativeLayout>
-
-    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                    android:layout_width="fill_parent"
+            <Button android:id="@+id/ok_2"
+                    android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:background="#FF000000"
-                    android:padding="10px"
-                    android:layoutDirection="inherit">
+                    android:layout_below="@id/entry_2"
+                    android:layout_alignParentRight="true"
+                    android:layout_marginLeft="10px"
+                    android:text="OK"/>
 
-        <TextView android:id="@+id/label_3"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:text="Type here:"/>
-
-        <EditText android:id="@+id/entry_3"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:layout_below="@id/label_3"/>
-
-        <Button android:id="@+id/ok_3"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/entry_3"
-                android:layout_alignParentRight="true"
-                android:layout_marginLeft="10px"
-                android:text="OK"/>
-
-        <Button android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_toLeftOf="@id/ok_3"
-                android:layout_alignTop="@id/ok_3"
-                android:text="Cancel"/>
-    </RelativeLayout>
-
-    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                    android:layout_width="fill_parent"
+            <Button android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:background="#FF000000"
-                    android:padding="10px"
-                    android:layoutDirection="rtl">
+                    android:layout_toLeftOf="@id/ok_2"
+                    android:layout_alignTop="@id/ok_2"
+                    android:text="Cancel"/>
+        </RelativeLayout>
 
-        <TextView android:id="@+id/label_4"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:text="Type here:"/>
-
-        <EditText android:id="@+id/entry_4"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:layout_below="@id/label_4"/>
-
-        <Button android:id="@+id/ok_4"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/entry_4"
-                android:layout_alignParentRight="true"
-                android:layout_marginLeft="10px"
-                android:text="OK"/>
-
-        <Button android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_toLeftOf="@id/ok_4"
-                android:layout_alignTop="@id/ok_4"
-                android:text="Cancel"/>
-    </RelativeLayout>
-
-    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                    android:layout_width="fill_parent"
+        <RelativeLayout android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:background="#FF000000"
+                        android:padding="10px"
+                        android:layoutDirection="inherit">
+    
+            <TextView android:id="@+id/label_3"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:text="Type here:"/>
+    
+            <EditText android:id="@+id/entry_3"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_below="@id/label_3"/>
+    
+            <Button android:id="@+id/ok_3"
+                    android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:background="#FF000000"
-                    android:padding="10px"
-                    android:layoutDirection="locale">
+                    android:layout_below="@id/entry_3"
+                    android:layout_alignParentRight="true"
+                    android:layout_marginLeft="10px"
+                    android:text="OK"/>
+    
+            <Button android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_toLeftOf="@id/ok_3"
+                    android:layout_alignTop="@id/ok_3"
+                    android:text="Cancel"/>
+        </RelativeLayout>
 
-        <TextView android:id="@+id/label_4"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:text="Type here:"/>
+        <RelativeLayout android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:background="#FF000000"
+                        android:padding="10px"
+                        android:layoutDirection="rtl">
 
-        <EditText android:id="@+id/entry_4"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:layout_below="@id/label_4"/>
+            <TextView android:id="@+id/label_4"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:text="Type here:"/>
 
-        <Button android:id="@+id/ok_4"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/entry_4"
-                android:layout_alignParentRight="true"
-                android:layout_marginLeft="10px"
-                android:text="OK"/>
+            <EditText android:id="@+id/entry_4"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_below="@id/label_4"/>
 
-        <Button android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_toLeftOf="@id/ok_4"
-                android:layout_alignTop="@id/ok_4"
-                android:text="Cancel"/>
-    </RelativeLayout>
+            <Button android:id="@+id/ok_4"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_below="@id/entry_4"
+                    android:layout_alignParentRight="true"
+                    android:layout_marginLeft="10px"
+                    android:text="OK"/>
 
-</LinearLayout>
\ No newline at end of file
+            <Button android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_toLeftOf="@id/ok_4"
+                    android:layout_alignTop="@id/ok_4"
+                    android:text="Cancel"/>
+        </RelativeLayout>
+
+        <RelativeLayout android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:background="#FF000000"
+                        android:padding="10px"
+                        android:layoutDirection="locale">
+    
+            <TextView android:id="@+id/label_4"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:text="Type here:"/>
+    
+            <EditText android:id="@+id/entry_4"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_below="@id/label_4"/>
+
+            <Button android:id="@+id/ok_4"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_below="@id/entry_4"
+                    android:layout_alignParentRight="true"
+                    android:layout_marginLeft="10px"
+                    android:text="OK"/>
+    
+            <Button android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_toLeftOf="@id/ok_4"
+                    android:layout_alignTop="@id/ok_4"
+                    android:text="Cancel"/>
+        </RelativeLayout>
+
+    </LinearLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/layout/relative_layout_2_ltr.xml b/tests/BiDiTests/res/layout/relative_layout_2_ltr.xml
index c4cab11..cf585b5 100644
--- a/tests/BiDiTests/res/layout/relative_layout_2_ltr.xml
+++ b/tests/BiDiTests/res/layout/relative_layout_2_ltr.xml
@@ -14,170 +14,170 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:id="@+id/relative_layout_ltr"
-              android:orientation="vertical"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:layoutDirection="ltr">
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/relative_layout_2_ltr"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
 
-    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                    android:layout_width="fill_parent"
+    <LinearLayout android:orientation="vertical"
+                  android:layout_width="match_parent"
+                  android:layout_height="match_parent"
+                  android:layoutDirection="ltr">
+
+        <RelativeLayout android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:background="#FF000000"
+                        android:padding="10px">
+
+            <TextView android:id="@+id/label_1"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:text="Type here:"/>
+
+            <EditText android:id="@+id/entry_1"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_below="@id/label_1"/>
+
+            <Button android:id="@+id/ok_1"
+                    android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:background="#FF000000"
-                    android:padding="10px">
+                    android:layout_below="@id/entry_1"
+                    android:layout_alignParentRight="true"
+                    android:layout_marginLeft="10px"
+                    android:text="OK"/>
 
-        <TextView android:id="@+id/label_1"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:text="Type here:"/>
-
-        <EditText android:id="@+id/entry_1"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:layout_below="@id/label_1"/>
-
-        <Button android:id="@+id/ok_1"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/entry_1"
-                android:layout_alignParentRight="true"
-                android:layout_marginLeft="10px"
-                android:text="OK"/>
-
-        <Button android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_toLeftOf="@id/ok_1"
-                android:layout_alignTop="@id/ok_1"
-                android:text="Cancel"/>
-    </RelativeLayout>
-
-    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                    android:layout_width="fill_parent"
+            <Button android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:background="#FF000000"
-                    android:padding="10px"
-                    android:layoutDirection="ltr">
+                    android:layout_toLeftOf="@id/ok_1"
+                    android:layout_alignTop="@id/ok_1"
+                    android:text="Cancel"/>
+        </RelativeLayout>
 
-        <TextView android:id="@+id/label_2"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:text="Type here:"/>
+        <RelativeLayout android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:background="#FF000000"
+                        android:padding="10px"
+                        android:layoutDirection="ltr">
 
-        <EditText android:id="@+id/entry_2"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:layout_below="@id/label_2"/>
+            <TextView android:id="@+id/label_2"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:text="Type here:"/>
 
-        <Button android:id="@+id/ok_2"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/entry_2"
-                android:layout_alignParentRight="true"
-                android:layout_marginLeft="10px"
-                android:text="OK"/>
+            <EditText android:id="@+id/entry_2"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_below="@id/label_2"/>
 
-        <Button android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_toLeftOf="@id/ok_2"
-                android:layout_alignTop="@id/ok_2"
-                android:text="Cancel"/>
-    </RelativeLayout>
-
-    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                    android:layout_width="fill_parent"
+            <Button android:id="@+id/ok_2"
+                    android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:background="#FF000000"
-                    android:padding="10px"
-                    android:layoutDirection="inherit">
+                    android:layout_below="@id/entry_2"
+                    android:layout_alignParentRight="true"
+                    android:layout_marginLeft="10px"
+                    android:text="OK"/>
 
-        <TextView android:id="@+id/label_3"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:text="Type here:"/>
-
-        <EditText android:id="@+id/entry_3"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:layout_below="@id/label_3"/>
-
-        <Button android:id="@+id/ok_3"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/entry_3"
-                android:layout_alignParentRight="true"
-                android:layout_marginLeft="10px"
-                android:text="OK"/>
-
-        <Button android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_toLeftOf="@id/ok_3"
-                android:layout_alignTop="@id/ok_3"
-                android:text="Cancel"/>
-    </RelativeLayout>
-
-    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                    android:layout_width="fill_parent"
+            <Button android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:background="#FF000000"
-                    android:padding="10px"
-                    android:layoutDirection="rtl">
+                    android:layout_toLeftOf="@id/ok_2"
+                    android:layout_alignTop="@id/ok_2"
+                    android:text="Cancel"/>
+        </RelativeLayout>
 
-        <TextView android:id="@+id/label_4"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:text="Type here:"/>
-
-        <EditText android:id="@+id/entry_4"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:layout_below="@id/label_4"/>
-
-        <Button android:id="@+id/ok_4"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/entry_4"
-                android:layout_alignParentRight="true"
-                android:layout_marginLeft="10px"
-                android:text="OK"/>
-
-        <Button android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_toLeftOf="@id/ok_4"
-                android:layout_alignTop="@id/ok_4"
-                android:text="Cancel"/>
-    </RelativeLayout>
-
-    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                    android:layout_width="fill_parent"
+        <RelativeLayout android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:background="#FF000000"
+                        android:padding="10px"
+                        android:layoutDirection="inherit">
+    
+            <TextView android:id="@+id/label_3"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:text="Type here:"/>
+    
+            <EditText android:id="@+id/entry_3"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_below="@id/label_3"/>
+    
+            <Button android:id="@+id/ok_3"
+                    android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:background="#FF000000"
-                    android:padding="10px"
-                    android:layoutDirection="locale">
+                    android:layout_below="@id/entry_3"
+                    android:layout_alignParentRight="true"
+                    android:layout_marginLeft="10px"
+                    android:text="OK"/>
+    
+            <Button android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_toLeftOf="@id/ok_3"
+                    android:layout_alignTop="@id/ok_3"
+                    android:text="Cancel"/>
+        </RelativeLayout>
 
-        <TextView android:id="@+id/label_4"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:text="Type here:"/>
+        <RelativeLayout android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:background="#FF000000"
+                        android:padding="10px"
+                        android:layoutDirection="rtl">
 
-        <EditText android:id="@+id/entry_4"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:layout_below="@id/label_4"/>
+            <TextView android:id="@+id/label_4"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:text="Type here:"/>
 
-        <Button android:id="@+id/ok_4"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/entry_4"
-                android:layout_alignParentRight="true"
-                android:layout_marginLeft="10px"
-                android:text="OK"/>
+            <EditText android:id="@+id/entry_4"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_below="@id/label_4"/>
 
-        <Button android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_toLeftOf="@id/ok_4"
-                android:layout_alignTop="@id/ok_4"
-                android:text="Cancel"/>
-    </RelativeLayout>
+            <Button android:id="@+id/ok_4"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_below="@id/entry_4"
+                    android:layout_alignParentRight="true"
+                    android:layout_marginLeft="10px"
+                    android:text="OK"/>
 
-</LinearLayout>
\ No newline at end of file
+            <Button android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_toLeftOf="@id/ok_4"
+                    android:layout_alignTop="@id/ok_4"
+                    android:text="Cancel"/>
+        </RelativeLayout>
+
+        <RelativeLayout android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:background="#FF000000"
+                        android:padding="10px"
+                        android:layoutDirection="locale">
+    
+            <TextView android:id="@+id/label_4"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:text="Type here:"/>
+    
+            <EditText android:id="@+id/entry_4"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_below="@id/label_4"/>
+
+            <Button android:id="@+id/ok_4"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_below="@id/entry_4"
+                    android:layout_alignParentRight="true"
+                    android:layout_marginLeft="10px"
+                    android:text="OK"/>
+    
+            <Button android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_toLeftOf="@id/ok_4"
+                    android:layout_alignTop="@id/ok_4"
+                    android:text="Cancel"/>
+        </RelativeLayout>
+
+    </LinearLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/layout/relative_layout_2_rtl.xml b/tests/BiDiTests/res/layout/relative_layout_2_rtl.xml
index 009d442..729f1ca 100644
--- a/tests/BiDiTests/res/layout/relative_layout_2_rtl.xml
+++ b/tests/BiDiTests/res/layout/relative_layout_2_rtl.xml
@@ -14,170 +14,170 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:id="@+id/relative_layout_ltr"
-              android:orientation="vertical"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:layoutDirection="rtl">
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/relative_layout_2_rtl"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
 
-    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                    android:layout_width="fill_parent"
+    <LinearLayout android:orientation="vertical"
+                  android:layout_width="match_parent"
+                  android:layout_height="match_parent"
+                  android:layoutDirection="rtl">
+
+        <RelativeLayout android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:background="#FF000000"
+                        android:padding="10px">
+
+            <TextView android:id="@+id/label_1"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:text="Type here:"/>
+
+            <EditText android:id="@+id/entry_1"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_below="@id/label_1"/>
+
+            <Button android:id="@+id/ok_1"
+                    android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:background="#FF000000"
-                    android:padding="10px">
+                    android:layout_below="@id/entry_1"
+                    android:layout_alignParentRight="true"
+                    android:layout_marginLeft="10px"
+                    android:text="OK"/>
 
-        <TextView android:id="@+id/label_1"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:text="Type here:"/>
-
-        <EditText android:id="@+id/entry_1"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:layout_below="@id/label_1"/>
-
-        <Button android:id="@+id/ok_1"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/entry_1"
-                android:layout_alignParentRight="true"
-                android:layout_marginLeft="10px"
-                android:text="OK"/>
-
-        <Button android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_toLeftOf="@id/ok_1"
-                android:layout_alignTop="@id/ok_1"
-                android:text="Cancel"/>
-    </RelativeLayout>
-
-    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                    android:layout_width="fill_parent"
+            <Button android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:background="#FF000000"
-                    android:padding="10px"
-                    android:layoutDirection="ltr">
+                    android:layout_toLeftOf="@id/ok_1"
+                    android:layout_alignTop="@id/ok_1"
+                    android:text="Cancel"/>
+        </RelativeLayout>
 
-        <TextView android:id="@+id/label_2"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:text="Type here:"/>
+        <RelativeLayout android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:background="#FF000000"
+                        android:padding="10px"
+                        android:layoutDirection="ltr">
 
-        <EditText android:id="@+id/entry_2"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:layout_below="@id/label_2"/>
+            <TextView android:id="@+id/label_2"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:text="Type here:"/>
 
-        <Button android:id="@+id/ok_2"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/entry_2"
-                android:layout_alignParentRight="true"
-                android:layout_marginLeft="10px"
-                android:text="OK"/>
+            <EditText android:id="@+id/entry_2"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_below="@id/label_2"/>
 
-        <Button android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_toLeftOf="@id/ok_2"
-                android:layout_alignTop="@id/ok_2"
-                android:text="Cancel"/>
-    </RelativeLayout>
-
-    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                    android:layout_width="fill_parent"
+            <Button android:id="@+id/ok_2"
+                    android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:background="#FF000000"
-                    android:padding="10px"
-                    android:layoutDirection="inherit">
+                    android:layout_below="@id/entry_2"
+                    android:layout_alignParentRight="true"
+                    android:layout_marginLeft="10px"
+                    android:text="OK"/>
 
-        <TextView android:id="@+id/label_3"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:text="Type here:"/>
-
-        <EditText android:id="@+id/entry_3"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:layout_below="@id/label_3"/>
-
-        <Button android:id="@+id/ok_3"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/entry_3"
-                android:layout_alignParentRight="true"
-                android:layout_marginLeft="10px"
-                android:text="OK"/>
-
-        <Button android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_toLeftOf="@id/ok_3"
-                android:layout_alignTop="@id/ok_3"
-                android:text="Cancel"/>
-    </RelativeLayout>
-
-    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                    android:layout_width="fill_parent"
+            <Button android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:background="#FF000000"
-                    android:padding="10px"
-                    android:layoutDirection="rtl">
+                    android:layout_toLeftOf="@id/ok_2"
+                    android:layout_alignTop="@id/ok_2"
+                    android:text="Cancel"/>
+        </RelativeLayout>
 
-        <TextView android:id="@+id/label_4"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:text="Type here:"/>
-
-        <EditText android:id="@+id/entry_4"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:layout_below="@id/label_4"/>
-
-        <Button android:id="@+id/ok_4"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/entry_4"
-                android:layout_alignParentRight="true"
-                android:layout_marginLeft="10px"
-                android:text="OK"/>
-
-        <Button android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_toLeftOf="@id/ok_4"
-                android:layout_alignTop="@id/ok_4"
-                android:text="Cancel"/>
-    </RelativeLayout>
-
-    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                    android:layout_width="fill_parent"
+        <RelativeLayout android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:background="#FF000000"
+                        android:padding="10px"
+                        android:layoutDirection="inherit">
+    
+            <TextView android:id="@+id/label_3"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:text="Type here:"/>
+    
+            <EditText android:id="@+id/entry_3"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_below="@id/label_3"/>
+    
+            <Button android:id="@+id/ok_3"
+                    android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:background="#FF000000"
-                    android:padding="10px"
-                    android:layoutDirection="locale">
+                    android:layout_below="@id/entry_3"
+                    android:layout_alignParentRight="true"
+                    android:layout_marginLeft="10px"
+                    android:text="OK"/>
+    
+            <Button android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_toLeftOf="@id/ok_3"
+                    android:layout_alignTop="@id/ok_3"
+                    android:text="Cancel"/>
+        </RelativeLayout>
 
-        <TextView android:id="@+id/label_4"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:text="Type here:"/>
+        <RelativeLayout android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:background="#FF000000"
+                        android:padding="10px"
+                        android:layoutDirection="rtl">
 
-        <EditText android:id="@+id/entry_4"
-                  android:layout_width="fill_parent"
-                  android:layout_height="wrap_content"
-                  android:layout_below="@id/label_4"/>
+            <TextView android:id="@+id/label_4"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:text="Type here:"/>
 
-        <Button android:id="@+id/ok_4"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/entry_4"
-                android:layout_alignParentRight="true"
-                android:layout_marginLeft="10px"
-                android:text="OK"/>
+            <EditText android:id="@+id/entry_4"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_below="@id/label_4"/>
 
-        <Button android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_toLeftOf="@id/ok_4"
-                android:layout_alignTop="@id/ok_4"
-                android:text="Cancel"/>
-    </RelativeLayout>
+            <Button android:id="@+id/ok_4"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_below="@id/entry_4"
+                    android:layout_alignParentRight="true"
+                    android:layout_marginLeft="10px"
+                    android:text="OK"/>
 
-</LinearLayout>
\ No newline at end of file
+            <Button android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_toLeftOf="@id/ok_4"
+                    android:layout_alignTop="@id/ok_4"
+                    android:text="Cancel"/>
+        </RelativeLayout>
+
+        <RelativeLayout android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:background="#FF000000"
+                        android:padding="10px"
+                        android:layoutDirection="locale">
+    
+            <TextView android:id="@+id/label_4"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:text="Type here:"/>
+    
+            <EditText android:id="@+id/entry_4"
+                      android:layout_width="fill_parent"
+                      android:layout_height="wrap_content"
+                      android:layout_below="@id/label_4"/>
+
+            <Button android:id="@+id/ok_4"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_below="@id/entry_4"
+                    android:layout_alignParentRight="true"
+                    android:layout_marginLeft="10px"
+                    android:text="OK"/>
+    
+            <Button android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_toLeftOf="@id/ok_4"
+                    android:layout_alignTop="@id/ok_4"
+                    android:text="Cancel"/>
+        </RelativeLayout>
+
+    </LinearLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/layout/relative_layout_ltr.xml b/tests/BiDiTests/res/layout/relative_layout_ltr.xml
index e9e8661..461ec98 100644
--- a/tests/BiDiTests/res/layout/relative_layout_ltr.xml
+++ b/tests/BiDiTests/res/layout/relative_layout_ltr.xml
@@ -15,74 +15,78 @@
 -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             android:id="@+id/frame_layout_ltr"
-             android:layout_width="match_parent"
-             android:layout_height="match_parent"
-             android:layoutDirection="ltr"
-             android:background="#FF000000">
+        android:id="@+id/relative_layout_ltr"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
 
-    <RelativeLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="right|center_vertical"
-            android:background="#FFFF0000">
-    </RelativeLayout>
+    <FrameLayout android:layout_width="match_parent"
+                 android:layout_height="match_parent"
+                 android:layoutDirection="ltr"
+                 android:background="#FF000000">
 
-    <RelativeLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="left|center_vertical"
-            android:background="#FF00FF00">
-    </RelativeLayout>
+        <RelativeLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="right|center_vertical"
+                android:background="#FFFF0000">
+        </RelativeLayout>
 
-    <RelativeLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="top|center_horizontal"
-            android:background="#FF0000FF">
-    </RelativeLayout>
+        <RelativeLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="left|center_vertical"
+                android:background="#FF00FF00">
+        </RelativeLayout>
 
-    <RelativeLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="bottom|center_horizontal"
-            android:background="#FF00FFFF">
-    </RelativeLayout>
+        <RelativeLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="top|center_horizontal"
+                android:background="#FF0000FF">
+        </RelativeLayout>
 
-    <RelativeLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="top|start"
-            android:background="#FFFFFFFF">
-    </RelativeLayout>
+        <RelativeLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="bottom|center_horizontal"
+                android:background="#FF00FFFF">
+        </RelativeLayout>
 
-    <RelativeLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="top|end"
-            android:background="#FFFFFF00">
-    </RelativeLayout>
+        <RelativeLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="top|start"
+                android:background="#FFFFFFFF">
+        </RelativeLayout>
 
-    <RelativeLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="bottom|start"
-            android:background="#FFFFFFFF">
-    </RelativeLayout>
+        <RelativeLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="top|end"
+                android:background="#FFFFFF00">
+        </RelativeLayout>
 
-    <RelativeLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="bottom|end"
-            android:background="#FFFFFF00">
-    </RelativeLayout>
+        <RelativeLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="bottom|start"
+                android:background="#FFFFFFFF">
+        </RelativeLayout>
 
-    <RelativeLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="center_horizontal|center_vertical"
-            android:background="#FF888888">
-    </RelativeLayout>
+        <RelativeLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="bottom|end"
+                android:background="#FFFFFF00">
+        </RelativeLayout>
 
-</FrameLayout>
+        <RelativeLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="center_horizontal|center_vertical"
+                android:background="#FF888888">
+        </RelativeLayout>
+    
+    </FrameLayout>
 
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/layout/relative_layout_rtl.xml b/tests/BiDiTests/res/layout/relative_layout_rtl.xml
index 57b2ad0..545d16e 100644
--- a/tests/BiDiTests/res/layout/relative_layout_rtl.xml
+++ b/tests/BiDiTests/res/layout/relative_layout_rtl.xml
@@ -15,74 +15,78 @@
 -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             android:id="@+id/frame_layout_rtl"
-             android:layout_width="match_parent"
-             android:layout_height="match_parent"
-             android:layoutDirection="rtl"
-             android:background="#FF000000">
+        android:id="@+id/relative_layout_rtl"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
 
-    <RelativeLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="right|center_vertical"
-            android:background="#FFFF0000">
-    </RelativeLayout>
+    <FrameLayout android:layout_width="match_parent"
+                 android:layout_height="match_parent"
+                 android:layoutDirection="rtl"
+                 android:background="#FF000000">
 
-    <RelativeLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="left|center_vertical"
-            android:background="#FF00FF00">
-    </RelativeLayout>
+        <RelativeLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="right|center_vertical"
+                android:background="#FFFF0000">
+        </RelativeLayout>
 
-    <RelativeLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="top|center_horizontal"
-            android:background="#FF0000FF">
-    </RelativeLayout>
+        <RelativeLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="left|center_vertical"
+                android:background="#FF00FF00">
+        </RelativeLayout>
 
-    <RelativeLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="bottom|center_horizontal"
-            android:background="#FF00FFFF">
-    </RelativeLayout>
+        <RelativeLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="top|center_horizontal"
+                android:background="#FF0000FF">
+        </RelativeLayout>
 
-    <RelativeLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="top|start"
-            android:background="#FFFFFFFF">
-    </RelativeLayout>
+        <RelativeLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="bottom|center_horizontal"
+                android:background="#FF00FFFF">
+        </RelativeLayout>
 
-    <RelativeLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="top|end"
-            android:background="#FFFFFF00">
-    </RelativeLayout>
+        <RelativeLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="top|start"
+                android:background="#FFFFFFFF">
+        </RelativeLayout>
 
-    <RelativeLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="bottom|start"
-            android:background="#FFFFFFFF">
-    </RelativeLayout>
+        <RelativeLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="top|end"
+                android:background="#FFFFFF00">
+        </RelativeLayout>
 
-    <RelativeLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="bottom|end"
-            android:background="#FFFFFF00">
-    </RelativeLayout>
+        <RelativeLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="bottom|start"
+                android:background="#FFFFFFFF">
+        </RelativeLayout>
 
-    <RelativeLayout
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:layout_gravity="center_horizontal|center_vertical"
-            android:background="#FF888888">
-    </RelativeLayout>
+        <RelativeLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="bottom|end"
+                android:background="#FFFFFF00">
+        </RelativeLayout>
 
-</FrameLayout>
+        <RelativeLayout
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="center_horizontal|center_vertical"
+                android:background="#FF888888">
+        </RelativeLayout>
+    
+    </FrameLayout>
 
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/layout/table_layout_locale.xml b/tests/BiDiTests/res/layout/table_layout_locale.xml
index 847eb07..2589b40 100644
--- a/tests/BiDiTests/res/layout/table_layout_locale.xml
+++ b/tests/BiDiTests/res/layout/table_layout_locale.xml
@@ -14,245 +14,245 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:id="@+id/linear_layout_ltr"
-              android:orientation="vertical"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:layoutDirection="locale">
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/table_layout_locale"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
 
-    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                 android:layout_width="wrap_content"
-                 android:layout_height="wrap_content"
-                 android:stretchColumns="1,2">
+    <LinearLayout android:orientation="vertical"
+                  android:layout_width="match_parent"
+                  android:layout_height="match_parent"
+                  android:layoutDirection="locale">
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button1_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_right_text"
-                    android:textSize="24dip"
-                    android:gravity="right"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_after_text"
-                    android:textSize="24dip"
-                    android:gravity="after"
-                    />
-        </TableRow>
+        <TableLayout android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:stretchColumns="1,2">
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button2_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_left_text"
-                    android:textSize="24dip"
-                    android:gravity="left"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_before_text"
-                    android:textSize="24dip"
-                    android:gravity="before"
-                    />
-        </TableRow>
-    </TableLayout>
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button1_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_right_text"
+                        android:textSize="24dip"
+                        android:gravity="right"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_after_text"
+                        android:textSize="24dip"
+                        android:gravity="after"
+                        />
+            </TableRow>
 
-    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                 android:layout_width="wrap_content"
-                 android:layout_height="wrap_content"
-                 android:stretchColumns="1,2"
-                 android:layoutDirection="inherit">
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button2_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_left_text"
+                        android:textSize="24dip"
+                        android:gravity="left"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_before_text"
+                        android:textSize="24dip"
+                        android:gravity="before"
+                        />
+            </TableRow>
+        </TableLayout>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button1_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_right_text"
-                    android:textSize="24dip"
-                    android:gravity="right"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_after_text"
-                    android:textSize="24dip"
-                    android:gravity="after"
-                    />
-        </TableRow>
+        <TableLayout android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:stretchColumns="1,2"
+                     android:layoutDirection="inherit">
+    
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button1_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_right_text"
+                        android:textSize="24dip"
+                        android:gravity="right"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_after_text"
+                        android:textSize="24dip"
+                        android:gravity="after"
+                        />
+            </TableRow>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button2_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_left_text"
-                    android:textSize="24dip"
-                    android:gravity="left"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_before_text"
-                    android:textSize="24dip"
-                    android:gravity="before"
-                    />
-        </TableRow>
-    </TableLayout>
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button2_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_left_text"
+                        android:textSize="24dip"
+                        android:gravity="left"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_before_text"
+                        android:textSize="24dip"
+                        android:gravity="before"
+                        />
+            </TableRow>
+        </TableLayout>
 
-    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                 android:layout_width="wrap_content"
-                 android:layout_height="wrap_content"
-                 android:stretchColumns="1,2"
-                 android:layoutDirection="ltr">
+        <TableLayout android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:stretchColumns="1,2"
+                     android:layoutDirection="ltr">
+    
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button1_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_right_text"
+                        android:textSize="24dip"
+                        android:gravity="right"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_after_text"
+                        android:textSize="24dip"
+                        android:gravity="after"
+                        />
+            </TableRow>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button1_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_right_text"
-                    android:textSize="24dip"
-                    android:gravity="right"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_after_text"
-                    android:textSize="24dip"
-                    android:gravity="after"
-                    />
-        </TableRow>
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button2_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_left_text"
+                        android:textSize="24dip"
+                        android:gravity="left"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_before_text"
+                        android:textSize="24dip"
+                        android:gravity="before"
+                        />
+            </TableRow>
+        </TableLayout>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button2_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_left_text"
-                    android:textSize="24dip"
-                    android:gravity="left"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_before_text"
-                    android:textSize="24dip"
-                    android:gravity="before"
-                    />
-        </TableRow>
-    </TableLayout>
+        <TableLayout android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:stretchColumns="1,2"
+                     android:layoutDirection="rtl">
+    
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button1_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_right_text"
+                        android:textSize="24dip"
+                        android:gravity="right"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_after_text"
+                        android:textSize="24dip"
+                        android:gravity="after"
+                        />
+            </TableRow>
 
-    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                 android:layout_width="wrap_content"
-                 android:layout_height="wrap_content"
-                 android:stretchColumns="1,2"
-                 android:layoutDirection="rtl">
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button2_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_left_text"
+                        android:textSize="24dip"
+                        android:gravity="left"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_before_text"
+                        android:textSize="24dip"
+                        android:gravity="before"
+                        />
+            </TableRow>
+        </TableLayout>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button1_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_right_text"
-                    android:textSize="24dip"
-                    android:gravity="right"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_after_text"
-                    android:textSize="24dip"
-                    android:gravity="after"
-                    />
-        </TableRow>
+        <TableLayout android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:stretchColumns="1,2"
+                     android:layoutDirection="locale">
+    
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button1_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_right_text"
+                        android:textSize="24dip"
+                        android:gravity="right"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_after_text"
+                        android:textSize="24dip"
+                        android:gravity="after"
+                        />
+            </TableRow>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button2_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_left_text"
-                    android:textSize="24dip"
-                    android:gravity="left"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_before_text"
-                    android:textSize="24dip"
-                    android:gravity="before"
-                    />
-        </TableRow>
-    </TableLayout>
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button2_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_left_text"
+                        android:textSize="24dip"
+                        android:gravity="left"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_before_text"
+                        android:textSize="24dip"
+                        android:gravity="before"
+                        />
+            </TableRow>
+        </TableLayout>
 
-    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                 android:layout_width="wrap_content"
-                 android:layout_height="wrap_content"
-                 android:stretchColumns="1,2"
-                 android:layoutDirection="locale">
+    </LinearLayout>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button1_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_right_text"
-                    android:textSize="24dip"
-                    android:gravity="right"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_after_text"
-                    android:textSize="24dip"
-                    android:gravity="after"
-                    />
-        </TableRow>
-
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button2_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_left_text"
-                    android:textSize="24dip"
-                    android:gravity="left"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_before_text"
-                    android:textSize="24dip"
-                    android:gravity="before"
-                    />
-        </TableRow>
-    </TableLayout>
-
-</LinearLayout>
\ No newline at end of file
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/layout/table_layout_ltr.xml b/tests/BiDiTests/res/layout/table_layout_ltr.xml
index 49d1d0d..d8d412c 100644
--- a/tests/BiDiTests/res/layout/table_layout_ltr.xml
+++ b/tests/BiDiTests/res/layout/table_layout_ltr.xml
@@ -14,245 +14,245 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:id="@+id/linear_layout_ltr"
-              android:orientation="vertical"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:layoutDirection="ltr">
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/table_layout_ltr"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
 
-    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                 android:layout_width="wrap_content"
-                 android:layout_height="wrap_content"
-                 android:stretchColumns="1,2">
+    <LinearLayout android:orientation="vertical"
+                  android:layout_width="match_parent"
+                  android:layout_height="match_parent"
+                  android:layoutDirection="ltr">
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button1_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_right_text"
-                    android:textSize="24dip"
-                    android:gravity="right"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_after_text"
-                    android:textSize="24dip"
-                    android:gravity="after"
-                    />
-        </TableRow>
+        <TableLayout android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:stretchColumns="1,2">
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button2_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_left_text"
-                    android:textSize="24dip"
-                    android:gravity="left"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_before_text"
-                    android:textSize="24dip"
-                    android:gravity="before"
-                    />
-        </TableRow>
-    </TableLayout>
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button1_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_right_text"
+                        android:textSize="24dip"
+                        android:gravity="right"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_after_text"
+                        android:textSize="24dip"
+                        android:gravity="after"
+                        />
+            </TableRow>
 
-    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                 android:layout_width="wrap_content"
-                 android:layout_height="wrap_content"
-                 android:stretchColumns="1,2"
-                 android:layoutDirection="inherit">
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button2_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_left_text"
+                        android:textSize="24dip"
+                        android:gravity="left"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_before_text"
+                        android:textSize="24dip"
+                        android:gravity="before"
+                        />
+            </TableRow>
+        </TableLayout>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button1_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_right_text"
-                    android:textSize="24dip"
-                    android:gravity="right"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_after_text"
-                    android:textSize="24dip"
-                    android:gravity="after"
-                    />
-        </TableRow>
+        <TableLayout android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:stretchColumns="1,2"
+                     android:layoutDirection="inherit">
+    
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button1_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_right_text"
+                        android:textSize="24dip"
+                        android:gravity="right"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_after_text"
+                        android:textSize="24dip"
+                        android:gravity="after"
+                        />
+            </TableRow>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button2_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_left_text"
-                    android:textSize="24dip"
-                    android:gravity="left"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_before_text"
-                    android:textSize="24dip"
-                    android:gravity="before"
-                    />
-        </TableRow>
-    </TableLayout>
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button2_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_left_text"
+                        android:textSize="24dip"
+                        android:gravity="left"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_before_text"
+                        android:textSize="24dip"
+                        android:gravity="before"
+                        />
+            </TableRow>
+        </TableLayout>
 
-    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                 android:layout_width="wrap_content"
-                 android:layout_height="wrap_content"
-                 android:stretchColumns="1,2"
-                 android:layoutDirection="ltr">
+        <TableLayout android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:stretchColumns="1,2"
+                     android:layoutDirection="ltr">
+    
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button1_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_right_text"
+                        android:textSize="24dip"
+                        android:gravity="right"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_after_text"
+                        android:textSize="24dip"
+                        android:gravity="after"
+                        />
+            </TableRow>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button1_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_right_text"
-                    android:textSize="24dip"
-                    android:gravity="right"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_after_text"
-                    android:textSize="24dip"
-                    android:gravity="after"
-                    />
-        </TableRow>
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button2_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_left_text"
+                        android:textSize="24dip"
+                        android:gravity="left"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_before_text"
+                        android:textSize="24dip"
+                        android:gravity="before"
+                        />
+            </TableRow>
+        </TableLayout>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button2_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_left_text"
-                    android:textSize="24dip"
-                    android:gravity="left"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_before_text"
-                    android:textSize="24dip"
-                    android:gravity="before"
-                    />
-        </TableRow>
-    </TableLayout>
+        <TableLayout android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:stretchColumns="1,2"
+                     android:layoutDirection="rtl">
+    
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button1_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_right_text"
+                        android:textSize="24dip"
+                        android:gravity="right"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_after_text"
+                        android:textSize="24dip"
+                        android:gravity="after"
+                        />
+            </TableRow>
 
-    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                 android:layout_width="wrap_content"
-                 android:layout_height="wrap_content"
-                 android:stretchColumns="1,2"
-                 android:layoutDirection="rtl">
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button2_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_left_text"
+                        android:textSize="24dip"
+                        android:gravity="left"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_before_text"
+                        android:textSize="24dip"
+                        android:gravity="before"
+                        />
+            </TableRow>
+        </TableLayout>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button1_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_right_text"
-                    android:textSize="24dip"
-                    android:gravity="right"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_after_text"
-                    android:textSize="24dip"
-                    android:gravity="after"
-                    />
-        </TableRow>
+        <TableLayout android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:stretchColumns="1,2"
+                     android:layoutDirection="locale">
+    
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button1_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_right_text"
+                        android:textSize="24dip"
+                        android:gravity="right"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_after_text"
+                        android:textSize="24dip"
+                        android:gravity="after"
+                        />
+            </TableRow>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button2_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_left_text"
-                    android:textSize="24dip"
-                    android:gravity="left"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_before_text"
-                    android:textSize="24dip"
-                    android:gravity="before"
-                    />
-        </TableRow>
-    </TableLayout>
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button2_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_left_text"
+                        android:textSize="24dip"
+                        android:gravity="left"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_before_text"
+                        android:textSize="24dip"
+                        android:gravity="before"
+                        />
+            </TableRow>
+        </TableLayout>
 
-    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                 android:layout_width="wrap_content"
-                 android:layout_height="wrap_content"
-                 android:stretchColumns="1,2"
-                 android:layoutDirection="locale">
+    </LinearLayout>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button1_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_right_text"
-                    android:textSize="24dip"
-                    android:gravity="right"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_after_text"
-                    android:textSize="24dip"
-                    android:gravity="after"
-                    />
-        </TableRow>
-
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button2_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_left_text"
-                    android:textSize="24dip"
-                    android:gravity="left"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_before_text"
-                    android:textSize="24dip"
-                    android:gravity="before"
-                    />
-        </TableRow>
-    </TableLayout>
-
-</LinearLayout>
\ No newline at end of file
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/layout/table_layout_rtl.xml b/tests/BiDiTests/res/layout/table_layout_rtl.xml
index a665e45..53130fe2 100644
--- a/tests/BiDiTests/res/layout/table_layout_rtl.xml
+++ b/tests/BiDiTests/res/layout/table_layout_rtl.xml
@@ -14,245 +14,245 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:id="@+id/linear_layout_ltr"
-              android:orientation="vertical"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:layoutDirection="rtl">
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/table_layout_rtl"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
 
-    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                 android:layout_width="wrap_content"
-                 android:layout_height="wrap_content"
-                 android:stretchColumns="1,2">
+    <LinearLayout android:orientation="vertical"
+                  android:layout_width="match_parent"
+                  android:layout_height="match_parent"
+                  android:layoutDirection="rtl">
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button1_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_right_text"
-                    android:textSize="24dip"
-                    android:gravity="right"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_after_text"
-                    android:textSize="24dip"
-                    android:gravity="after"
-                    />
-        </TableRow>
+        <TableLayout android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:stretchColumns="1,2">
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button2_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_left_text"
-                    android:textSize="24dip"
-                    android:gravity="left"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_before_text"
-                    android:textSize="24dip"
-                    android:gravity="before"
-                    />
-        </TableRow>
-    </TableLayout>
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button1_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_right_text"
+                        android:textSize="24dip"
+                        android:gravity="right"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_after_text"
+                        android:textSize="24dip"
+                        android:gravity="after"
+                        />
+            </TableRow>
 
-    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                 android:layout_width="wrap_content"
-                 android:layout_height="wrap_content"
-                 android:stretchColumns="1,2"
-                 android:layoutDirection="inherit">
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button2_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_left_text"
+                        android:textSize="24dip"
+                        android:gravity="left"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_before_text"
+                        android:textSize="24dip"
+                        android:gravity="before"
+                        />
+            </TableRow>
+        </TableLayout>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button1_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_right_text"
-                    android:textSize="24dip"
-                    android:gravity="right"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_after_text"
-                    android:textSize="24dip"
-                    android:gravity="after"
-                    />
-        </TableRow>
+        <TableLayout android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:stretchColumns="1,2"
+                     android:layoutDirection="inherit">
+    
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button1_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_right_text"
+                        android:textSize="24dip"
+                        android:gravity="right"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_after_text"
+                        android:textSize="24dip"
+                        android:gravity="after"
+                        />
+            </TableRow>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button2_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_left_text"
-                    android:textSize="24dip"
-                    android:gravity="left"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_before_text"
-                    android:textSize="24dip"
-                    android:gravity="before"
-                    />
-        </TableRow>
-    </TableLayout>
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button2_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_left_text"
+                        android:textSize="24dip"
+                        android:gravity="left"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_before_text"
+                        android:textSize="24dip"
+                        android:gravity="before"
+                        />
+            </TableRow>
+        </TableLayout>
 
-    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                 android:layout_width="wrap_content"
-                 android:layout_height="wrap_content"
-                 android:stretchColumns="1,2"
-                 android:layoutDirection="ltr">
+        <TableLayout android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:stretchColumns="1,2"
+                     android:layoutDirection="ltr">
+    
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button1_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_right_text"
+                        android:textSize="24dip"
+                        android:gravity="right"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_after_text"
+                        android:textSize="24dip"
+                        android:gravity="after"
+                        />
+            </TableRow>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button1_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_right_text"
-                    android:textSize="24dip"
-                    android:gravity="right"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_after_text"
-                    android:textSize="24dip"
-                    android:gravity="after"
-                    />
-        </TableRow>
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button2_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_left_text"
+                        android:textSize="24dip"
+                        android:gravity="left"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_before_text"
+                        android:textSize="24dip"
+                        android:gravity="before"
+                        />
+            </TableRow>
+        </TableLayout>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button2_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_left_text"
-                    android:textSize="24dip"
-                    android:gravity="left"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_before_text"
-                    android:textSize="24dip"
-                    android:gravity="before"
-                    />
-        </TableRow>
-    </TableLayout>
+        <TableLayout android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:stretchColumns="1,2"
+                     android:layoutDirection="rtl">
+    
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button1_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_right_text"
+                        android:textSize="24dip"
+                        android:gravity="right"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_after_text"
+                        android:textSize="24dip"
+                        android:gravity="after"
+                        />
+            </TableRow>
 
-    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                 android:layout_width="wrap_content"
-                 android:layout_height="wrap_content"
-                 android:stretchColumns="1,2"
-                 android:layoutDirection="rtl">
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button2_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_left_text"
+                        android:textSize="24dip"
+                        android:gravity="left"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_before_text"
+                        android:textSize="24dip"
+                        android:gravity="before"
+                        />
+            </TableRow>
+        </TableLayout>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button1_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_right_text"
-                    android:textSize="24dip"
-                    android:gravity="right"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_after_text"
-                    android:textSize="24dip"
-                    android:gravity="after"
-                    />
-        </TableRow>
+        <TableLayout android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:stretchColumns="1,2"
+                     android:layoutDirection="locale">
+    
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button1_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_right_text"
+                        android:textSize="24dip"
+                        android:gravity="right"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_after_text"
+                        android:textSize="24dip"
+                        android:gravity="after"
+                        />
+            </TableRow>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button2_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_left_text"
-                    android:textSize="24dip"
-                    android:gravity="left"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_before_text"
-                    android:textSize="24dip"
-                    android:gravity="before"
-                    />
-        </TableRow>
-    </TableLayout>
+            <TableRow>
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button2_text"
+                        android:textSize="24dip"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_left_text"
+                        android:textSize="24dip"
+                        android:gravity="left"
+                        />
+                <Button android:layout_height="wrap_content"
+                        android:layout_width="wrap_content"
+                        android:text="@string/button_before_text"
+                        android:textSize="24dip"
+                        android:gravity="before"
+                        />
+            </TableRow>
+        </TableLayout>
 
-    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                 android:layout_width="wrap_content"
-                 android:layout_height="wrap_content"
-                 android:stretchColumns="1,2"
-                 android:layoutDirection="locale">
+    </LinearLayout>
 
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button1_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_right_text"
-                    android:textSize="24dip"
-                    android:gravity="right"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_after_text"
-                    android:textSize="24dip"
-                    android:gravity="after"
-                    />
-        </TableRow>
-
-        <TableRow>
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button2_text"
-                    android:textSize="24dip"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_left_text"
-                    android:textSize="24dip"
-                    android:gravity="left"
-                    />
-            <Button android:layout_height="wrap_content"
-                    android:layout_width="wrap_content"
-                    android:text="@string/button_before_text"
-                    android:textSize="24dip"
-                    android:gravity="before"
-                    />
-        </TableRow>
-    </TableLayout>
-
-</LinearLayout>
\ No newline at end of file
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
index 1ffe7ee..a3a0041 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
@@ -16,12 +16,56 @@
 
 package com.android.bidi;
 
-import android.app.TabActivity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.widget.TabHost;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
-public class BiDiTestActivity extends TabActivity {
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentTransaction;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.SimpleAdapter;
+
+public class BiDiTestActivity extends Activity {
+
+    private static final String KEY_CLASS = "class";
+    private static final String KEY_TITLE = "title";
+    private static final String KEY_FRAGMENT_ID = "id";
+    
+    private ListView mList;
+    
+    private AdapterView.OnItemClickListener mOnClickListener = 
+            new AdapterView.OnItemClickListener() {
+                public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
+                    onListItemClick((ListView)parent, v, position, id);
+                }
+    };
+
+    private void onListItemClick(ListView lv, View v, int position, long id) {
+        // Show the test
+        Map<String, Object> map = (Map<String, Object>)lv.getItemAtPosition(position);
+        int fragmentId = (Integer) map.get(KEY_FRAGMENT_ID);
+        Fragment fragment = getFragmentManager().findFragmentById(fragmentId);
+        if (fragment == null) {
+            try {
+                // Create an instance of the test
+                Class<? extends Fragment> clazz = (Class<? extends Fragment>) map.get(KEY_CLASS);  
+                fragment = clazz.newInstance();
+                
+                // Replace the old test fragment with the new one
+                FragmentTransaction ft = getFragmentManager().beginTransaction();
+                ft.replace(R.id.testframe, fragment);
+                ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
+                ft.commit();
+            } catch (InstantiationException e) {
+            } catch (IllegalAccessException e) {
+            }
+        }
+    }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -29,94 +73,52 @@
 
         setContentView(R.layout.main);
 
-        TabHost tabHost = getTabHost();
-        TabHost.TabSpec spec;
-        Intent intent;
+        mList = (ListView) findViewById(R.id.testlist);
+        mList.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+        mList.setFocusableInTouchMode(true);
+        
+        final SimpleAdapter adapter = new SimpleAdapter(this, getTests(),
+                R.layout.custom_list_item, new String[]{"title"},
+                new int[]{android.R.id.text1});
+        mList.setAdapter(adapter);
+        
+        mList.setOnItemClickListener(mOnClickListener);
+    }
 
-        // Create an Intent to launch an Activity for the tab (to be reused)
-        intent = new Intent().setClass(this, BiDiTestBasicActivity.class);
+    private void addItem(List<Map<String, Object>> data, String name,
+            Class<? extends Fragment> clazz, int fragmentId) {
+        Map<String, Object> temp = new HashMap<String, Object>();
+        temp.put(KEY_TITLE, name);
+        temp.put(KEY_CLASS, clazz);
+        temp.put(KEY_FRAGMENT_ID, fragmentId);
+        data.add(temp);
+    }
 
-        // Initialize a TabSpec for each tab and add it to the TabHost
-        spec = tabHost.newTabSpec("basic").setIndicator("Basic").
-            setContent(intent);
-        tabHost.addTab(spec);
+    private List<Map<String, Object>> getTests() {
+        List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
 
-        // Do the same for the other tabs
-        intent = new Intent().setClass(this, BiDiTestCanvasActivity.class);
-        spec = tabHost.newTabSpec("canvas").setIndicator("Canvas").
-            setContent(intent);
-        tabHost.addTab(spec);
+        addItem(result, "Basic", BiDiTestBasic.class, R.id.basic);
+        addItem(result, "Canvas", BiDiTestCanvas.class, R.id.canvas);
+        
+        addItem(result, "Linear LTR", BiDiTestLinearLayoutLtr.class, R.id.linear_layout_ltr);
+        addItem(result, "Linear RTL", BiDiTestLinearLayoutRtl.class, R.id.linear_layout_rtl);
+        addItem(result, "Linear LOC", BiDiTestLinearLayoutLocale.class, R.id.linear_layout_locale);
+        
+        addItem(result, "Frame LTR", BiDiTestFrameLayoutLtr.class, R.id.frame_layout_ltr);
+        addItem(result, "Frame RTL", BiDiTestFrameLayoutRtl.class, R.id.frame_layout_rtl);
+        addItem(result, "Frame LOC", BiDiTestFrameLayoutLocale.class, R.id.frame_layout_locale);
+        
+        addItem(result, "Relative LTR", BiDiTestRelativeLayoutLtr.class, R.id.relative_layout_ltr);
+        addItem(result, "Relative RTL", BiDiTestRelativeLayoutRtl.class, R.id.relative_layout_rtl);
+        
+        addItem(result, "Relative2 LTR", BiDiTestRelativeLayout2Ltr.class, R.id.relative_layout_2_ltr);
+        addItem(result, "Relative2 RTL", BiDiTestRelativeLayout2Rtl.class, R.id.relative_layout_2_rtl);
+        addItem(result, "Relative2 LOC", BiDiTestRelativeLayout2Locale.class, R.id.relative_layout_2_locale);
+        
+        addItem(result, "Table LTR", BiDiTestTableLayoutLtr.class, R.id.table_layout_ltr);
+        addItem(result, "Table RTL", BiDiTestTableLayoutRtl.class, R.id.table_layout_rtl);
+        addItem(result, "Table LOC", BiDiTestTableLayoutLocale.class, R.id.table_layout_locale);
 
-        intent = new Intent().setClass(this, BiDiTestLinearLayoutLtrActivity.class);
-        spec = tabHost.newTabSpec("linear-layout-ltr").setIndicator("Linear LTR").
-            setContent(intent);
-        tabHost.addTab(spec);
-
-        intent = new Intent().setClass(this, BiDiTestLinearLayoutRtlActivity.class);
-        spec = tabHost.newTabSpec("linear-layout-rtl").setIndicator("Linear RTL").
-            setContent(intent);
-        tabHost.addTab(spec);
-
-        intent = new Intent().setClass(this, BiDiTestLinearLayoutLocaleActivity.class);
-        spec = tabHost.newTabSpec("linear-layout-locale").setIndicator("Linear LOC").
-            setContent(intent);
-        tabHost.addTab(spec);
-
-        intent = new Intent().setClass(this, BiDiTestFrameLayoutLtrActivity.class);
-        spec = tabHost.newTabSpec("frame-layout-ltr").setIndicator("Frame LTR").
-            setContent(intent);
-        tabHost.addTab(spec);
-
-        intent = new Intent().setClass(this, BiDiTestFrameLayoutRtlActivity.class);
-        spec = tabHost.newTabSpec("frame-layout-rtl").setIndicator("Frame RTL").
-            setContent(intent);
-        tabHost.addTab(spec);
-
-        intent = new Intent().setClass(this, BiDiTestFrameLayoutLocaleActivity.class);
-        spec = tabHost.newTabSpec("frame-layout-locale").setIndicator("Frame LOC").
-            setContent(intent);
-        tabHost.addTab(spec);
-
-        intent = new Intent().setClass(this, BiDiTestRelativeLayoutLtrActivity.class);
-        spec = tabHost.newTabSpec("relative-layout-ltr").setIndicator("Relative LTR").
-            setContent(intent);
-        tabHost.addTab(spec);
-
-        intent = new Intent().setClass(this, BiDiTestRelativeLayoutRtlActivity.class);
-        spec = tabHost.newTabSpec("relative-layout-rtl").setIndicator("Relative RTL").
-            setContent(intent);
-        tabHost.addTab(spec);
-
-        intent = new Intent().setClass(this, BiDiTestRelativeLayoutLtrActivity2.class);
-        spec = tabHost.newTabSpec("relative-layout-ltr-2").setIndicator("Relative2 LTR").
-            setContent(intent);
-        tabHost.addTab(spec);
-
-        intent = new Intent().setClass(this, BiDiTestRelativeLayoutRtlActivity2.class);
-        spec = tabHost.newTabSpec("relative-layout-rtl-2").setIndicator("Relative2 RTL").
-            setContent(intent);
-        tabHost.addTab(spec);
-
-        intent = new Intent().setClass(this, BiDiTestRelativeLayoutLocaleActivity2.class);
-        spec = tabHost.newTabSpec("relative-layout-locale-2").setIndicator("Relative2 LOC").
-            setContent(intent);
-        tabHost.addTab(spec);
-
-        intent = new Intent().setClass(this, BiDiTestTableLayoutLtrActivity.class);
-        spec = tabHost.newTabSpec("table-layout-ltr").setIndicator("Table LTR").
-            setContent(intent);
-        tabHost.addTab(spec);
-
-        intent = new Intent().setClass(this, BiDiTestTableLayoutRtlActivity.class);
-        spec = tabHost.newTabSpec("table-layout-rtl").setIndicator("Table RTL").
-            setContent(intent);
-        tabHost.addTab(spec);
-
-        intent = new Intent().setClass(this, BiDiTestTableLayoutLocaleActivity.class);
-        spec = tabHost.newTabSpec("table-layout-locale").setIndicator("Table LOC").
-            setContent(intent);
-        tabHost.addTab(spec);
-
-        tabHost.setCurrentTab(0);
+        return result;
     }
 }
\ No newline at end of file
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestBasic.java
similarity index 66%
rename from tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
rename to tests/BiDiTests/src/com/android/bidi/BiDiTestBasic.java
index 8694dd1..9b3918d 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestBasic.java
@@ -16,15 +16,17 @@
 
 package com.android.bidi;
 
-import android.app.Activity;
+import android.app.Fragment;
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 
-public class BiDiTestLinearLayoutLocaleActivity extends Activity {
-
+public class BiDiTestBasic extends Fragment {
+    
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.linear_layout_locale);
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.basic, container, false);
     }
 }
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestBasicActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestBasicActivity.java
deleted file mode 100644
index 2a8de04..0000000
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestBasicActivity.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bidi;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class BiDiTestBasicActivity extends Activity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.basic);
-    }
-}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvasActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas.java
similarity index 69%
rename from tests/BiDiTests/src/com/android/bidi/BiDiTestCanvasActivity.java
rename to tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas.java
index 3ab75d5..33ed731 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvasActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas.java
@@ -16,30 +16,39 @@
 
 package com.android.bidi;
 
-import android.app.Activity;
+import android.app.Fragment;
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 import android.widget.SeekBar;
 
 import static com.android.bidi.BiDiTestConstants.FONT_MAX_SIZE;
 import static com.android.bidi.BiDiTestConstants.FONT_MIN_SIZE;
 
-public class BiDiTestCanvasActivity extends Activity {
+public class BiDiTestCanvas extends Fragment {
 
     static final int INIT_TEXT_SIZE = (FONT_MAX_SIZE - FONT_MIN_SIZE) / 2;
 
     private BiDiTestView testView;
     private SeekBar textSizeSeekBar;
+    private View currentView;
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        currentView = inflater.inflate(R.layout.canvas, container, false);
+        return currentView;
+    }
 
-        setContentView(R.layout.canvas);
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
 
-        testView = (BiDiTestView) findViewById(R.id.testview);
+        testView = (BiDiTestView) currentView.findViewById(R.id.testview);
         testView.setCurrentTextSize(INIT_TEXT_SIZE);
 
-        textSizeSeekBar = (SeekBar) findViewById(R.id.seekbar);
+        textSizeSeekBar = (SeekBar) currentView.findViewById(R.id.seekbar);
         textSizeSeekBar.setProgress(INIT_TEXT_SIZE);
         textSizeSeekBar.setMax(FONT_MAX_SIZE - FONT_MIN_SIZE);
 
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLocale.java
similarity index 64%
copy from tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
copy to tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLocale.java
index 8694dd1..900bcd1 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLocale.java
@@ -16,15 +16,18 @@
 
 package com.android.bidi;
 
-import android.app.Activity;
+import android.app.Fragment;
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 
-public class BiDiTestLinearLayoutLocaleActivity extends Activity {
+public class BiDiTestFrameLayoutLocale extends Fragment {
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.linear_layout_locale);
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.frame_layout_locale, container, false);
     }
 }
+
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLocaleActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLocaleActivity.java
deleted file mode 100644
index 457c52a..0000000
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLocaleActivity.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bidi;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class BiDiTestFrameLayoutLocaleActivity extends Activity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.frame_layout_locale);
-    }
-}
-
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLtr.java
similarity index 65%
copy from tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
copy to tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLtr.java
index 8694dd1..43900da 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLtr.java
@@ -16,15 +16,18 @@
 
 package com.android.bidi;
 
-import android.app.Activity;
+import android.app.Fragment;
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 
-public class BiDiTestLinearLayoutLocaleActivity extends Activity {
+public class BiDiTestFrameLayoutLtr extends Fragment {
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.linear_layout_locale);
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.frame_layout_ltr, container, false);
     }
 }
+
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLtrActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLtrActivity.java
deleted file mode 100644
index 6ce4fe4..0000000
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutLtrActivity.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bidi;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class BiDiTestFrameLayoutLtrActivity extends Activity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.frame_layout_ltr);
-    }
-}
-
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutRtl.java
similarity index 65%
copy from tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
copy to tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutRtl.java
index 8694dd1..a261449 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutRtl.java
@@ -16,15 +16,18 @@
 
 package com.android.bidi;
 
-import android.app.Activity;
+import android.app.Fragment;
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 
-public class BiDiTestLinearLayoutLocaleActivity extends Activity {
+public class BiDiTestFrameLayoutRtl extends Fragment {
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.linear_layout_locale);
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.frame_layout_rtl, container, false);
     }
 }
+
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutRtlActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutRtlActivity.java
deleted file mode 100644
index 6012a5c..0000000
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestFrameLayoutRtlActivity.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bidi;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class BiDiTestFrameLayoutRtlActivity extends Activity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.frame_layout_rtl);
-    }
-}
-
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocale.java
similarity index 64%
copy from tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
copy to tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocale.java
index 8694dd1..ad686df 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocale.java
@@ -16,15 +16,17 @@
 
 package com.android.bidi;
 
-import android.app.Activity;
+import android.app.Fragment;
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 
-public class BiDiTestLinearLayoutLocaleActivity extends Activity {
+public class BiDiTestLinearLayoutLocale extends Fragment {
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.linear_layout_locale);
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.linear_layout_locale, container, false);
     }
 }
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLtr.java
similarity index 65%
copy from tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
copy to tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLtr.java
index 8694dd1..da9195a 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLtr.java
@@ -16,15 +16,17 @@
 
 package com.android.bidi;
 
-import android.app.Activity;
+import android.app.Fragment;
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 
-public class BiDiTestLinearLayoutLocaleActivity extends Activity {
+public class BiDiTestLinearLayoutLtr extends Fragment {
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.linear_layout_locale);
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.linear_layout_ltr, container, false);
     }
 }
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLtrActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLtrActivity.java
deleted file mode 100644
index 280af6a..0000000
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLtrActivity.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bidi;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class BiDiTestLinearLayoutLtrActivity extends Activity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.linear_layout_ltr);
-    }
-}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutRtl.java
similarity index 65%
copy from tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
copy to tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutRtl.java
index 8694dd1..dfe247f 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutRtl.java
@@ -16,15 +16,17 @@
 
 package com.android.bidi;
 
-import android.app.Activity;
+import android.app.Fragment;
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 
-public class BiDiTestLinearLayoutLocaleActivity extends Activity {
+public class BiDiTestLinearLayoutRtl extends Fragment {
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.linear_layout_locale);
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.linear_layout_rtl, container, false);
     }
 }
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutRtlActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutRtlActivity.java
deleted file mode 100644
index 7121a62..0000000
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutRtlActivity.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bidi;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class BiDiTestLinearLayoutRtlActivity extends Activity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.linear_layout_rtl);
-    }
-}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayout2Locale.java
similarity index 64%
copy from tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
copy to tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayout2Locale.java
index 8694dd1..957f189 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayout2Locale.java
@@ -16,15 +16,18 @@
 
 package com.android.bidi;
 
-import android.app.Activity;
+import android.app.Fragment;
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 
-public class BiDiTestLinearLayoutLocaleActivity extends Activity {
+public class BiDiTestRelativeLayout2Locale extends Fragment {
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.linear_layout_locale);
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.relative_layout_2_locale, container, false);
     }
 }
+
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayout2Ltr.java
similarity index 64%
copy from tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
copy to tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayout2Ltr.java
index 8694dd1..a27b3a4 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayout2Ltr.java
@@ -16,15 +16,18 @@
 
 package com.android.bidi;
 
-import android.app.Activity;
+import android.app.Fragment;
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 
-public class BiDiTestLinearLayoutLocaleActivity extends Activity {
+public class BiDiTestRelativeLayout2Ltr extends Fragment {
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.linear_layout_locale);
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.relative_layout_2_ltr, container, false);
     }
 }
+
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayout2Rtl.java
similarity index 64%
copy from tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
copy to tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayout2Rtl.java
index 8694dd1..6185a6f 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayout2Rtl.java
@@ -16,15 +16,18 @@
 
 package com.android.bidi;
 
-import android.app.Activity;
+import android.app.Fragment;
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 
-public class BiDiTestLinearLayoutLocaleActivity extends Activity {
+public class BiDiTestRelativeLayout2Rtl extends Fragment {
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.linear_layout_locale);
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.relative_layout_2_rtl, container, false);
     }
 }
+
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLocaleActivity2.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLocaleActivity2.java
deleted file mode 100644
index 8a52b38..0000000
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLocaleActivity2.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bidi;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class BiDiTestRelativeLayoutLocaleActivity2 extends Activity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.relative_layout_2_locale);
-    }
-}
-
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLtr.java
similarity index 64%
copy from tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
copy to tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLtr.java
index 8694dd1..d854e7a 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLtr.java
@@ -16,15 +16,18 @@
 
 package com.android.bidi;
 
-import android.app.Activity;
+import android.app.Fragment;
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 
-public class BiDiTestLinearLayoutLocaleActivity extends Activity {
+public class BiDiTestRelativeLayoutLtr extends Fragment {
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.linear_layout_locale);
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.relative_layout_ltr, container, false);
     }
 }
+
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLtrActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLtrActivity.java
deleted file mode 100644
index d6b8d02..0000000
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLtrActivity.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bidi;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class BiDiTestRelativeLayoutLtrActivity extends Activity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.relative_layout_ltr);
-    }
-}
-
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLtrActivity2.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLtrActivity2.java
deleted file mode 100644
index 65a5ed0..0000000
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutLtrActivity2.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bidi;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class BiDiTestRelativeLayoutLtrActivity2 extends Activity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.relative_layout_2_ltr);
-    }
-}
-
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutRtl.java
similarity index 64%
copy from tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
copy to tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutRtl.java
index 8694dd1..ed5607a 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutRtl.java
@@ -16,15 +16,18 @@
 
 package com.android.bidi;
 
-import android.app.Activity;
+import android.app.Fragment;
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 
-public class BiDiTestLinearLayoutLocaleActivity extends Activity {
+public class BiDiTestRelativeLayoutRtl extends Fragment {
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.linear_layout_locale);
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.relative_layout_rtl, container, false);
     }
 }
+
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutRtlActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutRtlActivity.java
deleted file mode 100644
index 683b7a3..0000000
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutRtlActivity.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bidi;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class BiDiTestRelativeLayoutRtlActivity extends Activity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.relative_layout_rtl);
-    }
-}
-
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutRtlActivity2.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutRtlActivity2.java
deleted file mode 100644
index dad5491..0000000
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestRelativeLayoutRtlActivity2.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bidi;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class BiDiTestRelativeLayoutRtlActivity2 extends Activity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.relative_layout_2_rtl);
-    }
-}
-
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLocale.java
similarity index 64%
copy from tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
copy to tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLocale.java
index 8694dd1..7172c94 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLocale.java
@@ -16,15 +16,18 @@
 
 package com.android.bidi;
 
-import android.app.Activity;
+import android.app.Fragment;
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 
-public class BiDiTestLinearLayoutLocaleActivity extends Activity {
+public class BiDiTestTableLayoutLocale extends Fragment {
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.linear_layout_locale);
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.table_layout_locale, container, false);
     }
 }
+
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLocaleActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLocaleActivity.java
deleted file mode 100644
index 9222aa2..0000000
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLocaleActivity.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bidi;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class BiDiTestTableLayoutLocaleActivity extends Activity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.table_layout_locale);
-    }
-}
-
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLtr.java
similarity index 65%
copy from tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
copy to tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLtr.java
index 8694dd1..ef75b5e 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLtr.java
@@ -16,15 +16,18 @@
 
 package com.android.bidi;
 
-import android.app.Activity;
+import android.app.Fragment;
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 
-public class BiDiTestLinearLayoutLocaleActivity extends Activity {
+public class BiDiTestTableLayoutLtr extends Fragment {
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.linear_layout_locale);
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.table_layout_ltr, container, false);
     }
 }
+
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLtrActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLtrActivity.java
deleted file mode 100644
index 0719dae..0000000
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutLtrActivity.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bidi;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class BiDiTestTableLayoutLtrActivity extends Activity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.table_layout_ltr);
-    }
-}
-
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutRtl.java
similarity index 65%
copy from tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
copy to tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutRtl.java
index 8694dd1..d3c20ff 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestLinearLayoutLocaleActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutRtl.java
@@ -16,15 +16,18 @@
 
 package com.android.bidi;
 
-import android.app.Activity;
+import android.app.Fragment;
 import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 
-public class BiDiTestLinearLayoutLocaleActivity extends Activity {
+public class BiDiTestTableLayoutRtl extends Fragment {
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.linear_layout_locale);
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.table_layout_rtl, container, false);
     }
 }
+
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutRtlActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutRtlActivity.java
deleted file mode 100644
index 3553ed8..0000000
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestTableLayoutRtlActivity.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.bidi;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class BiDiTestTableLayoutRtlActivity extends Activity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.table_layout_rtl);
-    }
-}
-
diff --git a/tests/GridLayoutTest/res/layout/grid3.xml b/tests/GridLayoutTest/res/layout/grid3.xml
index 31dc75a..5cdacf7 100644
--- a/tests/GridLayoutTest/res/layout/grid3.xml
+++ b/tests/GridLayoutTest/res/layout/grid3.xml
@@ -19,14 +19,17 @@
 
         android:layout_width="match_parent"
         android:layout_height="match_parent"
+
         android:useDefaultMargins="true"
         android:marginsIncludedInAlignment="false"
+
         android:columnCount="4"
         >
 
     <TextView
             android:text="Email account"
             android:textSize="48dip"
+
             android:layout_columnSpan="4"
             android:layout_gravity="center_horizontal"
             />
@@ -34,12 +37,14 @@
     <TextView
             android:text="You can configure email in just a few steps:"
             android:textSize="20dip"
+
             android:layout_columnSpan="4"
             android:layout_gravity="left"
             />
 
     <TextView
             android:text="Email address:"
+
             android:layout_gravity="right"
             />
 
@@ -49,6 +54,7 @@
 
     <TextView
             android:text="Password:"
+
             android:layout_column="0"
             android:layout_gravity="right"
             />
@@ -58,14 +64,15 @@
             />
 
     <Space
-            android:layout_rowWeight="1"
-            android:layout_columnWeight="1"
             android:layout_row="4"
             android:layout_column="2"
+            android:layout_rowWeight="1"
+            android:layout_columnWeight="1"
             />
 
     <Button
             android:text="Manual setup"
+
             android:layout_row="5"
             android:layout_column="3"
             android:layout_gravity="fill_horizontal"
@@ -73,6 +80,7 @@
 
     <Button
             android:text="Next"
+
             android:layout_column="3"
             android:layout_gravity="fill_horizontal"
             />
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
index 5e29cf1..32365d7 100644
--- a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
@@ -20,11 +20,15 @@
 import android.content.Context;
 import android.os.Bundle;
 import android.view.View;
-
-import android.widget.*;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.GridLayout;
+import android.widget.Space;
+import android.widget.TextView;
 
 import static android.text.InputType.TYPE_CLASS_TEXT;
-import static android.view.inputmethod.EditorInfo.*;
+import static android.view.inputmethod.EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
+import static android.view.inputmethod.EditorInfo.TYPE_TEXT_VARIATION_PASSWORD;
 import static android.widget.GridLayout.*;
 
 public class Activity2 extends Activity {
@@ -42,12 +46,12 @@
         Group row6 = new Group(6, CENTER);
         Group row7 = new Group(7, CENTER);
 
-        Group col1a = new Group(1, 5, CENTER);
-        Group col1b = new Group(1, 5, LEFT);
+        Group col1a = new Group(1, 4, CENTER);
+        Group col1b = new Group(1, 4, LEFT);
         Group col1c = new Group(1, RIGHT);
-        Group col2 =  new Group(2, LEFT);
-        Group col3 =  new Group(3, FILL);
-        Group col4 =  new Group(4, FILL);
+        Group col2 = new Group(2, LEFT);
+        Group col3 = new Group(3, FILL);
+        Group col4 = new Group(4, FILL);
 
         {
             TextView v = new TextView(context);
@@ -55,20 +59,17 @@
             v.setText("Email setup");
             vg.addView(v, new LayoutParams(row1, col1a));
         }
-
         {
             TextView v = new TextView(context);
             v.setTextSize(20);
             v.setText("You can configure email in just a few steps:");
             vg.addView(v, new LayoutParams(row2, col1b));
         }
-
         {
             TextView v = new TextView(context);
             v.setText("Email address:");
             vg.addView(v, new LayoutParams(row3, col1c));
         }
-
         {
             EditText v = new EditText(context);
             v.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
@@ -78,13 +79,11 @@
                 vg.addView(v, lp);
             }
         }
-
         {
             TextView v = new TextView(context);
             v.setText("Password:");
             vg.addView(v, new LayoutParams(row4, col1c));
         }
-
         {
             TextView v = new EditText(context);
             v.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD);
@@ -94,7 +93,6 @@
                 vg.addView(v, lp);
             }
         }
-
         {
             Space v = new Space(context);
             {
@@ -104,13 +102,11 @@
                 vg.addView(v, lp);
             }
         }
-
         {
             Button v = new Button(context);
             v.setText("Manual setup");
             vg.addView(v, new LayoutParams(row6, col4));
         }
-
         {
             Button v = new Button(context);
             v.setText("Next");
diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java
index b5f1a17..4837eb9 100644
--- a/voip/java/com/android/server/sip/SipSessionGroup.java
+++ b/voip/java/com/android/server/sip/SipSessionGroup.java
@@ -528,12 +528,8 @@
         public void answerCall(String sessionDescription, int timeout) {
             synchronized (SipSessionGroup.this) {
                 if (mPeerProfile == null) return;
-                try {
-                    processCommand(new MakeCallCommand(mPeerProfile,
-                            sessionDescription, timeout));
-                } catch (SipException e) {
-                    onError(e);
-                }
+                doCommandAsync(new MakeCallCommand(mPeerProfile,
+                        sessionDescription, timeout));
             }
         }
 
diff --git a/wifi/java/android/net/wifi/SupplicantState.java b/wifi/java/android/net/wifi/SupplicantState.java
index 91e685f..509b02c 100644
--- a/wifi/java/android/net/wifi/SupplicantState.java
+++ b/wifi/java/android/net/wifi/SupplicantState.java
@@ -216,6 +216,28 @@
         }
     }
 
+    static boolean isDriverActive(SupplicantState state) {
+        switch(state) {
+            case DISCONNECTED:
+            case DORMANT:
+            case INACTIVE:
+            case AUTHENTICATING:
+            case ASSOCIATING:
+            case ASSOCIATED:
+            case SCANNING:
+            case FOUR_WAY_HANDSHAKE:
+            case GROUP_HANDSHAKE:
+            case COMPLETED:
+                return true;
+            case INTERFACE_DISABLED:
+            case UNINITIALIZED:
+            case INVALID:
+                return false;
+            default:
+                throw new IllegalArgumentException("Unknown supplicant state");
+        }
+    }
+
     /** Implement the Parcelable interface {@hide} */
     public int describeContents() {
         return 0;
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java
index 4a45825..4ec4cfc 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/wifi/java/android/net/wifi/WifiMonitor.java
@@ -107,7 +107,7 @@
      * <pre>
      * CTRL-EVENT-DRIVER-STATE state
      * </pre>
-     * <code>state</code> is either STARTED or STOPPED
+     * <code>state</code> can be HANGED
      */
     private static final String driverStateEvent = "DRIVER-STATE";
     /**
@@ -304,11 +304,7 @@
             if (state == null) {
                 return;
             }
-            if (state.equals("STOPPED")) {
-                mWifiStateMachine.notifyDriverStopped();
-            } else if (state.equals("STARTED")) {
-                mWifiStateMachine.notifyDriverStarted();
-            } else if (state.equals("HANGED")) {
+            if (state.equals("HANGED")) {
                 mWifiStateMachine.notifyDriverHung();
             }
         }
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 6df37bb..3df3736 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -212,22 +212,18 @@
     static final int SUP_CONNECTION_EVENT                 = BASE + 31;
     /* Connection to supplicant lost */
     static final int SUP_DISCONNECTION_EVENT              = BASE + 32;
-    /* Driver start completed */
-    static final int DRIVER_START_EVENT                   = BASE + 33;
-    /* Driver stop completed */
-    static final int DRIVER_STOP_EVENT                    = BASE + 34;
-    /* Network connection completed */
-    static final int NETWORK_CONNECTION_EVENT             = BASE + 36;
+   /* Network connection completed */
+    static final int NETWORK_CONNECTION_EVENT             = BASE + 33;
     /* Network disconnection completed */
-    static final int NETWORK_DISCONNECTION_EVENT          = BASE + 37;
+    static final int NETWORK_DISCONNECTION_EVENT          = BASE + 34;
     /* Scan results are available */
-    static final int SCAN_RESULTS_EVENT                   = BASE + 38;
+    static final int SCAN_RESULTS_EVENT                   = BASE + 35;
     /* Supplicate state changed */
-    static final int SUPPLICANT_STATE_CHANGE_EVENT        = BASE + 39;
+    static final int SUPPLICANT_STATE_CHANGE_EVENT        = BASE + 36;
     /* Password failure and EAP authentication failure */
-    static final int AUTHENTICATION_FAILURE_EVENT         = BASE + 40;
+    static final int AUTHENTICATION_FAILURE_EVENT         = BASE + 37;
     /* WPS overlap detected */
-    static final int WPS_OVERLAP_EVENT                    = BASE + 41;
+    static final int WPS_OVERLAP_EVENT                    = BASE + 38;
 
 
     /* Supplicant commands */
@@ -1421,6 +1417,35 @@
         return mNetworkInfo.getDetailedState();
     }
 
+
+    private SupplicantState handleSupplicantStateChange(Message message) {
+        StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
+        SupplicantState state = stateChangeResult.state;
+        // Supplicant state change
+        // [31-13] Reserved for future use
+        // [8 - 0] Supplicant state (as defined in SupplicantState.java)
+        // 50023 supplicant_state_changed (custom|1|5)
+        EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, state.ordinal());
+        mWifiInfo.setSupplicantState(state);
+        // Network id is only valid when we start connecting
+        if (SupplicantState.isConnecting(state)) {
+            mWifiInfo.setNetworkId(stateChangeResult.networkId);
+        } else {
+            mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
+        }
+
+        if (state == SupplicantState.ASSOCIATING) {
+            /* BSSID is valid only in ASSOCIATING state */
+            mWifiInfo.setBSSID(stateChangeResult.BSSID);
+        }
+        setNetworkDetailedState(WifiInfo.getDetailedStateOf(state));
+
+        mSupplicantStateTracker.sendMessage(Message.obtain(message));
+        mWpsStateMachine.sendMessage(Message.obtain(message));
+
+        return state;
+    }
+
     /**
      * Resets the Wi-Fi Connections by clearing any state, resetting any sockets
      * using the interface, stopping DHCP & disabling interface
@@ -1674,14 +1699,6 @@
         sendMessage(SCAN_RESULTS_EVENT);
     }
 
-    void notifyDriverStarted() {
-        sendMessage(DRIVER_START_EVENT);
-    }
-
-    void notifyDriverStopped() {
-        sendMessage(DRIVER_STOP_EVENT);
-    }
-
     void notifyDriverHung() {
         setWifiEnabled(false);
         setWifiEnabled(true);
@@ -1737,8 +1754,6 @@
                 case CMD_REASSOCIATE:
                 case SUP_CONNECTION_EVENT:
                 case SUP_DISCONNECTION_EVENT:
-                case DRIVER_START_EVENT:
-                case DRIVER_STOP_EVENT:
                 case NETWORK_CONNECTION_EVENT:
                 case NETWORK_DISCONNECTION_EVENT:
                 case SCAN_RESULTS_EVENT:
@@ -2284,13 +2299,19 @@
         public boolean processMessage(Message message) {
             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
             switch(message.what) {
-                case DRIVER_START_EVENT:
-                    transitionTo(mDriverStartedState);
+               case SUPPLICANT_STATE_CHANGE_EVENT:
+                    SupplicantState state = handleSupplicantStateChange(message);
+                    /* If suplicant is exiting out of INTERFACE_DISABLED state into
+                     * a state that indicates driver has started, it is ready to
+                     * receive driver commands
+                     */
+                    if (SupplicantState.isDriverActive(state)) {
+                        transitionTo(mDriverStartedState);
+                    }
                     break;
                     /* Queue driver commands & connection events */
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
-                case SUPPLICANT_STATE_CHANGE_EVENT:
                 case NETWORK_CONNECTION_EVENT:
                 case NETWORK_DISCONNECTION_EVENT:
                 case AUTHENTICATION_FAILURE_EVENT:
@@ -2429,8 +2450,11 @@
         public boolean processMessage(Message message) {
             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
             switch(message.what) {
-                case DRIVER_STOP_EVENT:
-                    transitionTo(mDriverStoppedState);
+                case SUPPLICANT_STATE_CHANGE_EVENT:
+                    SupplicantState state = handleSupplicantStateChange(message);
+                    if (state == SupplicantState.INTERFACE_DISABLED) {
+                        transitionTo(mDriverStoppedState);
+                    }
                     break;
                     /* Queue driver commands */
                 case CMD_START_DRIVER:
@@ -2465,11 +2489,23 @@
         public boolean processMessage(Message message) {
             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
             switch (message.what) {
-                case CMD_START_DRIVER:
-                    mWakeLock.acquire();
-                    WifiNative.startDriverCommand();
-                    transitionTo(mDriverStartingState);
-                    mWakeLock.release();
+               case CMD_START_DRIVER:
+                   mWakeLock.acquire();
+                   WifiNative.startDriverCommand();
+                   mWakeLock.release();
+                   break;
+                case SUPPLICANT_STATE_CHANGE_EVENT:
+                    SupplicantState state = handleSupplicantStateChange(message);
+                    /* A driver start causes supplicant to first report an INTERFACE_DISABLED
+                     * state before transitioning out of it for connection. Stay in
+                     * DriverStoppedState until we get an INTERFACE_DISABLED state and transition
+                     * to DriverStarting upon getting that
+                     * TODO: Fix this when the supplicant can be made to just transition out of
+                     * INTERFACE_DISABLED state when driver gets started
+                     */
+                    if (state == SupplicantState.INTERFACE_DISABLED) {
+                        transitionTo(mDriverStartingState);
+                    }
                     break;
                 default:
                     return NOT_HANDLED;
@@ -2535,29 +2571,8 @@
                     sendErrorBroadcast(WifiManager.WPS_OVERLAP_ERROR);
                     break;
                 case SUPPLICANT_STATE_CHANGE_EVENT:
-                    stateChangeResult = (StateChangeResult) message.obj;
-                    SupplicantState state = stateChangeResult.state;
-                    // Supplicant state change
-                    // [31-13] Reserved for future use
-                    // [8 - 0] Supplicant state (as defined in SupplicantState.java)
-                    // 50023 supplicant_state_changed (custom|1|5)
-                    EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, state.ordinal());
-                    mWifiInfo.setSupplicantState(state);
-                    // Network id is only valid when we start connecting
-                    if (SupplicantState.isConnecting(state)) {
-                        mWifiInfo.setNetworkId(stateChangeResult.networkId);
-                    } else {
-                        mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
-                    }
-
-                    if (state == SupplicantState.ASSOCIATING) {
-                        /* BSSID is valid only in ASSOCIATING state */
-                        mWifiInfo.setBSSID(stateChangeResult.BSSID);
-                    }
-
-                    mSupplicantStateTracker.sendMessage(Message.obtain(message));
-                    mWpsStateMachine.sendMessage(Message.obtain(message));
-                    break;
+                    handleSupplicantStateChange(message);
+                   break;
                     /* Do a redundant disconnect without transition */
                 case CMD_DISCONNECT:
                     WifiNative.disconnectCommand();
@@ -2964,12 +2979,7 @@
                     /* Ignore network disconnect */
                 case NETWORK_DISCONNECTION_EVENT:
                     break;
-                case SUPPLICANT_STATE_CHANGE_EVENT:
-                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;
-                    setNetworkDetailedState(WifiInfo.getDetailedStateOf(stateChangeResult.state));
-                    /* DriverStartedState does the rest of the handling */
-                    return NOT_HANDLED;
-                case CMD_START_SCAN:
+               case CMD_START_SCAN:
                     /* Disable background scan temporarily during a regular scan */
                     if (mEnableBackgroundScan) {
                         WifiNative.enableBackgroundScanCommand(false);