Merge "Don't match wrap_content/match_parent children with child count = 1. Bug #3328711" into honeycomb
diff --git a/api/current.xml b/api/current.xml
index f7721c4..bf004c7 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -43586,6 +43586,17 @@
 <parameter name="data" type="D">
 </parameter>
 </method>
+<method name="waitForLoader"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 </class>
 <class name="BroadcastReceiver"
  extends="java.lang.Object"
@@ -258096,7 +258107,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="arg0" type="T">
+<parameter name="t" type="T">
 </parameter>
 </method>
 </interface>
diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java
index d6bc959..01a2912 100644
--- a/core/java/android/content/AsyncTaskLoader.java
+++ b/core/java/android/content/AsyncTaskLoader.java
@@ -17,6 +17,9 @@
 package android.content;
 
 import android.os.AsyncTask;
+import android.util.Log;
+
+import java.util.concurrent.ExecutionException;
 
 /**
  * Abstract Loader that provides an {@link AsyncTask} to do the work.
@@ -24,6 +27,9 @@
  * @param <D> the data type to be loaded.
  */
 public abstract class AsyncTaskLoader<D> extends Loader<D> {
+
+    private static final String TAG = "AsyncTaskLoader";
+
     final class LoadTask extends AsyncTask<Void, Void, D> {
 
         private D result;
@@ -47,7 +53,7 @@
         }
     }
 
-    LoadTask mTask;
+    volatile LoadTask mTask;
 
     public AsyncTaskLoader(Context context) {
         super(context);
@@ -105,4 +111,25 @@
      * @return the result of the load
      */
     public abstract D loadInBackground();
+
+    /**
+     * Locks the current thread until the loader completes the current load
+     * operation. Returns immediately if there is no load operation running.
+     * Should not be called from the UI thread.
+     * <p>
+     * Used for testing.
+     */
+    public void waitForLoader() {
+        LoadTask task = mTask;
+        if (task != null) {
+            try {
+                task.get();
+            } catch (InterruptedException e) {
+                Log.w(TAG, e);
+            } catch (ExecutionException e) {
+                throw new RuntimeException("An error occured while executing waitForLoader()",
+                        e.getCause());
+            }
+        }
+    }
 }
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index 26a1440..4c2d123 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -412,6 +412,7 @@
                 db = mQuery.mDatabase.getDatabaseHandle(mQuery.mSql);
             } catch (IllegalStateException e) {
                 // for backwards compatibility, just return false
+                Log.w(TAG, "requery() failed " + e.getMessage(), e);
                 return false;
             }
             if (!db.equals(mQuery.mDatabase)) {
@@ -421,6 +422,7 @@
                     db.lock();
                 } catch (IllegalStateException e) {
                     // for backwards compatibility, just return false
+                    Log.w(TAG, "requery() failed " + e.getMessage(), e);
                     return false;
                 }
                 try {
@@ -429,6 +431,7 @@
                     mQuery = new SQLiteQuery(db, mQuery);
                 } catch (IllegalStateException e) {
                     // for backwards compatibility, just return false
+                    Log.w(TAG, "requery() failed " + e.getMessage(), e);
                     return false;
                 } finally {
                     db.unlock();
@@ -443,6 +446,7 @@
                 mQuery.requery();
             } catch (IllegalStateException e) {
                 // for backwards compatibility, just return false
+                Log.w(TAG, "requery() failed " + e.getMessage(), e);
                 return false;
             } finally {
                 queryThreadUnlock();
@@ -459,6 +463,7 @@
             result = super.requery();
         } catch (IllegalStateException e) {
             // for backwards compatibility, just return false
+            Log.w(TAG, "requery() failed " + e.getMessage(), e);
         }
         if (Config.LOGV) {
             long timeEnd = System.currentTimeMillis();
diff --git a/core/java/android/net/Downloads.java b/core/java/android/net/Downloads.java
index ddde5c1..ed6d103 100644
--- a/core/java/android/net/Downloads.java
+++ b/core/java/android/net/Downloads.java
@@ -196,7 +196,7 @@
          * @return a boolean whether the download is successful.
          */
         public boolean isSuccessful() {
-            return android.provider.Downloads.Impl.isStatusCompleted(statusCode);
+            return android.provider.Downloads.Impl.isStatusSuccess(statusCode);
         }
     }
 
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index fb4bed7..9f0ea32 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -1028,6 +1028,13 @@
             public static final String ALBUM_ARTIST = "album_artist";
 
             /**
+             * Whether the song is part of a compilation
+             * <P>Type: TEXT</P>
+             * @hide
+             */
+            public static final String COMPILATION = "compilation";
+
+            /**
              * A non human readable key calculated from the ARTIST, used for
              * searching, sorting and grouping
              * <P>Type: TEXT</P>
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index cdb6959..de1faa2 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -488,8 +488,10 @@
                         }
                     }
                 }
-                WebViewWorker.getHandler().sendEmptyMessage(
-                        WebViewWorker.MSG_TRIM_CACHE);
+                if (!JniUtil.useChromiumHttpStack()) {
+                    WebViewWorker.getHandler().sendEmptyMessage(
+                            WebViewWorker.MSG_TRIM_CACHE);
+                }
                 break;
             }
 
diff --git a/core/java/android/webkit/CacheLoader.java b/core/java/android/webkit/CacheLoader.java
index 05c02b0..0721045 100644
--- a/core/java/android/webkit/CacheLoader.java
+++ b/core/java/android/webkit/CacheLoader.java
@@ -18,6 +18,7 @@
 
 import android.net.http.Headers;
 import android.text.TextUtils;
+import android.webkit.JniUtil;
 
 /**
  * This class is a concrete implementation of StreamLoader that uses a
@@ -36,6 +37,9 @@
      */
     CacheLoader(LoadListener loadListener, CacheManager.CacheResult result) {
         super(loadListener);
+
+        assert !JniUtil.useChromiumHttpStack();
+
         mCacheResult = result;
     }
 
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index 9eecafa..e46daad 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -190,6 +190,11 @@
      * @param context The application context.
      */
     static void init(Context context) {
+        if (JniUtil.useChromiumHttpStack()) {
+            // TODO: Need to init mBaseDir.
+            return;
+        }
+
         mDataBase = WebViewDatabase.getInstance(context.getApplicationContext());
         mBaseDir = new File(context.getCacheDir(), "webviewCache");
         if (createCacheDirectory() && mClearCacheOnInit) {
@@ -204,6 +209,8 @@
      * @return true if the cache directory didn't exist and was created.
      */
     static private boolean createCacheDirectory() {
+        assert !JniUtil.useChromiumHttpStack();
+
         if (!mBaseDir.exists()) {
             if(!mBaseDir.mkdirs()) {
                 Log.w(LOGTAG, "Unable to create webviewCache directory");
@@ -245,6 +252,8 @@
      * @param disabled Whether the cache should be disabled
      */
     static void setCacheDisabled(boolean disabled) {
+        assert !JniUtil.useChromiumHttpStack();
+
         if (disabled == mDisabled) {
             return;
         }
@@ -269,6 +278,8 @@
     // only called from WebViewWorkerThread
     // make sure to call enableTransaction/disableTransaction in pair
     static boolean enableTransaction() {
+        assert !JniUtil.useChromiumHttpStack();
+
         if (++mRefCount == 1) {
             mDataBase.startCacheTransaction();
             return true;
@@ -279,6 +290,8 @@
     // only called from WebViewWorkerThread
     // make sure to call enableTransaction/disableTransaction in pair
     static boolean disableTransaction() {
+        assert !JniUtil.useChromiumHttpStack();
+
         if (--mRefCount == 0) {
             mDataBase.endCacheTransaction();
             return true;
@@ -289,12 +302,16 @@
     // only called from WebViewWorkerThread
     // make sure to call startTransaction/endTransaction in pair
     static boolean startTransaction() {
+        assert !JniUtil.useChromiumHttpStack();
+
         return mDataBase.startCacheTransaction();
     }
 
     // only called from WebViewWorkerThread
     // make sure to call startTransaction/endTransaction in pair
     static boolean endTransaction() {
+        assert !JniUtil.useChromiumHttpStack();
+
         boolean ret = mDataBase.endCacheTransaction();
         if (++mTrimCacheCount >= TRIM_CACHE_INTERVAL) {
             mTrimCacheCount = 0;
@@ -347,8 +364,12 @@
             return null;
         }
 
-        String databaseKey = getDatabaseKey(url, postIdentifier);
+        if (JniUtil.useChromiumHttpStack()) {
+            // TODO: Implement this.
+            return null;
+        }
 
+        String databaseKey = getDatabaseKey(url, postIdentifier);
         CacheResult result = mDataBase.getCache(databaseKey);
         if (result == null) {
             return null;
@@ -415,6 +436,11 @@
     @Deprecated
     public static CacheResult createCacheFile(String url, int statusCode,
             Headers headers, String mimeType, boolean forceCache) {
+        if (JniUtil.useChromiumHttpStack()) {
+            // TODO: Implement this.
+            return null;
+        }
+
         return createCacheFile(url, statusCode, headers, mimeType, 0,
                 forceCache);
     }
@@ -422,6 +448,8 @@
     static CacheResult createCacheFile(String url, int statusCode,
             Headers headers, String mimeType, long postIdentifier,
             boolean forceCache) {
+        assert !JniUtil.useChromiumHttpStack();
+
         if (!forceCache && mDisabled) {
             return null;
         }
@@ -493,6 +521,11 @@
             return;
         }
 
+        if (JniUtil.useChromiumHttpStack()) {
+            // TODO: Implement this.
+            return;
+        }
+
         if (!cacheRet.outFile.exists()) {
             // the file in the cache directory can be removed by the system
             return;
@@ -520,6 +553,8 @@
     }
 
     static boolean cleanupCacheFile(CacheResult cacheRet) {
+        assert !JniUtil.useChromiumHttpStack();
+
         try {
             cacheRet.outStream.close();
         } catch (IOException e) {
@@ -534,6 +569,8 @@
      * @return Whether the removal succeeded.
      */
     static boolean removeAllCacheFiles() {
+        assert !JniUtil.useChromiumHttpStack();
+
         // Note, this is called before init() when the database is
         // created or upgraded.
         if (mBaseDir == null) {
@@ -570,6 +607,8 @@
     }
 
     static void trimCacheIfNeeded() {
+        assert !JniUtil.useChromiumHttpStack();
+
         if (mDataBase.getCacheTotalSize() > CACHE_THRESHOLD) {
             List<String> pathList = mDataBase.trimCache(CACHE_TRIM_AMOUNT);
             int size = pathList.size();
@@ -603,6 +642,8 @@
     }
 
     static void clearCache() {
+        assert !JniUtil.useChromiumHttpStack();
+
         // delete database
         mDataBase.clearCache();
     }
@@ -617,12 +658,16 @@
     }
 
     private static String getDatabaseKey(String url, long postIdentifier) {
+        assert !JniUtil.useChromiumHttpStack();
+
         if (postIdentifier == 0) return url;
         return postIdentifier + url;
     }
 
     @SuppressWarnings("deprecation")
     private static void setupFiles(String url, CacheResult cacheRet) {
+        assert !JniUtil.useChromiumHttpStack();
+
         if (true) {
             // Note: SHA1 is much stronger hash. But the cost of setupFiles() is
             // 3.2% cpu time for a fresh load of nytimes.com. While a simple
@@ -689,6 +734,8 @@
     }
 
     private static void appendAsHex(int i, StringBuffer ret) {
+        assert !JniUtil.useChromiumHttpStack();
+
         String hex = Integer.toHexString(i);
         switch (hex.length()) {
             case 1:
@@ -718,6 +765,8 @@
 
     private static CacheResult parseHeaders(int statusCode, Headers headers,
             String mimeType) {
+        assert !JniUtil.useChromiumHttpStack();
+
         // if the contentLength is already larger than CACHE_MAX_SIZE, skip it
         if (headers.getContentLength() > CACHE_MAX_SIZE) return null;
 
@@ -734,8 +783,7 @@
         CacheResult ret = new CacheResult();
         ret.httpStatusCode = statusCode;
 
-        String location = headers.getLocation();
-        if (location != null) ret.location = location;
+        ret.location = headers.getLocation();
 
         ret.expires = -1;
         ret.expiresString = headers.getExpires();
@@ -754,15 +802,9 @@
             }
         }
 
-        String contentDisposition = headers.getContentDisposition();
-        if (contentDisposition != null) {
-            ret.contentdisposition = contentDisposition;
-        }
+        ret.contentdisposition = headers.getContentDisposition();
 
-        String crossDomain = headers.getXPermittedCrossDomainPolicies();
-        if (crossDomain != null) {
-            ret.crossDomain = crossDomain;
-        }
+        ret.crossDomain = headers.getXPermittedCrossDomainPolicies();
 
         // lastModified and etag may be set back to http header. So they can't
         // be empty string.
@@ -772,7 +814,9 @@
         }
 
         String etag = headers.getEtag();
-        if (etag != null && etag.length() > 0) ret.etag = etag;
+        if (etag != null && etag.length() > 0) {
+            ret.etag = etag;
+        }
 
         String cacheControl = headers.getCacheControl();
         if (cacheControl != null) {
diff --git a/core/java/android/webkit/FindActionModeCallback.java b/core/java/android/webkit/FindActionModeCallback.java
index 842f6c8..700d313 100644
--- a/core/java/android/webkit/FindActionModeCallback.java
+++ b/core/java/android/webkit/FindActionModeCallback.java
@@ -143,6 +143,7 @@
     /*
      * Update the string which tells the user how many matches were found, and
      * which match is currently highlighted.
+     * Not to be called when mNumberOfMatches is 0.
      */
     private void updateMatchesString() {
         String template = mResources.getQuantityString(
@@ -196,6 +197,11 @@
             findAll();
             return true;
         }
+        if (0 == mNumberOfMatches) {
+            // There are no matches, so moving to the next match will not do
+            // anything.
+            return true;
+        }
         switch(item.getItemId()) {
             case com.android.internal.R.id.find_prev:
                 findNext(false);
diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java
index 951dab3..2b44775 100644
--- a/core/java/android/webkit/FrameLoader.java
+++ b/core/java/android/webkit/FrameLoader.java
@@ -22,6 +22,7 @@
 import android.os.Build;
 import android.util.Log;
 import android.webkit.CacheManager.CacheResult;
+import android.webkit.JniUtil;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -56,6 +57,8 @@
     
     FrameLoader(LoadListener listener, WebSettings settings,
             String method, WebResourceResponse interceptResponse) {
+        assert !JniUtil.useChromiumHttpStack();
+
         mListener = listener;
         mHeaders = null;
         mMethod = method;
@@ -148,9 +151,10 @@
 
     }
 
-    /* package */
-    static boolean handleLocalFile(String url, LoadListener loadListener,
+    private static boolean handleLocalFile(String url, LoadListener loadListener,
             WebSettings settings) {
+        assert !JniUtil.useChromiumHttpStack();
+
         // Attempt to decode the percent-encoded url before passing to the
         // local loaders.
         try {
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index a29299d..6d1d39a 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -35,6 +35,7 @@
 import android.os.Message;
 import android.util.Log;
 import android.webkit.CacheManager.CacheResult;
+import android.webkit.JniUtil;
 
 import com.android.internal.R;
 
@@ -156,6 +157,8 @@
             int nativeLoader, boolean synchronous, boolean isMainPageLoader,
             boolean isMainResource, boolean userGesture, long postIdentifier,
             String username, String password) {
+        assert !JniUtil.useChromiumHttpStack();
+
         if (DebugFlags.LOAD_LISTENER) {
             Log.v(LOGTAG, "LoadListener constructor url=" + url);
         }
@@ -991,6 +994,7 @@
      * URL.
      */
     static boolean willLoadFromCache(String url, long identifier) {
+        assert !JniUtil.useChromiumHttpStack();
         boolean inCache =
                 CacheManager.getCacheFile(url, identifier, null) != null;
         if (DebugFlags.LOAD_LISTENER) {
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 43ec378..5479d55 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -38,6 +38,7 @@
 import android.webkit.DeviceMotionService;
 import android.webkit.DeviceMotionAndOrientationManager;
 import android.webkit.DeviceOrientationService;
+import android.webkit.JniUtil;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -1201,15 +1202,19 @@
                             Process.setThreadPriority(mTid,
                                     Process.THREAD_PRIORITY_BACKGROUND);
                             pauseTimers();
-                            WebViewWorker.getHandler().sendEmptyMessage(
-                                    WebViewWorker.MSG_PAUSE_CACHE_TRANSACTION);
+                            if (!JniUtil.useChromiumHttpStack()) {
+                                WebViewWorker.getHandler().sendEmptyMessage(
+                                        WebViewWorker.MSG_PAUSE_CACHE_TRANSACTION);
+                            }
                             break;
 
                         case RESUME_TIMERS:
                             Process.setThreadPriority(mTid, mSavedPriority);
                             resumeTimers();
-                            WebViewWorker.getHandler().sendEmptyMessage(
-                                    WebViewWorker.MSG_RESUME_CACHE_TRANSACTION);
+                            if (!JniUtil.useChromiumHttpStack()) {
+                                WebViewWorker.getHandler().sendEmptyMessage(
+                                        WebViewWorker.MSG_RESUME_CACHE_TRANSACTION);
+                            }
                             break;
 
                         case ON_PAUSE:
@@ -1733,7 +1738,7 @@
 
     private void clearCache(boolean includeDiskFiles) {
         mBrowserFrame.clearCache();
-        if (includeDiskFiles) {
+        if (includeDiskFiles && !JniUtil.useChromiumHttpStack()) {
             CacheManager.removeAllCacheFiles();
         }
     }
@@ -2150,12 +2155,14 @@
     // called by JNI
     private void sendNotifyProgressFinished() {
         sendUpdateTextEntry();
-        // as CacheManager can behave based on database transaction, we need to
-        // call tick() to trigger endTransaction
-        WebViewWorker.getHandler().removeMessages(
-                WebViewWorker.MSG_CACHE_TRANSACTION_TICKER);
-        WebViewWorker.getHandler().sendEmptyMessage(
-                WebViewWorker.MSG_CACHE_TRANSACTION_TICKER);
+        if (!JniUtil.useChromiumHttpStack()) {
+            // as CacheManager can behave based on database transaction, we need to
+            // call tick() to trigger endTransaction
+            WebViewWorker.getHandler().removeMessages(
+                    WebViewWorker.MSG_CACHE_TRANSACTION_TICKER);
+            WebViewWorker.getHandler().sendEmptyMessage(
+                    WebViewWorker.MSG_CACHE_TRANSACTION_TICKER);
+        }
         contentDraw();
     }
 
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index 8f89678..7b9def0 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -33,6 +33,7 @@
 import android.util.Log;
 import android.webkit.CookieManager.Cookie;
 import android.webkit.CacheManager.CacheResult;
+import android.webkit.JniUtil;
 
 public class WebViewDatabase {
     private static final String DATABASE_FILE = "webview.db";
@@ -202,6 +203,17 @@
             return;
         }
 
+        initDatabase(context);
+        if (!JniUtil.useChromiumHttpStack()) {
+            initCacheDatabase(context);
+        }
+
+        // Thread done, notify.
+        mInitialized = true;
+        notify();
+    }
+
+    private void initDatabase(Context context) {
         try {
             mDatabase = context.openOrCreateDatabase(DATABASE_FILE, 0, null);
         } catch (SQLiteException e) {
@@ -234,6 +246,10 @@
         // improves performance as database's ReentrantLock is
         // expansive
         mDatabase.setLockingEnabled(false);
+    }
+
+    private void initCacheDatabase(Context context) {
+        assert !JniUtil.useChromiumHttpStack();
 
         try {
             mCacheDatabase = context.openOrCreateDatabase(
@@ -306,10 +322,6 @@
                 .getColumnIndex(CACHE_CONTENTDISPOSITION_COL);
         mCacheCrossDomainColIndex = mCacheInserter
                 .getColumnIndex(CACHE_CROSSDOMAIN_COL);
-
-        // Thread done, notify.
-        mInitialized = true;
-        notify();
     }
 
     private static void upgradeDatabase() {
@@ -668,6 +680,8 @@
      * @return CacheResult The CacheManager.CacheResult
      */
     CacheResult getCache(String url) {
+        assert !JniUtil.useChromiumHttpStack();
+
         if (url == null || !checkInitialized()) {
             return null;
         }
@@ -708,6 +722,8 @@
      * @param url The url
      */
     void removeCache(String url) {
+        assert !JniUtil.useChromiumHttpStack();
+
         if (url == null || !checkInitialized()) {
             return;
         }
@@ -722,6 +738,8 @@
      * @param c The CacheManager.CacheResult
      */
     void addCache(String url, CacheResult c) {
+        assert !JniUtil.useChromiumHttpStack();
+
         if (url == null || !checkInitialized()) {
             return;
         }
diff --git a/core/java/android/webkit/WebViewWorker.java b/core/java/android/webkit/WebViewWorker.java
index c488150..6a4ca29 100644
--- a/core/java/android/webkit/WebViewWorker.java
+++ b/core/java/android/webkit/WebViewWorker.java
@@ -125,6 +125,7 @@
                 break;
             }
             case MSG_CREATE_CACHE: {
+                assert !JniUtil.useChromiumHttpStack();
                 CacheCreateData data = (CacheCreateData) msg.obj;
                 CacheManager.CacheResult cache = CacheManager.createCacheFile(
                         data.mUrl, data.mStatusCode, data.mHeaders,
@@ -137,6 +138,7 @@
                 break;
             }
             case MSG_UPDATE_CACHE_ENCODING: {
+                assert !JniUtil.useChromiumHttpStack();
                 CacheEncoding data = (CacheEncoding) msg.obj;
                 CacheManager.CacheResult cache = mCacheResultMap
                         .get(data.mListener);
@@ -146,6 +148,7 @@
                 break;
             }
             case MSG_APPEND_CACHE: {
+                assert !JniUtil.useChromiumHttpStack();
                 CacheData data = (CacheData) msg.obj;
                 CacheManager.CacheResult cache = mCacheResultMap
                         .get(data.mListener);
@@ -168,6 +171,7 @@
                 break;
             }
             case MSG_SAVE_CACHE: {
+                assert !JniUtil.useChromiumHttpStack();
                 CacheSaveData data = (CacheSaveData) msg.obj;
                 CacheManager.CacheResult cache = mCacheResultMap
                         .get(data.mListener);
@@ -178,6 +182,7 @@
                 break;
             }
             case MSG_REMOVE_CACHE: {
+                assert !JniUtil.useChromiumHttpStack();
                 LoadListener listener = (LoadListener) msg.obj;
                 CacheManager.CacheResult cache = mCacheResultMap.get(listener);
                 if (cache != null) {
@@ -187,14 +192,17 @@
                 break;
             }
             case MSG_TRIM_CACHE: {
+                assert !JniUtil.useChromiumHttpStack();
                 CacheManager.trimCacheIfNeeded();
                 break;
             }
             case MSG_CLEAR_CACHE: {
+                assert !JniUtil.useChromiumHttpStack();
                 CacheManager.clearCache();
                 break;
             }
             case MSG_CACHE_TRANSACTION_TICKER: {
+                assert !JniUtil.useChromiumHttpStack();
                 if (!mCacheTickersBlocked) {
                     CacheManager.endTransaction();
                     CacheManager.startTransaction();
@@ -204,6 +212,7 @@
                 break;
             }
             case MSG_PAUSE_CACHE_TRANSACTION: {
+                assert !JniUtil.useChromiumHttpStack();
                 if (CacheManager.disableTransaction()) {
                     mCacheTickersBlocked = true;
                     removeMessages(MSG_CACHE_TRANSACTION_TICKER);
@@ -211,6 +220,7 @@
                 break;
             }
             case MSG_RESUME_CACHE_TRANSACTION: {
+                assert !JniUtil.useChromiumHttpStack();
                 if (CacheManager.enableTransaction()) {
                     mCacheTickersBlocked = false;
                     sendEmptyMessageDelayed(MSG_CACHE_TRANSACTION_TICKER,
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index fa74b4c..da27ea8 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -738,16 +738,6 @@
         boolean smoothScrollbar = a.getBoolean(R.styleable.AbsListView_smoothScrollbar, true);
         setSmoothScrollbarEnabled(smoothScrollbar);
 
-        final int adapterId = a.getResourceId(R.styleable.AbsListView_adapter, 0);
-        if (adapterId != 0) {
-            final Context c = context;
-            post(new Runnable() {
-                public void run() {
-                    setAdapter(Adapters.loadAdapter(c, adapterId));
-                }
-            });
-        }
-
         setChoiceMode(a.getInt(R.styleable.AbsListView_choiceMode, CHOICE_MODE_NONE));
         setFastScrollAlwaysVisible(
                 a.getBoolean(R.styleable.AbsListView_fastScrollAlwaysVisible, false));
diff --git a/core/java/android/widget/Adapters.java b/core/java/android/widget/Adapters.java
deleted file mode 100644
index 3849aa4..0000000
--- a/core/java/android/widget/Adapters.java
+++ /dev/null
@@ -1,1235 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.database.Cursor;
-import android.graphics.BitmapFactory;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.util.AttributeSet;
-import android.util.Xml;
-import android.view.View;
-
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-/**
- * @hide -- not sure if we really want this in the framework.
- *
- * <p>This class can be used to load {@link android.widget.Adapter adapters} defined in
- * XML resources. XML-defined adapters can be used to easily create adapters in your
- * own application or to pass adapters to other processes.</p>
- * 
- * <h2>Types of adapters</h2>
- * <p>Adapters defined using XML resources can only be one of the following supported
- * types. Arbitrary adapters are not supported to guarantee the safety of the loaded
- * code when adapters are loaded across packages.</p>
- * <ul>
- *  <li><a href="#xml-cursor-adapter">Cursor adapter</a>: a cursor adapter can be used
- *  to display the content of a cursor, most often coming from a content provider</li>
- * </ul>
- * <p>The complete XML format definition of each adapter type is available below.</p>
- * 
- * <a name="xml-cursor-adapter"></a>
- * <h2>Cursor adapter</h2>
- * <p>A cursor adapter XML definition starts with the
- * <a href="#xml-cursor-adapter-tag"><code>&lt;cursor-adapter /&gt;</code></a>
- * tag and may contain one or more instances of the following tags:</p>
- * <ul>
- *  <li><a href="#xml-cursor-adapter-select-tag"><code>&lt;select /&gt;</code></a></li>
- *  <li><a href="#xml-cursor-adapter-bind-tag"><code>&lt;bind /&gt;</code></a></li>
- * </ul>
- * 
- * <a name="xml-cursor-adapter-tag"></a>
- * <h3>&lt;cursor-adapter /&gt;</h3>
- * <p>The <code>&lt;cursor-adapter /&gt;</code> element defines the beginning of the
- * document and supports the following attributes:</p>
- * <ul>
- *  <li><code>android:layout</code>: Reference to the XML layout to be inflated for
- *  each item of the adapter. This attribute is mandatory.</li>
- *  <li><code>android:selection</code>: Selection expression, used when the
- *  <code>android:uri</code> attribute is defined or when the adapter is loaded with
- *  {@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, String, Object[])}.
- *  This attribute is optional.</li>
- *  <li><code>android:sortOrder</code>: Sort expression, used when the
- *  <code>android:uri</code> attribute is defined or when the adapter is loaded with
- *  {@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, String, Object[])}.
- *  This attribute is optional.</li>
- *  <li><code>android:uri</code>: URI of the content provider to query to retrieve a cursor.
- *  Specifying this attribute is equivalent to calling
- *  {@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, String, Object[])}.
- *  If you call this method, the value of the XML attribute is ignored. This attribute is
- *  optional.</li>
- * </ul>
- * <p>In addition, you can specify one or more instances of
- * <a href="#xml-cursor-adapter-select-tag"><code>&lt;select /&gt;</code></a> and
- * <a href="#xml-cursor-adapter-bind-tag"><code>&lt;bind /&gt;</code></a> tags as children
- * of <code>&lt;cursor-adapter /&gt;</code>.</p>
- * 
- * <a name="xml-cursor-adapter-select-tag"></a>
- * <h3>&lt;select /&gt;</h3>
- * <p>The <code>&lt;select /&gt;</code> tag is used to select columns from the cursor
- * when doing the query. This can be very useful when using transformations in the
- * <code>&lt;bind /&gt;</code> elements. It can also be very useful if you are providing
- * your own <a href="#xml-cursor-adapter-bind-data-types">binder</a> or
- * <a href="#xml-cursor-adapter-bind-data-types">transformation</a> classes.
- * <code>&lt;select /&gt;</code> elements are ignored if you supply the cursor yourself.</p>
- * <p>The <code>&lt;select /&gt;</code> supports the following attributes:</p>
- * <ul>
- *  <li><code>android:column</code>: Name of the column to select in the cursor during the
- *  query operation</li>
- * </ul>
- * <p><strong>Note:</strong> The column named <code>_id</code> is always implicitly
- * selected.</p>
- * 
- * <a name="xml-cursor-adapter-bind-tag"></a>
- * <h3>&lt;bind /&gt;</h3>
- * <p>The <code>&lt;bind /&gt;</code> tag is used to bind a column from the cursor to
- * a {@link android.view.View}. A column bound using this tag is automatically selected
- * during the query and a matching
- * <a href="#xml-cursor-adapter-select-tag"><code>&lt;select /&gt;</code> tag is therefore
- * not required.</p>
- * 
- * <p>Each binding is declared as a one to one matching but
- * custom binder classes or special
- * <a href="#xml-cursor-adapter-bind-data-transformation">data transformations</a> can
- * allow you to bind several columns to a single view. In this case you must use the
- * <a href="#xml-cursor-adapter-select-tag"><code>&lt;select /&gt;</code> tag to make
- * sure any required column is part of the query.</p>
- * 
- * <p>The <code>&lt;bind /&gt;</code> tag supports the following attributes:</p>
- * <ul>
- *  <li><code>android:from</code>: The name of the column to bind from.
- *  This attribute is mandatory. Note that <code>@</code> which are not used to reference resources
- *  should be backslash protected as in <code>\@</code>.</li>
- *  <li><code>android:to</code>: The id of the view to bind to. This attribute is mandatory.</li>
- *  <li><code>android:as</code>: The <a href="#xml-cursor-adapter-bind-data-types">data type</a>
- *  of the binding. This attribute is mandatory.</li>
- * </ul>
- * 
- * <p>In addition, a <code>&lt;bind /&gt;</code> can contain zero or more instances of
- * <a href="#xml-cursor-adapter-bind-data-transformation">data transformations</a> children
- * tags.</p>
- *
- * <a name="xml-cursor-adapter-bind-data-types"></a>
- * <h4>Binding data types</h4>
- * <p>For a binding to occur the data type of the bound column/view pair must be specified.
- * The following data types are currently supported:</p>
- * <ul>
- *  <li><code>string</code>: The content of the column is interpreted as a string and must be
- *  bound to a {@link android.widget.TextView}</li>
- *  <li><code>image</code>: The content of the column is interpreted as a blob describing an
- *  image and must be bound to an {@link android.widget.ImageView}</li>
- *  <li><code>image-uri</code>: The content of the column is interpreted as a URI to an image
- *  and must be bound to an {@link android.widget.ImageView}</li>
- *  <li><code>drawable</code>: The content of the column is interpreted as a resource id to a
- *  drawable and must be bound to an {@link android.widget.ImageView}</li>
- *  <li><code>tag</code>: The content of the column is interpreted as a string and will be set as
- *  the tag (using {@link View#setTag(Object)} of the associated View. This can be used to
- *  associate meta-data to your view, that can be used for instance by a listener.</li>
- *  <li>A fully qualified class name: The name of a class corresponding to an implementation of
- *  {@link android.widget.Adapters.CursorBinder}. Cursor binders can be used to provide
- *  bindings not supported by default. Custom binders cannot be used with
- *  {@link android.content.Context#isRestricted() restricted contexts}, for instance in an
- *  application widget</li>
- * </ul>
- * 
- * <a name="xml-cursor-adapter-bind-transformation"></a>
- * <h4>Binding transformations</h4>
- * <p>When defining a data binding you can specify an optional transformation by using one
- * of the following tags as a child of a <code>&lt;bind /&gt;</code> elements:</p>
- * <ul>
- *  <li><code>&lt;map /&gt;</code>: Maps a constant string to a string or a resource. Use
- *  one instance of this tag per value you want to map</li>
- *  <li><code>&lt;transform /&gt;</code>: Transforms a column's value using an expression
- *  or an instance of {@link android.widget.Adapters.CursorTransformation}</li>
- * </ul>
- * <p>While several <code>&lt;map /&gt;</code> tags can be used at the same time, you cannot
- * mix <code>&lt;map /&gt;</code> and <code>&lt;transform /&gt;</code> tags. If several
- * <code>&lt;transform /&gt;</code> tags are specified, only the last one is retained.</p>
- * 
- * <a name="xml-cursor-adapter-bind-transformation-map" />
- * <p><strong>&lt;map /&gt;</strong></p>
- * <p>A map element simply specifies a value to match from and a value to match to. When
- * a column's value equals the value to match from, it is replaced with the value to match
- * to. The following attributes are supported:</p>
- * <ul>
- *  <li><code>android:fromValue</code>: The value to match from. This attribute is mandatory</li>
- *  <li><code>android:toValue</code>: The value to match to. This value can be either a string
- *  or a resource identifier. This value is interpreted as a resource identifier when the
- *  data binding is of type <code>drawable</code>. This attribute is mandatory</li>
- * </ul>
- * 
- * <a name="xml-cursor-adapter-bind-transformation-transform"></a>
- * <p><strong>&lt;transform /&gt;</strong></p>
- * <p>A simple transform that occurs either by calling a specified class or by performing
- * simple text substitution. The following attributes are supported:</p>
- * <ul>
- *  <li><code>android:withExpression</code>: The transformation expression. The expression is
- *  a string containing column names surrounded with curly braces { and }. During the
- *  transformation each column name is replaced by its value. All columns must have been
- *  selected in the query. An example of expression is <code>"First name: {first_name},
- *  last name: {last_name}"</code>. This attribute is mandatory
- *  if <code>android:withClass</code> is not specified and ignored if <code>android:withClass</code>
- *  is specified</li>
- *  <li><code>android:withClass</code>: A fully qualified class name corresponding to an
- *  implementation of {@link android.widget.Adapters.CursorTransformation}. Custom
- *  transformations cannot be used with
- *  {@link android.content.Context#isRestricted() restricted contexts}, for instance in
- *  an app widget This attribute is mandatory if <code>android:withExpression</code> is
- *  not specified</li>
- * </ul>
- * 
- * <h3>Example</h3>
- * <p>The following example defines a cursor adapter that queries all the contacts with
- * a phone number using the contacts content provider. Each contact is displayed with
- * its display name, its favorite status and its photo. To display photos, a custom data
- * binder is declared:</p>
- * 
- * <pre class="prettyprint">
- * &lt;cursor-adapter xmlns:android="http://schemas.android.com/apk/res/android"
- *     android:uri="content://com.android.contacts/contacts"
- *     android:selection="has_phone_number=1"
- *     android:layout="@layout/contact_item"&gt;
- *
- *     &lt;bind android:from="display_name" android:to="@id/name" android:as="string" /&gt;
- *     &lt;bind android:from="starred" android:to="@id/star" android:as="drawable"&gt;
- *         &lt;map android:fromValue="0" android:toValue="@android:drawable/star_big_off" /&gt;
- *         &lt;map android:fromValue="1" android:toValue="@android:drawable/star_big_on" /&gt;
- *     &lt;/bind&gt;
- *     &lt;bind android:from="_id" android:to="@id/name"
- *              android:as="com.google.android.test.adapters.ContactPhotoBinder" /&gt;
- *
- * &lt;/cursor-adapter&gt;
- * </pre>
- * 
- * <h3>Related APIs</h3>
- * <ul>
- *  <li>{@link android.widget.Adapters#loadAdapter(android.content.Context, int, Object[])}</li>
- *  <li>{@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, android.database.Cursor, Object[])}</li>
- *  <li>{@link android.widget.Adapters#loadCursorAdapter(android.content.Context, int, String, Object[])}</li>
- *  <li>{@link android.widget.Adapters.CursorBinder}</li>
- *  <li>{@link android.widget.Adapters.CursorTransformation}</li>
- *  <li>{@link android.widget.CursorAdapter}</li>
- * </ul>
- * 
- * @see android.widget.Adapter
- * @see android.content.ContentProvider
- * 
- * attr ref android.R.styleable#CursorAdapter_layout
- * attr ref android.R.styleable#CursorAdapter_selection
- * attr ref android.R.styleable#CursorAdapter_sortOrder
- * attr ref android.R.styleable#CursorAdapter_uri
- * attr ref android.R.styleable#CursorAdapter_BindItem_as
- * attr ref android.R.styleable#CursorAdapter_BindItem_from
- * attr ref android.R.styleable#CursorAdapter_BindItem_to
- * attr ref android.R.styleable#CursorAdapter_MapItem_fromValue
- * attr ref android.R.styleable#CursorAdapter_MapItem_toValue
- * attr ref android.R.styleable#CursorAdapter_SelectItem_column
- * attr ref android.R.styleable#CursorAdapter_TransformItem_withClass
- * attr ref android.R.styleable#CursorAdapter_TransformItem_withExpression
- */
-@SuppressWarnings({"JavadocReference"})
-public class Adapters {
-    private static final String ADAPTER_CURSOR = "cursor-adapter";
-
-    /**
-     * <p>Interface used to bind a {@link android.database.Cursor} column to a View. This
-     * interface can be used to provide bindings for data types not supported by the
-     * standard implementation of {@link android.widget.Adapters}.</p>
-     * 
-     * <p>A binder is provided with a cursor transformation which may or may not be used
-     * to transform the value retrieved from the cursor. The transformation is guaranteed
-     * to never be null so it's always safe to apply the transformation.</p>
-     * 
-     * <p>The binder is associated with a Context but can be re-used with multiple cursors.
-     * As such, the implementation should make no assumption about the Cursor in use.</p>
-     *
-     * @see android.view.View 
-     * @see android.database.Cursor
-     * @see android.widget.Adapters.CursorTransformation
-     */
-    public static abstract class CursorBinder {
-        /**
-         * <p>The context associated with this binder.</p>
-         */
-        protected final Context mContext;
-
-        /**
-         * <p>The transformation associated with this binder. This transformation is never
-         * null and may or may not be applied to the Cursor data during the
-         * {@link #bind(android.view.View, android.database.Cursor, int)} operation.</p>
-         * 
-         * @see #bind(android.view.View, android.database.Cursor, int) 
-         */
-        protected final CursorTransformation mTransformation;
-
-        /**
-         * <p>Creates a new Cursor binder.</p> 
-         * 
-         * @param context The context associated with this binder.
-         * @param transformation The transformation associated with this binder. This
-         *        transformation may or may not be applied by the binder and is guaranteed
-         *        to not be null.
-         */
-        public CursorBinder(Context context, CursorTransformation transformation) {
-            mContext = context;
-            mTransformation = transformation;
-        }
-
-        /**
-         * <p>Binds the specified Cursor column to the supplied View. The binding operation
-         * can query other Cursor columns as needed. During the binding operation, values
-         * retrieved from the Cursor may or may not be transformed using this binder's
-         * cursor transformation.</p>
-         * 
-         * @param view The view to bind data to.
-         * @param cursor The cursor to bind data from.
-         * @param columnIndex The column index in the cursor where the data to bind resides.
-         * 
-         * @see #mTransformation
-         * 
-         * @return True if the column was successfully bound to the View, false otherwise.
-         */
-        public abstract boolean bind(View view, Cursor cursor, int columnIndex);
-    }
-
-    /**
-     * <p>Interface used to transform data coming out of a {@link android.database.Cursor}
-     * before it is bound to a {@link android.view.View}.</p>
-     * 
-     * <p>Transformations are used to transform text-based data (in the form of a String),
-     * or to transform data into a resource identifier. A default implementation is provided
-     * to generate resource identifiers.</p>
-     * 
-     * @see android.database.Cursor
-     * @see android.widget.Adapters.CursorBinder
-     */
-    public static abstract class CursorTransformation {
-        /**
-         * <p>The context associated with this transformation.</p>
-         */
-        protected final Context mContext;
-
-        /**
-         * <p>Creates a new Cursor transformation.</p>
-         * 
-         * @param context The context associated with this transformation.
-         */
-        public CursorTransformation(Context context) {
-            mContext = context;
-        }
-
-        /**
-         * <p>Transforms the specified Cursor column into a String. The transformation
-         * can simply return the content of the column as a String (this is known
-         * as the identity transformation) or manipulate the content. For instance,
-         * a transformation can perform text substitutions or concatenate other
-         * columns with the specified column.</p>
-         * 
-         * @param cursor The cursor that contains the data to transform. 
-         * @param columnIndex The index of the column to transform.
-         * 
-         * @return A String containing the transformed value of the column.
-         */
-        public abstract String transform(Cursor cursor, int columnIndex);
-
-        /**
-         * <p>Transforms the specified Cursor column into a resource identifier.
-         * The default implementation simply interprets the content of the column
-         * as an integer.</p>
-         * 
-         * @param cursor The cursor that contains the data to transform. 
-         * @param columnIndex The index of the column to transform.
-         * 
-         * @return A resource identifier.
-         */
-        public int transformToResource(Cursor cursor, int columnIndex) {
-            return cursor.getInt(columnIndex);
-        }        
-    }
-
-    /**
-     * <p>Loads the {@link android.widget.CursorAdapter} defined in the specified
-     * XML resource. The content of the adapter is loaded from the content provider
-     * identified by the supplied URI.</p>
-     * 
-     * <p><strong>Note:</strong> If the supplied {@link android.content.Context} is
-     * an {@link android.app.Activity}, the cursor returned by the content provider
-     * will be automatically managed. Otherwise, you are responsible for managing the
-     * cursor yourself.</p>
-     * 
-     * <p>The format of the XML definition of the cursor adapter is documented at
-     * the top of this page.</p>
-     * 
-     * @param context The context to load the XML resource from.
-     * @param id The identifier of the XML resource declaring the adapter.
-     * @param uri The URI of the content provider.
-     * @param parameters Optional parameters to pass to the CursorAdapter, used
-     *        to substitute values in the selection expression.
-     * 
-     * @return A {@link android.widget.CursorAdapter}
-     * 
-     * @throws IllegalArgumentException If the XML resource does not contain
-     *         a valid &lt;cursor-adapter /&gt; definition.
-     * 
-     * @see android.content.ContentProvider
-     * @see android.widget.CursorAdapter
-     * @see #loadAdapter(android.content.Context, int, Object[]) 
-     */
-    public static CursorAdapter loadCursorAdapter(Context context, int id, String uri,
-            Object... parameters) {
-
-        XmlCursorAdapter adapter = (XmlCursorAdapter) loadAdapter(context, id, ADAPTER_CURSOR,
-                parameters);
-
-        if (uri != null) {
-            adapter.setUri(uri);
-        }
-        adapter.load();
-
-        return adapter;
-    }
-
-    /**
-     * <p>Loads the {@link android.widget.CursorAdapter} defined in the specified
-     * XML resource. The content of the adapter is loaded from the specified cursor.
-     * You are responsible for managing the supplied cursor.</p>
-     * 
-     * <p>The format of the XML definition of the cursor adapter is documented at
-     * the top of this page.</p>
-     * 
-     * @param context The context to load the XML resource from.
-     * @param id The identifier of the XML resource declaring the adapter.
-     * @param cursor The cursor containing the data for the adapter.
-     * @param parameters Optional parameters to pass to the CursorAdapter, used
-     *        to substitute values in the selection expression.
-     * 
-     * @return A {@link android.widget.CursorAdapter}
-     * 
-     * @throws IllegalArgumentException If the XML resource does not contain
-     *         a valid &lt;cursor-adapter /&gt; definition.
-     * 
-     * @see android.content.ContentProvider
-     * @see android.widget.CursorAdapter
-     * @see android.database.Cursor
-     * @see #loadAdapter(android.content.Context, int, Object[]) 
-     */
-    public static CursorAdapter loadCursorAdapter(Context context, int id, Cursor cursor,
-            Object... parameters) {
-
-        XmlCursorAdapter adapter = (XmlCursorAdapter) loadAdapter(context, id, ADAPTER_CURSOR,
-                parameters);
-
-        if (cursor != null) {
-            adapter.changeCursor(cursor);
-        }
-
-        return adapter;
-    }
-
-    /**
-     * <p>Loads the adapter defined in the specified XML resource. The XML definition of
-     * the adapter must follow the format definition of one of the supported adapter
-     * types described at the top of this page.</p>
-     * 
-     * <p><strong>Note:</strong> If the loaded adapter is a {@link android.widget.CursorAdapter}
-     * and the supplied {@link android.content.Context} is an {@link android.app.Activity},
-     * the cursor returned by the content provider will be automatically managed. Otherwise,
-     * you are responsible for managing the cursor yourself.</p>
-     * 
-     * @param context The context to load the XML resource from.
-     * @param id The identifier of the XML resource declaring the adapter.
-     * @param parameters Optional parameters to pass to the adapter.
-     *  
-     * @return An adapter instance.
-     * 
-     * @see #loadCursorAdapter(android.content.Context, int, android.database.Cursor, Object[]) 
-     * @see #loadCursorAdapter(android.content.Context, int, String, Object[]) 
-     */
-    public static BaseAdapter loadAdapter(Context context, int id, Object... parameters) {
-        final BaseAdapter adapter = loadAdapter(context, id, null, parameters);
-        if (adapter instanceof ManagedAdapter) {
-            ((ManagedAdapter) adapter).load();
-        }
-        return adapter;
-    }
-
-    /**
-     * Loads an adapter from the specified XML resource. The optional assertName can
-     * be used to exit early if the adapter defined in the XML resource is not of the
-     * expected type.
-     * 
-     * @param context The context to associate with the adapter.
-     * @param id The resource id of the XML document defining the adapter.
-     * @param assertName The mandatory name of the adapter in the XML document.
-     *        Ignored if null.
-     * @param parameters Optional parameters passed to the adapter.
-     * 
-     * @return An instance of {@link android.widget.BaseAdapter}.
-     */
-    private static BaseAdapter loadAdapter(Context context, int id, String assertName,
-            Object... parameters) {
-
-        XmlResourceParser parser = null;
-        try {
-            parser = context.getResources().getXml(id);
-            return createAdapterFromXml(context, parser, Xml.asAttributeSet(parser),
-                    id, parameters, assertName);
-        } catch (XmlPullParserException ex) {
-            Resources.NotFoundException rnf = new Resources.NotFoundException(
-                    "Can't load adapter resource ID " +
-                    context.getResources().getResourceEntryName(id));
-            rnf.initCause(ex);
-            throw rnf;
-        } catch (IOException ex) {
-            Resources.NotFoundException rnf = new Resources.NotFoundException(
-                    "Can't load adapter resource ID " +
-                    context.getResources().getResourceEntryName(id));
-            rnf.initCause(ex);
-            throw rnf;
-        } finally {
-            if (parser != null) parser.close();
-        }
-    }
-
-    /**
-     * Generates an adapter using the specified XML parser. This method is responsible
-     * for choosing the type of the adapter to create based on the content of the
-     * XML parser.
-     * 
-     * This method will generate an {@link IllegalArgumentException} if
-     * <code>assertName</code> is not null and does not match the root tag of the XML
-     * document. 
-     */
-    private static BaseAdapter createAdapterFromXml(Context c,
-            XmlPullParser parser, AttributeSet attrs, int id, Object[] parameters,
-            String assertName) throws XmlPullParserException, IOException {
-
-        BaseAdapter adapter = null;
-
-        // Make sure we are on a start tag.
-        int type;
-        int depth = parser.getDepth();
-
-        while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) &&
-                type != XmlPullParser.END_DOCUMENT) {
-
-            if (type != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            String name = parser.getName();
-            if (assertName != null && !assertName.equals(name)) {
-                throw new IllegalArgumentException("The adapter defined in " +
-                        c.getResources().getResourceEntryName(id) + " must be a <" +
-                        assertName + " />");
-            }
-
-            if (ADAPTER_CURSOR.equals(name)) {
-                adapter = createCursorAdapter(c, parser, attrs, id, parameters);
-            } else {
-                throw new IllegalArgumentException("Unknown adapter name " + parser.getName() +
-                        " in " + c.getResources().getResourceEntryName(id));
-            }
-        }
-
-        return adapter;
-
-    }
-
-    /**
-     * Creates an XmlCursorAdapter using an XmlCursorAdapterParser.
-     */
-    private static XmlCursorAdapter createCursorAdapter(Context c, XmlPullParser parser,
-            AttributeSet attrs, int id, Object[] parameters)
-            throws IOException, XmlPullParserException {
-
-        return new XmlCursorAdapterParser(c, parser, attrs, id).parse(parameters);
-    }
-
-    /**
-     * Parser that can generate XmlCursorAdapter instances. This parser is responsible for
-     * handling all the attributes and child nodes for a &lt;cursor-adapter /&gt;.
-     */
-    private static class XmlCursorAdapterParser {
-        private static final String ADAPTER_CURSOR_BIND = "bind";
-        private static final String ADAPTER_CURSOR_SELECT = "select";
-        private static final String ADAPTER_CURSOR_AS_STRING = "string";
-        private static final String ADAPTER_CURSOR_AS_IMAGE = "image";
-        private static final String ADAPTER_CURSOR_AS_TAG = "tag";
-        private static final String ADAPTER_CURSOR_AS_IMAGE_URI = "image-uri";
-        private static final String ADAPTER_CURSOR_AS_DRAWABLE = "drawable";
-        private static final String ADAPTER_CURSOR_MAP = "map";
-        private static final String ADAPTER_CURSOR_TRANSFORM = "transform";
-
-        private final Context mContext;
-        private final XmlPullParser mParser;
-        private final AttributeSet mAttrs;
-        private final int mId;
-
-        private final HashMap<String, CursorBinder> mBinders;
-        private final ArrayList<String> mFrom;
-        private final ArrayList<Integer> mTo;
-        private final CursorTransformation mIdentity;
-        private final Resources mResources;
-
-        public XmlCursorAdapterParser(Context c, XmlPullParser parser, AttributeSet attrs, int id) {
-            mContext = c;
-            mParser = parser;
-            mAttrs = attrs;
-            mId = id;
-
-            mResources = mContext.getResources();
-            mBinders = new HashMap<String, CursorBinder>();
-            mFrom = new ArrayList<String>();
-            mTo = new ArrayList<Integer>();
-            mIdentity = new IdentityTransformation(mContext);            
-        }
-
-        public XmlCursorAdapter parse(Object[] parameters)
-               throws IOException, XmlPullParserException {
-
-            Resources resources = mResources;
-            TypedArray a = resources.obtainAttributes(mAttrs, com.android.internal.R.styleable.CursorAdapter);
-
-            String uri = a.getString(com.android.internal.R.styleable.CursorAdapter_uri);
-            String selection = a.getString(com.android.internal.R.styleable.CursorAdapter_selection);
-            String sortOrder = a.getString(com.android.internal.R.styleable.CursorAdapter_sortOrder);
-            int layout = a.getResourceId(com.android.internal.R.styleable.CursorAdapter_layout, 0);
-            if (layout == 0) {
-                throw new IllegalArgumentException("The layout specified in " +
-                        resources.getResourceEntryName(mId) + " does not exist");
-            }
-
-            a.recycle();
-
-            XmlPullParser parser = mParser;
-            int type;
-            int depth = parser.getDepth();
-
-            while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) &&
-                    type != XmlPullParser.END_DOCUMENT) {
-
-                if (type != XmlPullParser.START_TAG) {
-                    continue;
-                }
-
-                String name = parser.getName();
-
-                if (ADAPTER_CURSOR_BIND.equals(name)) {
-                    parseBindTag();
-                } else if (ADAPTER_CURSOR_SELECT.equals(name)) {
-                    parseSelectTag();
-                } else {
-                    throw new RuntimeException("Unknown tag name " + parser.getName() + " in " +
-                            resources.getResourceEntryName(mId));
-                }
-            }
-
-            String[] fromArray = mFrom.toArray(new String[mFrom.size()]);
-            int[] toArray = new int[mTo.size()];
-            for (int i = 0; i < toArray.length; i++) {
-                toArray[i] = mTo.get(i);
-            }
-
-            String[] selectionArgs = null;
-            if (parameters != null) {
-                selectionArgs = new String[parameters.length];
-                for (int i = 0; i < selectionArgs.length; i++) {
-                    selectionArgs[i] = (String) parameters[i];
-                }
-            }
-
-            return new XmlCursorAdapter(mContext, layout, uri, fromArray, toArray, selection,
-                    selectionArgs, sortOrder, mBinders);
-        }
-
-        private void parseSelectTag() {
-            TypedArray a = mResources.obtainAttributes(mAttrs,
-                    com.android.internal.R.styleable.CursorAdapter_SelectItem);
-
-            String fromName = a.getString(com.android.internal.R.styleable.CursorAdapter_SelectItem_column);
-            if (fromName == null) {
-                throw new IllegalArgumentException("A select item in " +
-                        mResources.getResourceEntryName(mId) +
-                        " does not have a 'column' attribute");
-            }
-
-            a.recycle();
-
-            mFrom.add(fromName);
-            mTo.add(View.NO_ID);
-        }
-
-        private void parseBindTag() throws IOException, XmlPullParserException {
-            Resources resources = mResources;
-            TypedArray a = resources.obtainAttributes(mAttrs,
-                    com.android.internal.R.styleable.CursorAdapter_BindItem);
-
-            String fromName = a.getString(com.android.internal.R.styleable.CursorAdapter_BindItem_from);
-            if (fromName == null) {
-                throw new IllegalArgumentException("A bind item in " +
-                        resources.getResourceEntryName(mId) + " does not have a 'from' attribute");
-            }
-
-            int toName = a.getResourceId(com.android.internal.R.styleable.CursorAdapter_BindItem_to, 0);
-            if (toName == 0) {
-                throw new IllegalArgumentException("A bind item in " +
-                        resources.getResourceEntryName(mId) + " does not have a 'to' attribute");
-            }
-
-            String asType = a.getString(com.android.internal.R.styleable.CursorAdapter_BindItem_as);
-            if (asType == null) {
-                throw new IllegalArgumentException("A bind item in " +
-                        resources.getResourceEntryName(mId) + " does not have an 'as' attribute");
-            }
-
-            mFrom.add(fromName);
-            mTo.add(toName);
-            mBinders.put(fromName, findBinder(asType));
-
-            a.recycle();
-        }
-
-        private CursorBinder findBinder(String type) throws IOException, XmlPullParserException {
-            final XmlPullParser parser = mParser;
-            final Context context = mContext;
-            CursorTransformation transformation = mIdentity;
-
-            int tagType;
-            int depth = parser.getDepth();
-
-            final boolean isDrawable = ADAPTER_CURSOR_AS_DRAWABLE.equals(type);            
-
-            while (((tagType = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
-                    && tagType != XmlPullParser.END_DOCUMENT) {
-
-                if (tagType != XmlPullParser.START_TAG) {
-                    continue;
-                }
-
-                String name = parser.getName();
-
-                if (ADAPTER_CURSOR_TRANSFORM.equals(name)) {
-                    transformation = findTransformation();
-                } else if (ADAPTER_CURSOR_MAP.equals(name)) {
-                    if (!(transformation instanceof MapTransformation)) {
-                        transformation = new MapTransformation(context);
-                    }
-                    findMap(((MapTransformation) transformation), isDrawable);
-                } else {
-                    throw new RuntimeException("Unknown tag name " + parser.getName() + " in " +
-                            context.getResources().getResourceEntryName(mId));
-                }
-            }
-
-            if (ADAPTER_CURSOR_AS_STRING.equals(type)) {
-                return new StringBinder(context, transformation);
-            } else if (ADAPTER_CURSOR_AS_TAG.equals(type)) {
-                return new TagBinder(context, transformation);
-            } else if (ADAPTER_CURSOR_AS_IMAGE.equals(type)) {
-                return new ImageBinder(context, transformation);            
-            } else if (ADAPTER_CURSOR_AS_IMAGE_URI.equals(type)) {
-                return new ImageUriBinder(context, transformation);
-            } else if (isDrawable) {
-                return new DrawableBinder(context, transformation);
-            } else {
-                return createBinder(type, transformation);
-            }
-        }
-
-        private CursorBinder createBinder(String type, CursorTransformation transformation) {
-            if (mContext.isRestricted()) return null;
-
-            try {
-                final Class<?> klass = Class.forName(type, true, mContext.getClassLoader());
-                if (CursorBinder.class.isAssignableFrom(klass)) {
-                    final Constructor<?> c = klass.getDeclaredConstructor(
-                            Context.class, CursorTransformation.class);
-                    return (CursorBinder) c.newInstance(mContext, transformation);
-                }
-            } catch (ClassNotFoundException e) {
-                throw new IllegalArgumentException("Cannot instanciate binder type in " +
-                        mContext.getResources().getResourceEntryName(mId) + ": " + type, e);
-            } catch (NoSuchMethodException e) {
-                throw new IllegalArgumentException("Cannot instanciate binder type in " +
-                        mContext.getResources().getResourceEntryName(mId) + ": " + type, e);
-            } catch (InvocationTargetException e) {
-                throw new IllegalArgumentException("Cannot instanciate binder type in " +
-                        mContext.getResources().getResourceEntryName(mId) + ": " + type, e);
-            } catch (InstantiationException e) {
-                throw new IllegalArgumentException("Cannot instanciate binder type in " +
-                        mContext.getResources().getResourceEntryName(mId) + ": " + type, e);
-            } catch (IllegalAccessException e) {
-                throw new IllegalArgumentException("Cannot instanciate binder type in " +
-                        mContext.getResources().getResourceEntryName(mId) + ": " + type, e);
-            }
-
-            return null;
-        }
-
-        private void findMap(MapTransformation transformation, boolean drawable) {
-            Resources resources = mResources;
-
-            TypedArray a = resources.obtainAttributes(mAttrs,
-                    com.android.internal.R.styleable.CursorAdapter_MapItem);
-
-            String from = a.getString(com.android.internal.R.styleable.CursorAdapter_MapItem_fromValue);
-            if (from == null) {
-                throw new IllegalArgumentException("A map item in " +
-                        resources.getResourceEntryName(mId) +
-                        " does not have a 'fromValue' attribute");
-            }
-
-            if (!drawable) {
-                String to = a.getString(com.android.internal.R.styleable.CursorAdapter_MapItem_toValue);
-                if (to == null) {
-                    throw new IllegalArgumentException("A map item in " +
-                            resources.getResourceEntryName(mId) +
-                            " does not have a 'toValue' attribute");
-                }
-                transformation.addStringMapping(from, to);
-            } else {
-                int to = a.getResourceId(com.android.internal.R.styleable.CursorAdapter_MapItem_toValue, 0);
-                if (to == 0) {
-                    throw new IllegalArgumentException("A map item in " +
-                            resources.getResourceEntryName(mId) +
-                            " does not have a 'toValue' attribute");
-                }
-                transformation.addResourceMapping(from, to);
-            }
-
-            a.recycle();
-        }
-
-        private CursorTransformation findTransformation() {
-            Resources resources = mResources;
-            CursorTransformation transformation = null;
-            TypedArray a = resources.obtainAttributes(mAttrs,
-                    com.android.internal.R.styleable.CursorAdapter_TransformItem);
-
-            String className = a.getString(com.android.internal.R.styleable.CursorAdapter_TransformItem_withClass);
-            if (className == null) {
-                String expression = a.getString(
-                        com.android.internal.R.styleable.CursorAdapter_TransformItem_withExpression);
-                transformation = createExpressionTransformation(expression);
-            } else if (!mContext.isRestricted()) {
-                try {
-                    final Class<?> klas = Class.forName(className, true, mContext.getClassLoader());
-                    if (CursorTransformation.class.isAssignableFrom(klas)) {
-                        final Constructor<?> c = klas.getDeclaredConstructor(Context.class);
-                        transformation = (CursorTransformation) c.newInstance(mContext);
-                    }
-                } catch (ClassNotFoundException e) {
-                    throw new IllegalArgumentException("Cannot instanciate transform type in " +
-                           mContext.getResources().getResourceEntryName(mId) + ": " + className, e);
-                } catch (NoSuchMethodException e) {
-                    throw new IllegalArgumentException("Cannot instanciate transform type in " +
-                           mContext.getResources().getResourceEntryName(mId) + ": " + className, e);
-                } catch (InvocationTargetException e) {
-                    throw new IllegalArgumentException("Cannot instanciate transform type in " +
-                           mContext.getResources().getResourceEntryName(mId) + ": " + className, e);
-                } catch (InstantiationException e) {
-                    throw new IllegalArgumentException("Cannot instanciate transform type in " +
-                           mContext.getResources().getResourceEntryName(mId) + ": " + className, e);
-                } catch (IllegalAccessException e) {
-                    throw new IllegalArgumentException("Cannot instanciate transform type in " +
-                           mContext.getResources().getResourceEntryName(mId) + ": " + className, e);
-                }
-            }
-
-            a.recycle();
-
-            if (transformation == null) {
-                throw new IllegalArgumentException("A transform item in " +
-                    resources.getResourceEntryName(mId) + " must have a 'withClass' or " +
-                    "'withExpression' attribute");
-            }
-
-            return transformation;
-        }
-
-        private CursorTransformation createExpressionTransformation(String expression) {
-            return new ExpressionTransformation(mContext, expression);
-        }
-    }
-
-    /**
-     * Interface used by adapters that require to be loaded after creation.
-     */
-    private static interface ManagedAdapter {
-        /**
-         * Loads the content of the adapter, asynchronously.
-         */
-        void load();
-    }
-
-    /**
-     * Implementation of a Cursor adapter defined in XML. This class is a thin wrapper
-     * of a SimpleCursorAdapter. The main difference is the ability to handle CursorBinders.
-     */
-    private static class XmlCursorAdapter extends SimpleCursorAdapter implements ManagedAdapter {
-        private String mUri;
-        private final String mSelection;
-        private final String[] mSelectionArgs;
-        private final String mSortOrder;
-        private final String[] mColumns;
-        private final CursorBinder[] mBinders;
-        private AsyncTask<Void,Void,Cursor> mLoadTask;
-
-        XmlCursorAdapter(Context context, int layout, String uri, String[] from, int[] to,
-                String selection, String[] selectionArgs, String sortOrder,
-                HashMap<String, CursorBinder> binders) {
-
-            super(context, layout, null, from, to);
-            mContext = context;
-            mUri = uri;
-            mSelection = selection;
-            mSelectionArgs = selectionArgs;
-            mSortOrder = sortOrder;
-            mColumns = new String[from.length + 1];
-            // This is mandatory in CursorAdapter
-            mColumns[0] = "_id";
-            System.arraycopy(from, 0, mColumns, 1, from.length);
-
-            CursorBinder basic = new StringBinder(context, new IdentityTransformation(context));
-            final int count = from.length;
-            mBinders = new CursorBinder[count];
-
-            for (int i = 0; i < count; i++) {
-                CursorBinder binder = binders.get(from[i]);
-                if (binder == null) binder = basic;
-                mBinders[i] = binder;
-            }
-        }
-
-        @Override
-        public void bindView(View view, Context context, Cursor cursor) {
-            final int count = mTo.length;
-            final int[] from = mFrom;
-            final int[] to = mTo;
-            final CursorBinder[] binders = mBinders;
-
-            for (int i = 0; i < count; i++) {
-                final View v = view.findViewById(to[i]);
-                if (v != null) {
-                    binders[i].bind(v, cursor, from[i]);
-                }
-            }
-        }
-
-        public void load() {
-            if (mUri != null) {
-                mLoadTask = new QueryTask().execute();
-            }
-        }
-
-        void setUri(String uri) {
-            mUri = uri;
-        }
-
-        @Override
-        public void changeCursor(Cursor c) {
-            if (mLoadTask != null && mLoadTask.getStatus() != QueryTask.Status.FINISHED) {
-                mLoadTask.cancel(true);
-                mLoadTask = null;
-            }
-            super.changeCursor(c);
-        }
-
-        class QueryTask extends AsyncTask<Void, Void, Cursor> {
-            @Override
-            protected Cursor doInBackground(Void... params) {
-                if (mContext instanceof Activity) {
-                    return ((Activity) mContext).managedQuery(
-                            Uri.parse(mUri), mColumns, mSelection, mSelectionArgs, mSortOrder);
-                } else {
-                    return mContext.getContentResolver().query(
-                            Uri.parse(mUri), mColumns, mSelection, mSelectionArgs, mSortOrder);
-                }
-            }
-
-            @Override
-            protected void onPostExecute(Cursor cursor) {
-                if (!isCancelled()) {
-                    XmlCursorAdapter.super.changeCursor(cursor);
-                }
-            }
-        }
-    }
-
-    /**
-     * Identity transformation, returns the content of the specified column as a String,
-     * without performing any manipulation. This is used when no transformation is specified.
-     */
-    private static class IdentityTransformation extends CursorTransformation {
-        public IdentityTransformation(Context context) {
-            super(context);
-        }
-
-        @Override
-        public String transform(Cursor cursor, int columnIndex) {
-            return cursor.getString(columnIndex);
-        }
-    }
-
-    /**
-     * An expression transformation is a simple template based replacement utility.
-     * In an expression, each segment of the form <code>{([^}]+)}</code> is replaced
-     * with the value of the column of name $1.
-     */
-    private static class ExpressionTransformation extends CursorTransformation {
-        private final ExpressionNode mFirstNode = new ConstantExpressionNode("");
-        private final StringBuilder mBuilder = new StringBuilder();
-
-        public ExpressionTransformation(Context context, String expression) {
-            super(context);
-
-            parse(expression);
-        }
-
-        private void parse(String expression) {
-            ExpressionNode node = mFirstNode;
-            int segmentStart;
-            int count = expression.length();
-
-            for (int i = 0; i < count; i++) {
-                char c = expression.charAt(i);
-                // Start a column name segment
-                segmentStart = i;
-                if (c == '{') {
-                    while (i < count && (c = expression.charAt(i)) != '}') {
-                        i++;
-                    }
-                    // We've reached the end, but the expression didn't close
-                    if (c != '}') {
-                        throw new IllegalStateException("The transform expression contains a " +
-                                "non-closed column name: " +
-                                expression.substring(segmentStart + 1, i));
-                    }
-                    node.next = new ColumnExpressionNode(expression.substring(segmentStart + 1, i));
-                } else {
-                    while (i < count && (c = expression.charAt(i)) != '{') {
-                        i++;
-                    }
-                    node.next = new ConstantExpressionNode(expression.substring(segmentStart, i));
-                    // Rewind if we've reached a column expression
-                    if (c == '{') i--;
-                }
-                node = node.next;
-            }
-        }
-
-        @Override
-        public String transform(Cursor cursor, int columnIndex) {
-            final StringBuilder builder = mBuilder;
-            builder.delete(0, builder.length());
-
-            ExpressionNode node = mFirstNode;
-            // Skip the first node
-            while ((node = node.next) != null) {
-                builder.append(node.asString(cursor));
-            }
-
-            return builder.toString();
-        }
-
-        static abstract class ExpressionNode {
-            public ExpressionNode next;
-
-            public abstract String asString(Cursor cursor);
-        }
-
-        static class ConstantExpressionNode extends ExpressionNode {
-            private final String mConstant;
-
-            ConstantExpressionNode(String constant) {
-                mConstant = constant;
-            }
-
-            @Override
-            public String asString(Cursor cursor) {
-                return mConstant;
-            }
-        }
-
-        static class ColumnExpressionNode extends ExpressionNode {
-            private final String mColumnName;
-            private Cursor mSignature;
-            private int mColumnIndex = -1;
-
-            ColumnExpressionNode(String columnName) {
-                mColumnName = columnName;
-            }
-
-            @Override
-            public String asString(Cursor cursor) {
-                if (cursor != mSignature || mColumnIndex == -1) {
-                    mColumnIndex = cursor.getColumnIndex(mColumnName);
-                    mSignature = cursor;
-                }
-
-                return cursor.getString(mColumnIndex);
-            }
-        }
-    }
-
-    /**
-     * A map transformation offers a simple mapping between specified String values
-     * to Strings or integers.
-     */
-    private static class MapTransformation extends CursorTransformation {
-        private final HashMap<String, String> mStringMappings;
-        private final HashMap<String, Integer> mResourceMappings;
-
-        public MapTransformation(Context context) {
-            super(context);
-            mStringMappings = new HashMap<String, String>();
-            mResourceMappings = new HashMap<String, Integer>();
-        }
-
-        void addStringMapping(String from, String to) {
-            mStringMappings.put(from, to);
-        }
-
-        void addResourceMapping(String from, int to) {
-            mResourceMappings.put(from, to);
-        }
-
-        @Override
-        public String transform(Cursor cursor, int columnIndex) {
-            final String value = cursor.getString(columnIndex);
-            final String transformed = mStringMappings.get(value);
-            return transformed == null ? value : transformed;
-        }
-
-        @Override
-        public int transformToResource(Cursor cursor, int columnIndex) {
-            final String value = cursor.getString(columnIndex);
-            final Integer transformed = mResourceMappings.get(value);
-            try {
-                return transformed == null ? Integer.parseInt(value) : transformed;
-            } catch (NumberFormatException e) {
-                return 0;
-            }
-        }
-    }
-
-    /**
-     * Binds a String to a TextView.
-     */
-    private static class StringBinder extends CursorBinder {
-        public StringBinder(Context context, CursorTransformation transformation) {
-            super(context, transformation);
-        }
-
-        @Override
-        public boolean bind(View view, Cursor cursor, int columnIndex) {
-            if (view instanceof TextView) {
-                final String text = mTransformation.transform(cursor, columnIndex);
-                ((TextView) view).setText(text);
-                return true;
-            }
-            return false;
-        }
-    }
-
-    /**
-     * Binds an image blob to an ImageView.
-     */
-    private static class ImageBinder extends CursorBinder {
-        public ImageBinder(Context context, CursorTransformation transformation) {
-            super(context, transformation);
-        }
-
-        @Override
-        public boolean bind(View view, Cursor cursor, int columnIndex) {
-            if (view instanceof ImageView) {
-                final byte[] data = cursor.getBlob(columnIndex);
-                ((ImageView) view).setImageBitmap(BitmapFactory.decodeByteArray(data, 0,
-                        data.length));
-                return true;
-            }
-            return false;
-        }
-    }
-
-    private static class TagBinder extends CursorBinder {
-        public TagBinder(Context context, CursorTransformation transformation) {
-            super(context, transformation);
-        }
-
-        @Override
-        public boolean bind(View view, Cursor cursor, int columnIndex) {
-            final String text = mTransformation.transform(cursor, columnIndex);
-            view.setTag(text);
-            return true;
-        }
-    }
-
-    /**
-     * Binds an image URI to an ImageView.
-     */
-    private static class ImageUriBinder extends CursorBinder {
-        public ImageUriBinder(Context context, CursorTransformation transformation) {
-            super(context, transformation);
-        }
-
-        @Override
-        public boolean bind(View view, Cursor cursor, int columnIndex) {
-            if (view instanceof ImageView) {
-                ((ImageView) view).setImageURI(Uri.parse(
-                        mTransformation.transform(cursor, columnIndex)));
-                return true;
-            }
-            return false;
-        }
-    }
-
-    /**
-     * Binds a drawable resource identifier to an ImageView.
-     */
-    private static class DrawableBinder extends CursorBinder {
-        public DrawableBinder(Context context, CursorTransformation transformation) {
-            super(context, transformation);
-        }
-
-        @Override
-        public boolean bind(View view, Cursor cursor, int columnIndex) {
-            if (view instanceof ImageView) {
-                final int resource = mTransformation.transformToResource(cursor, columnIndex);
-                if (resource == 0) return false;
-
-                ((ImageView) view).setImageResource(resource);
-                return true;
-            }
-            return false;
-        }
-    }
-}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index f0512f6..6a2a09a 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -7645,9 +7645,7 @@
                 hasPrimaryClip());
     }
 
-    private boolean isWordCharacter(int position) {
-        final char c = mTransformed.charAt(position);
-        final int type = Character.getType(c);
+    private boolean isWordCharacter(int c, int type) {
         return (c == '\'' || c == '"' ||
                 type == Character.UPPERCASE_LETTER ||
                 type == Character.LOWERCASE_LETTER ||
@@ -7696,35 +7694,32 @@
         int start = end;
 
         for (; start > 0; start--) {
-            if (start == end) {
+            final char c = mTransformed.charAt(start - 1);
+            final int type = Character.getType(c);
+            if (start == end && type == Character.OTHER_PUNCTUATION) { 
                 // Cases where the text ends with a '.' and we select from the end of the line
                 // (right after the dot), or when we select from the space character in "aaa, bbb".
-                final char c = mTransformed.charAt(start - 1);
-                final int type = Character.getType(c);
-                if (type == Character.OTHER_PUNCTUATION) continue;
+                continue;
+            }              
+            if (type == Character.SURROGATE) { // Two Character codepoint
+                end = start - 1; // Recheck as a pair when scanning forward
+                continue;
             }
-            if (!isWordCharacter(start - 1)) break;
+            if (!isWordCharacter(c, type)) break;
             if ((end - start) > MAX_LENGTH) return -1;
         }
 
         for (; end < len; end++) {
-            if (!isWordCharacter(end)) break;
+            final int c = Character.codePointAt(mTransformed, end);
+            final int type = Character.getType(c);
+            if (!isWordCharacter(c, type)) break;
             if ((end - start) > MAX_LENGTH) return -1;
-        }
-
-        if (start == end) {
-            return -1;
-        }
-
-        boolean hasLetter = false;
-        for (int i = start; i < end; i++) {
-            if (Character.isLetter(mTransformed.charAt(i))) {
-                hasLetter = true;
-                break;
+            if (c > 0xFFFF) { // Two Character codepoint
+                end++;
             }
         }
 
-        if (!hasLetter) {
+        if (start == end) {
             return -1;
         }
 
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index f927fae..2c5baba 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -187,17 +187,6 @@
             final MenuItemImpl itemData = itemsToShow.get(i);
             View actionView = itemData.getActionView();
 
-            if (actionView == null) {
-                // Check for a layout ID instead
-                final int layoutId = itemData.getActionViewId();
-                if (layoutId != 0) {
-                    LayoutInflater inflater = LayoutInflater.from(getContext());
-                    actionView = inflater.inflate(layoutId, this, false);
-                    itemData.setActionView(0);
-                    itemData.setActionView(actionView);
-                }
-            }
-
             if (actionView != null) {
                 final ViewParent parent = actionView.getParent();
                 if (parent instanceof ViewGroup) {
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 9faffe5..e1aa385 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -83,7 +83,6 @@
     private int mShowAsAction = SHOW_AS_ACTION_NEVER;
 
     private View mActionView;
-    private int mActionViewId;
 
     /** Used for the icon resource ID if this item does not have an icon */
     static final int NO_ICON = 0;
@@ -696,15 +695,13 @@
     }
 
     public MenuItem setActionView(int resId) {
-        mActionViewId = resId;
+        LayoutInflater inflater = LayoutInflater.from(mMenu.getContext());
+        ViewGroup parent = (ViewGroup) mMenu.getMenuView(MenuBuilder.TYPE_ACTION_BUTTON, null);
+        setActionView(inflater.inflate(resId, parent, false));
         return this;
     }
 
     public View getActionView() {
         return mActionView;
     }
-
-    public int getActionViewId() {
-        return mActionViewId;
-    }
 }
diff --git a/core/res/res/values-es-rUS-xlarge/strings.xml b/core/res/res/values-es-rUS-xlarge/strings.xml
new file mode 100644
index 0000000..cef8d12
--- /dev/null
+++ b/core/res/res/values-es-rUS-xlarge/strings.xml
@@ -0,0 +1,331 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- XL -->
+    <string name="fileSizeSuffix" msgid="3468563433835560758">"Segmento <xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
+    <!-- XL -->
+    <string name="unknownName" msgid="3202822008051920747">"(Desconocido)"</string>
+    <!-- XL -->
+    <string name="defaultVoiceMailAlphaTag" msgid="3668436100965334106">"Buzón de voz"</string>
+    <!-- XL -->
+    <string name="serviceClassVoice" msgid="7086876533404179039">"Google Voice"</string>
+    <!-- XL -->
+    <string name="cfTemplateNotForwarded" msgid="8534356655497306518">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha reenviado"</string>
+    <!-- XL -->
+    <string name="cfTemplateRegistered" msgid="1255841210142514510">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha reenviado"</string>
+    <!-- XL -->
+    <string name="cfTemplateRegisteredTime" msgid="7798907169190952367">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha reenviado"</string>
+    <!-- XL -->
+    <string name="notification_title" msgid="5210128823045542445">"Error al acceder a <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
+    <!-- XL -->
+    <string name="low_memory" product="tablet" msgid="4855646606241379548">"¡El espacio de almacenamiento de la tableta está completo! Elimina algunos archivos para liberar espacio."</string>
+    <string name="low_memory" product="default" msgid="9195238880281578473">"¡El espacio de almacenamiento está completo! Elimina algunos archivos para liberar espacio."</string>
+    <!-- XL -->
+    <string name="power_dialog" product="tablet" msgid="6884163545695410971">"Opciones de tableta"</string>
+    <string name="power_dialog" product="default" msgid="8882103237148972564">"Opciones de teléfono"</string>
+    <!-- XL -->
+    <string name="silent_mode" msgid="5687977677409351252">"Modo silencio"</string>
+    <!-- XL -->
+    <string name="shutdown_confirm" product="tablet" msgid="5776903973889956395">"Tu tableta se apagará."</string>
+    <string name="shutdown_confirm" product="default" msgid="3040950969577046278">"Tu teléfono se apagará."</string>
+    <!-- XL -->
+    <string name="global_actions" product="tablet" msgid="110297659383505180">"Opciones de tableta"</string>
+    <string name="global_actions" product="default" msgid="2108237350837066773">"Opciones de teléfono"</string>
+    <!-- XL -->
+    <string name="global_action_toggle_silent_mode" msgid="4538951049191334644">"Modo silencio"</string>
+    <!-- XL -->
+    <string name="global_action_silent_mode_off_status" msgid="9045822172493147761">"El sonido está ENCENDIDO"</string>
+    <!-- XL -->
+    <string name="global_actions_airplane_mode_on_status" msgid="7272433204482202219">"El modo avión está ENCENDIDO"</string>
+    <!-- XL -->
+    <string name="android_system_label" msgid="844561213652704593">"Sistema Androide"</string>
+    <!-- XL -->
+    <string name="permgroupdesc_costMoney" msgid="4836624191696189469">"Admitir que las aplicaciones realicen actividades que se cobran."</string>
+    <!-- XL -->
+    <string name="permgroupdesc_developmentTools" msgid="5514251182135739578">"Las funciones sólo son necesarias para los programadores de aplicaciones."</string>
+    <!-- XL -->
+    <string name="permgrouplab_storage" msgid="746210798053836644">"Almacenamiento"</string>
+    <!-- XL -->
+    <string name="permdesc_readSms" product="tablet" msgid="3026416194429353337">"Permite que la aplicación lea los mensajes SMS almacenados en tu tableta o tarjeta SIM. Las aplicaciones maliciosas pueden leer tus mensajes confidenciales."</string>
+    <string name="permdesc_readSms" product="default" msgid="191875931331016383">"Admite que la aplicación lea los mensajes SMS almacenados en tu teléfono o tarjeta SIM. Las aplicaciones maliciosas pueden leer tus mensajes confidenciales."</string>
+    <!-- XL -->
+    <string name="permdesc_writeSms" product="tablet" msgid="692041754996169941">"Permite que la aplicación escriba a los mensajes SMS almacenados en tu tableta o tarjeta SIM. Las aplicaciones maliciosas pueden borrar tus mensajes."</string>
+    <string name="permdesc_writeSms" product="default" msgid="1659315878254882599">"Admite que la aplicación escriba a los mensajes SMS almacenados en tu teléfono o tarjeta SIM. Las aplicaciones maliciosas pueden borrar tus mensajes."</string>
+    <!-- XL -->
+    <string name="permlab_forceStopPackages" msgid="1277034765943155677">"provocar la detención de otras aplicaciones"</string>
+    <!-- XL -->
+    <string name="permlab_forceBack" msgid="4272218642115232597">"cerrar la aplicación a la fuerza"</string>
+    <!-- XL -->
+    <string name="permdesc_injectEvents" product="tablet" msgid="6096352450860864899">"Permite que una aplicación ofrezca sus propios eventos de entrada (presionar teclas, etc.) a otras aplicaciones. Las aplicaciones maliciosas pueden utilizarlo para tomar el control de la tableta."</string>
+    <string name="permdesc_injectEvents" product="default" msgid="2842435693076075109">"Admite una aplicación que ofrece sus propios eventos de entrada (presionar teclas, etc.) a otras aplicaciones. Las aplicaciones maliciosas pueden utilizarlo para tomar el control del teléfono."</string>
+    <!-- XL -->
+    <string name="permdesc_clearAppCache" product="tablet" msgid="1147333973960547529">"Permite que una aplicación libere espacio de almacenamiento en la tableta eliminando archivos del directorio de memoria caché de la aplicación. En general, el acceso es muy restringido para el proceso del sistema."</string>
+    <string name="permdesc_clearAppCache" product="default" msgid="5790679870501740958">"Admite una aplicación que libera espacio de almacenamiento en el teléfono al eliminar archivos del directorio de memoria caché de la aplicación. En general, el acceso es muy restringido para el proceso del sistema."</string>
+    <!-- XL -->
+    <string name="permdesc_readLogs" product="tablet" msgid="3701009088710926065">"Permite que una aplicación lea diversos archivos de registro del sistema. Esto le permite descubrir información general acerca de lo que haces con la tableta, y puede potencialmente incluir información personal o privada."</string>
+    <string name="permdesc_readLogs" product="default" msgid="8520101632251038537">"Admite una aplicación que lee diversos archivos de registro del sistema. Esto te permite descubrir información general acerca de lo que haces con el teléfono, y puede potencialmente incluir información personal o privada."</string>
+    <!-- XL -->
+    <string name="permdesc_changeComponentState" product="tablet" msgid="1791075936446230356">"Permite que una aplicación cambie si se debe activar o no un componente de otra aplicación. Las aplicaciones maliciosas pueden utilizarlo para desactivar funciones importantes de la tableta. Se debe tener cuidado con el permiso, ya que es posible que los componentes de la aplicación alcancen un estado inservible, imperfecto e inestable."</string>
+    <string name="permdesc_changeComponentState" product="default" msgid="587130297076242796">"Permite que una aplicación cambie si se debe activar o no un componente de otra aplicación. Las aplicaciones maliciosas pueden utilizarlo para desactivar funciones importantes del teléfono. Se debe tener cuidado con el permiso, ya que es posible que los componentes de la aplicación alcancen un estado inservible, imperfecto e inestable."</string>
+    <!-- XL -->
+    <string name="permdesc_receiveBootCompleted" product="tablet" msgid="8660405432665162821">"Permite que una aplicación se inicie en cuanto el sistema haya finalizado la inicialización. Esto puede ocasionar que la tableta demore más en inicializar y que la aplicación retarde el funcionamiento total de la tableta al estar en ejecución constante."</string>
+    <string name="permdesc_receiveBootCompleted" product="default" msgid="1827765096700833418">"Admite una aplicación que se inicia cuando el sistema haya finalizado la inicialización. Esto puede ocasionar que se demore más tiempo en inicializar el teléfono y que la aplicación retarde el funcionamiento total del teléfono al estar en ejecución constante."</string>
+    <!-- XL -->
+    <string name="permdesc_readContacts" product="tablet" msgid="1611730857475623952">"Permite que una aplicación lea todos los datos de de contacto (direcciones) almacenados en tu tableta. Las aplicaciones maliciosas pueden utilizarlo para enviar tus datos a otras personas."</string>
+    <string name="permdesc_readContacts" product="default" msgid="6610535719925788049">"Admite una aplicación que lee todos los datos de (direcciones) de contactos almacenados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para enviar tus eventos de calendario a otras personas."</string>
+    <!-- XL -->
+    <string name="permdesc_writeContacts" product="tablet" msgid="4572703488642353934">"Permite que una aplicación modifique los datos de (dirección) guardados en tu tableta. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar los datos de contacto."</string>
+    <string name="permdesc_writeContacts" product="default" msgid="714397557711969040">"Admite una aplicación que modifica los datos de (dirección de) contacto guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar los datos de contacto."</string>
+    <!-- XL -->
+    <string name="permdesc_readCalendar" product="tablet" msgid="2991522150157238929">"Permite que una aplicación lea todos los eventos de calendario almacenados en tu tableta. Las aplicaciones maliciosas pueden utilizarlo para enviar tus eventos de calendario a otras personas."</string>
+    <string name="permdesc_readCalendar" product="default" msgid="2618681024074734985">"Admite que una aplicación lea todos los eventos de calendario almacenados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para enviar tus eventos de calendario a otras personas."</string>
+    <!-- XL -->
+    <string name="permdesc_accessFineLocation" product="tablet" msgid="9186984659787705379">"Accede a las fuentes de ubicación precisa, como el Sistema de posicionamiento global en la tableta, si está disponible. Las aplicaciones maliciosas pueden utilizarlo para determinar donde te encuentras y puede consumir energía adicional de la batería."</string>
+    <string name="permdesc_accessFineLocation" product="default" msgid="7130852247133907221">"Accede a las fuentes de ubicación precisa, como el Sistema de posicionamiento global en el teléfono, si está disponible. Las aplicaciones maliciosas pueden utilizarlo para determinar donde te encuentras y puede consumir energía adicional de la batería."</string>
+    <!-- XL -->
+    <string name="permdesc_accessCoarseLocation" product="tablet" msgid="2943949975553225591">"Accede a las fuentes de ubicación aproximada, como la base de datos de la red de celulares, para determinar la ubicación aproximada de un tableta, si está disponible. Las aplicaciones maliciosas pueden utilizarlo para determinar aproximadamente dónde te encuentras."</string>
+    <string name="permdesc_accessCoarseLocation" product="default" msgid="7474972764638621839">"Accede a las fuentes de ubicación aproximada, como la base de datos de la red de celulares, para determinar una ubicación telefónica aproximada, si está disponible. Las aplicaciones maliciosas pueden utilizarlo para determinar aproximadamente donde te encuentras."</string>
+    <!-- XL -->
+    <string name="permlab_brick" product="tablet" msgid="6967130388106614085">"inhabilitar tableta de forma permanente"</string>
+    <string name="permlab_brick" product="default" msgid="3120283238813720510">"desactivar teléfono de manera permanente"</string>
+    <!-- XL -->
+    <string name="permdesc_brick" product="tablet" msgid="8506097851567246888">"Permite que la aplicación desactive todo la tableta de manera permanente. Esto es muy peligroso."</string>
+    <string name="permdesc_brick" product="default" msgid="6696459767254028146">"Admite que la aplicación desactive todo el teléfono de manera permanente. Esto es muy peligroso."</string>
+    <!-- XL -->
+    <string name="permlab_reboot" product="tablet" msgid="8299304590708874992">"forzar reinicio de la tableta"</string>
+    <string name="permlab_reboot" product="default" msgid="7761230490609718232">"provocar el reinicio del teléfono"</string>
+    <!-- XL -->
+    <string name="permdesc_reboot" product="tablet" msgid="8289402537687518137">"Permite que la aplicación provoque el reinicio de la tableta."</string>
+    <string name="permdesc_reboot" product="default" msgid="2425170170087532554">"Admite que la aplicación provoque que el teléfono se reinicie."</string>
+    <!-- XL -->
+    <string name="permlab_performCdmaProvisioning" product="tablet" msgid="1602175938040327630">"iniciar directamente la configuración CDMA de la tableta"</string>
+    <string name="permlab_performCdmaProvisioning" product="default" msgid="2364447039211144234">"comienza directamente la configuración CDMA del teléfono"</string>
+    <!-- XL -->
+    <string name="permlab_checkinProperties" msgid="8770356116386811264">"acceder a las propiedades de registro"</string>
+    <!-- XL -->
+    <string name="permlab_bindGadget" msgid="2772444448613501375">"elegir controles"</string>
+    <!-- XL -->
+    <string name="permdesc_bindGadget" msgid="5172327215211875807">"Admite que la aplicación indique al sistema cuáles controles puede utilizar cada aplicación. Con este permiso, las aplicaciones pueden brindar acceso a los datos personales a otras aplicaciones. Las aplicaciones normales no deben utilizarlo."</string>
+    <!-- XL -->
+    <string name="permlab_wakeLock" product="tablet" msgid="8548785337425173690">"evitar que la tableta entre en estado de inactividad"</string>
+    <string name="permlab_wakeLock" product="default" msgid="7590534090355174805">"evitar que el teléfono entre en estado de inactividad"</string>
+    <!-- XL -->
+    <string name="permdesc_wakeLock" product="tablet" msgid="6871828582124115814">"Permite que una aplicación evite que la tableta entre en estado de inactividad."</string>
+    <string name="permdesc_wakeLock" product="default" msgid="1200311528451468554">"Admite una aplicación que evita que el teléfono entre en estado de inactividad."</string>
+    <!-- XL -->
+    <string name="permlab_devicePower" product="tablet" msgid="4737873025369971061">"apagar o encender la tableta"</string>
+    <string name="permlab_devicePower" product="default" msgid="6879460773734563850">"apagar o encender el teléfono"</string>
+    <!-- XL -->
+    <string name="permdesc_devicePower" product="tablet" msgid="5930342678996327905">"Permite que una aplicación encienda o apague la tableta."</string>
+    <string name="permdesc_devicePower" product="default" msgid="6653901512148320818">"Admite que la aplicación encienda o apague el teléfono."</string>
+    <!-- XL -->
+    <string name="permdesc_factoryTest" product="tablet" msgid="396653994609190055">"Se ejecuta como una prueba de fábrica de bajo nivel que permite un acceso completo al hardware de la tableta. Sólo disponible cuando la tableta se ejecuta en el modo de prueba de fábrica."</string>
+    <string name="permdesc_factoryTest" product="default" msgid="4581239666568781766">"Se ejecuta como una prueba de fábrica de bajo nivel que permite un acceso completo al hardware del teléfono. Sólo disponible cuando un teléfono se ejecuta en el modo de prueba de fábrica."</string>
+    <!-- XL -->
+    <string name="permlab_setWallpaper" msgid="845032615203772571">"establecer fondo de pantalla"</string>
+    <!-- XL -->
+    <string name="permdesc_setWallpaper" msgid="3378501759667797259">"Admite que la aplicación establezca el fondo de pantalla del sistema."</string>
+    <!-- XL -->
+    <string name="permlab_setWallpaperHints" msgid="4995885499848128983">"establecer sugerencias de tamaño del fondo de pantalla"</string>
+    <!-- XL -->
+    <string name="permdesc_setWallpaperHints" msgid="8857901708691279048">"Admite que la aplicación establezca las sugerencias de tamaño del fondo de pantalla del sistema."</string>
+    <!-- XL -->
+    <string name="permdesc_setTime" product="tablet" msgid="7329574196603775554">"Permite que una aplicación cambie la hora de la tableta."</string>
+    <string name="permdesc_setTime" product="default" msgid="7787175369529849526">"Permite a una aplicación cambiar la hora del teléfono."</string>
+    <!-- XL -->
+    <string name="permdesc_setTimeZone" product="tablet" msgid="3851480395450283316">"Permite que una aplicación cambie la zona horaria de la tableta."</string>
+    <string name="permdesc_setTimeZone" product="default" msgid="3231143515254577541">"Admite una aplicación que cambia la zona horaria del teléfono."</string>
+    <!-- XL -->
+    <string name="permdesc_getAccounts" product="tablet" msgid="374861616407073729">"Permite que una aplicación obtenga una la lista de cuentas conocidas por la tableta."</string>
+    <string name="permdesc_getAccounts" product="default" msgid="6356501268884684429">"Admite una aplicación que obtiene la lista de cuentas conocidas del teléfono."</string>
+    <!-- XL -->
+    <string name="permdesc_bluetoothAdmin" product="tablet" msgid="8034248164659819866">"Permite que una aplicación configure el Bluetooth local de la tableta, y descubra y se vincule con dispositivos remotos."</string>
+    <string name="permdesc_bluetoothAdmin" product="default" msgid="2555370145147752776">"Admite una aplicación que configura el teléfono Bluetooth local y descubre y se vincula con dispositivos remotos."</string>
+    <!-- XL -->
+    <string name="permdesc_bluetooth" product="tablet" msgid="4631562404621086816">"Permite que una aplicación vea la configuración de la tableta Bluetooth local, y que realice y acepte conexiones con dispositivos vinculados."</string>
+    <string name="permdesc_bluetooth" product="default" msgid="1202135959389935958">"Admite una aplicación que ve la configuración del teléfono Bluetooth local, y realiza y acepta conexiones con dispositivos vinculados."</string>
+    <!-- XL -->
+    <string name="policydesc_watchLogin" product="tablet" msgid="7927990389488709968">"Supervisar el número de contraseñas incorrectas ingresadas al desbloquear la pantalla, y bloquear la tableta o eliminar todos los datos del teléfono si se ingresan demasiadas contraseñas incorrectas."</string>
+    <string name="policydesc_watchLogin" product="default" msgid="4998594853332798741">"Supervisa el número de contraseñas incorrectas ingresadas al desbloquear la pantalla, y bloquee el teléfono o elimine todos los datos del teléfono si se ingresan demasiadas contraseñas incorrectas."</string>
+    <!-- XL -->
+    <string name="policydesc_wipeData" product="tablet" msgid="7871059407132175855">"Borrar los datos de la tableta sin advertencias, restableciendo la configuración de fábrica"</string>
+    <string name="policydesc_wipeData" product="default" msgid="6003127471292136411">"Borrar los datos del teléfono sin advertencias al restablecer la configuración original"</string>
+    <!-- XL -->
+  <string-array name="phoneTypes">
+    <item msgid="7066790683658405096">"Pantalla principal"</item>
+    <item msgid="5813675571320075289">"Teléfono móvil"</item>
+    <item msgid="1236863745322977021">"Trabajo"</item>
+    <item msgid="7018038125868933566">"Fax laboral"</item>
+    <item msgid="4280105707643078852">"Fax personal"</item>
+    <item msgid="6527083287534782580">"Localizador"</item>
+    <item msgid="706618935041239888">"Otro"</item>
+    <item msgid="8099625332540070724">"Personalizado"</item>
+  </string-array>
+    <!-- XL -->
+  <string-array name="emailAddressTypes">
+    <item msgid="8080673853442355385">"Pantalla principal"</item>
+    <item msgid="924798042157989715">"Trabajo"</item>
+    <item msgid="1959796935508361158">"Otro"</item>
+    <item msgid="756534161520555926">"Personalizado"</item>
+  </string-array>
+    <!-- XL -->
+  <string-array name="postalAddressTypes">
+    <item msgid="1166454994471190496">"Pantalla principal"</item>
+    <item msgid="3602955376664951787">"Trabajo"</item>
+    <item msgid="4646105398231575508">"Otro"</item>
+    <item msgid="8191179302220976184">"Personalizado"</item>
+  </string-array>
+    <!-- XL -->
+  <string-array name="imAddressTypes">
+    <item msgid="2528436635522549040">"Pantalla principal"</item>
+    <item msgid="5834207144511084508">"Trabajo"</item>
+    <item msgid="3796683891024584813">"Otro"</item>
+    <item msgid="6644316676098098833">"Personalizado"</item>
+  </string-array>
+    <!-- XL -->
+  <string-array name="organizationTypes">
+    <item msgid="6571823895277482483">"Trabajo"</item>
+    <item msgid="4013674940836786104">"Otro"</item>
+    <item msgid="8549998141814637453">"Personalizado"</item>
+  </string-array>
+    <!-- XL -->
+    <string name="phoneTypeHome" msgid="2087652870939635038">"Pantalla principal"</string>
+    <!-- XL -->
+    <string name="phoneTypeMobile" msgid="7084573626440935140">"Teléfono móvil"</string>
+    <!-- XL -->
+    <string name="emailTypeHome" msgid="1298773522695936612">"Pantalla principal"</string>
+    <!-- XL -->
+    <string name="emailTypeMobile" msgid="5515624509217674980">"Teléfono móvil"</string>
+    <!-- XL -->
+    <string name="postalTypeHome" msgid="7553888805834710738">"Pantalla principal"</string>
+    <!-- XL -->
+    <string name="imTypeHome" msgid="3732426015472142690">"Pantalla principal"</string>
+    <!-- XL -->
+    <string name="sipAddressTypeHome" msgid="8212230577724692911">"Pantalla principal"</string>
+    <!-- XL -->
+    <string name="lockscreen_pattern_instructions" msgid="9171665895877154059">"Extraer el patrón para desbloquear"</string>
+    <!-- XL -->
+    <string name="lockscreen_battery_short" msgid="891372653127247039">"Segmento <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+    <!-- XL -->
+    <string name="lockscreen_missing_sim_message" product="tablet" msgid="3961770350078423154">"No hay tarjeta SIM en la tableta."</string>
+    <string name="lockscreen_missing_sim_message" product="default" msgid="5997031739677800758">"No hay tarjeta SIM en el teléfono."</string>
+    <!-- XL -->
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="2429599468920598896">"Has establecido incorrectamente tu gráfico de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <!-- XL -->
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3211267232692817092">"Has establecido incorrectamente tu gráfico de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu tableta al acceder a Google."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="7097890594752816076">"Has establecido incorrectamente tu gráfico de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu teléfono al acceder a Google. "\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <!-- XL -->
+    <string name="lockscreen_glogin_submit_button" msgid="4760302858316749698">"Acceder"</string>
+    <!-- XL -->
+    <string name="lockscreen_glogin_invalid_input" msgid="7265806099449246244">"Nombre de usuario o contraseña no válidos."</string>
+    <!-- XL -->
+    <string name="hour_ampm" msgid="6161399724998500216">"Segmento <xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+    <!-- XL -->
+    <string name="hour_cap_ampm" msgid="724197720606114012">"Segmento <xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+    <!-- XL -->
+    <string name="double_tap_toast" msgid="2893001600485832537">"Sugerencia: presiona dos veces para acercar y alejar"</string>
+    <!-- XL -->
+    <string name="autofill_address_name_separator" msgid="5171727678145785075">" Segmento "</string>
+    <!-- XL -->
+    <string name="permlab_readHistoryBookmarks" msgid="6148149152792104516">"leer historial y favoritos del navegador"</string>
+    <!-- XL -->
+    <string name="permdesc_readHistoryBookmarks" msgid="7371336472744100059">"Permite a la aplicación leer todas las URL que ha visitado el navegador y todos los favoritos del navegador."</string>
+    <!-- XL -->
+    <string name="permlab_writeHistoryBookmarks" msgid="1369319390968848231">"escribir historial y favoritos del navegador"</string>
+    <!-- XL -->
+    <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="3870229397949634482">"Permite que una aplicación modifique el historial de navegación y los favoritos del navegador almacenados en tu tableta. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar los datos en tu navegador."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="6845659334691579933">"Permite a una aplicación modificar el historial y los favoritos del navegador almacenados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar tus datos."</string>
+    <!-- XL -->
+    <string name="permlab_setAlarm" msgid="8112208516527103653">"fija la alarma en el reloj de alarma"</string>
+    <!-- XL -->
+    <string name="permdesc_setAlarm" msgid="5454386032150297784">"Permite a la aplicación fijar una alarma en una aplicación de alarma. Es posible que algunas aplicaciones de alarma no implementen esta función."</string>
+    <!-- XL -->
+    <string name="menu_delete_shortcut_label" msgid="8482704027019632634">"eliminar"</string>
+    <!-- XL -->
+  <plurals name="num_minutes_ago">
+    <item quantity="one" msgid="468685153446407901">"hace 1 minuto"</item>
+    <item quantity="other" msgid="211907662145171054">"Hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+  </plurals>
+    <!-- XL -->
+  <plurals name="num_hours_ago">
+    <item quantity="one" msgid="2172827344495633666">"hace 1 hora"</item>
+    <item quantity="other" msgid="6094391999921908511">"Hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+  </plurals>
+    <!-- XL -->
+  <plurals name="num_days_ago">
+    <item quantity="one" msgid="3766494702684657165">"ayer"</item>
+    <item quantity="other" msgid="5030316952487658828">"Hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
+  </plurals>
+    <!-- XL -->
+  <plurals name="abbrev_num_seconds_ago">
+    <item quantity="one" msgid="1441918190525197797">"hace 1 s"</item>
+    <item quantity="other" msgid="3958332340802316933">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+  </plurals>
+    <!-- XL -->
+  <plurals name="abbrev_num_minutes_ago">
+    <item quantity="one" msgid="3404245071272952255">"hace 1 min"</item>
+    <item quantity="other" msgid="6004808520903389765">"hace <xliff:g id="COUNT">%d</xliff:g> min"</item>
+  </plurals>
+    <!-- XL -->
+  <plurals name="abbrev_num_hours_ago">
+    <item quantity="one" msgid="806010152744475654">"hace 1 hora"</item>
+    <item quantity="other" msgid="7553525762196895290">"Hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+  </plurals>
+    <!-- XL -->
+  <plurals name="abbrev_num_days_ago">
+    <item quantity="one" msgid="5819444260187611238">"ayer"</item>
+    <item quantity="other" msgid="1069986768190052012">"Hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
+  </plurals>
+    <!-- XL -->
+    <string name="preposition_for_time" msgid="3606608741888559522">"a la/s <xliff:g id="TIME">%s</xliff:g>"</string>
+    <!-- XL -->
+    <string name="minutes" msgid="1486240209627391507">"min"</string>
+    <!-- XL -->
+    <string name="selectAll" msgid="847570914566450966">"Seleccionar todos"</string>
+    <!-- XL -->
+    <string name="low_internal_storage_view_text" product="tablet" msgid="6497548813789342134">"Está quedando poco espacio de almacenamiento en la tableta."</string>
+    <string name="low_internal_storage_view_text" product="default" msgid="2901569701336868928">"Hay poco espacio de almacenamiento en el teléfono."</string>
+    <!-- XL -->
+    <string name="capital_on" msgid="5705918046896729554">"ENCENDIDO"</string>
+    <!-- XL -->
+    <string name="wait" msgid="8036803866051401072">"Espera"</string>
+    <!-- XL -->
+    <string name="heavy_weight_notification" msgid="5762367358298413602">"<xliff:g id="APP">%1$s</xliff:g> se está ejecutando"</string>
+    <!-- XL -->
+    <string name="ext_media_checking_notification_title" product="nosdcard" msgid="103298639852047758">"Preparando almacenamiento USB"</string>
+    <string name="ext_media_checking_notification_title" product="default" msgid="2111086053471573248">"Preparando la tarjeta SD"</string>
+    <!-- XL -->
+    <string name="ime_action_done" msgid="7200237418945571897">"Listo"</string>
+    <!-- XL -->
+    <string name="wallpaper_binding_label" msgid="6966627494441714436">"Fondo de pantalla"</string>
+    <!-- XL -->
+    <string name="websearch" msgid="904596193450917688">"Búsqueda web"</string>
+    <!-- XL -->
+    <string name="permlab_mediaStorageWrite" product="default" msgid="5585262071354704256">"modificar/eliminar los contenidos del almacenamientos de medios internos"</string>
+    <!-- XL -->
+    <string name="permdesc_mediaStorageWrite" product="default" msgid="2372999661142345443">"Permite que una aplicación modifique los contenidos del almacenamiento interno de medios."</string>
+    <!-- XL -->
+    <string name="autofill_address_summary_name_format" msgid="7531610259426153850">"$1$2$3"</string>
+    <!-- XL -->
+    <string name="autofill_address_summary_format" msgid="8398158823767723887">"$1$2$3"</string>
+    <!-- XL -->
+    <string name="gpsNotifTicker" msgid="6612390321359669319">"Solicitud de ubicación de <xliff:g id="NAME">%s</xliff:g>"</string>
+    <!-- XL -->
+    <string name="gpsNotifTitle" msgid="7533028619350196545">"Solicitud de ubicación"</string>
+    <!-- XL -->
+    <string name="gpsNotifMessage" msgid="5592972401593755530">"Solicitado por <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SERVICE">%2$s</xliff:g>)"</string>
+    <!-- XL -->
+    <string name="gpsVerifYes" msgid="1511016393202739483">"Sí"</string>
+    <!-- XL -->
+    <string name="gpsVerifNo" msgid="661731239940896232">"No"</string>
+    <!-- XL -->
+    <string name="sync_too_many_deletes" msgid="6088394702274114202">"Eliminar el límite excedido"</string>
+    <!-- XL -->
+    <string name="sync_too_many_deletes_desc" msgid="4794082462774743277">"Existen <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> artículos eliminados para <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, cuenta <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. ¿Qué te gustaría hacer?"</string>
+    <!-- XL -->
+    <string name="sync_really_delete" msgid="7782215155483034729">"Eliminar artículos."</string>
+    <!-- XL -->
+    <string name="sync_undo_deletes" msgid="6501390120900825477">"Deshacer eliminaciones."</string>
+    <!-- XL -->
+    <string name="sync_do_nothing" msgid="612038572646360281">"No hagas nada por el momento."</string>
+</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index f909bd6..7275ef4 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2047,9 +2047,6 @@
              will use only the number of items in the adapter and the number of items visible
              on screen to determine the scrollbar's properties. -->
         <attr name="smoothScrollbar" format="boolean" />
-        <!-- A reference to an XML description of the adapter to attach to the list.
-             XXX Should remove? -->
-        <attr name="adapter" format="reference" />
         <!-- Defines the choice behavior for the view. By default, lists do not have
              any choice behavior. By setting the choiceMode to singleChoice, the list
              allows up to one item to be in a chosen state. By setting the choiceMode to
@@ -4578,74 +4575,6 @@
         <attr name="settingsActivity" />
     </declare-styleable>
 
-    <!-- =============================== -->
-    <!-- Adapters attributes             -->
-    <!-- =============================== -->
-    <eat-comment />
-
-    <!-- Adapter used to bind cursors.
-         @hide XXX should remove? -->
-    <declare-styleable name="CursorAdapter">
-        <!-- URI to get the cursor from. Optional. -->
-        <attr name="uri" format="string" />
-        <!-- Selection statement for the query. Optional. -->
-        <attr name="selection" format="string" />
-        <!-- Sort order statement for the query. Optional. -->
-        <attr name="sortOrder" format="string" />
-        <!-- Layout resource used to display each row from the cursor. Mandatory. -->
-        <attr name="layout" />
-    </declare-styleable>
-
-    <!-- Attributes used in bind items for XML cursor adapters.
-         @hide XXX should remove? -->
-    <declare-styleable name="CursorAdapter_BindItem">
-        <!-- The name of the column to bind from. Mandatory. -->
-        <attr name="from" format="string" />
-        <!-- The resource id of the view to bind to. Mandatory. -->
-        <attr name="to" format="reference" />
-        <!-- The type of binding. If this value is not specified, the type will be
-             inferred from the type of the "to" target view. Mandatory.
-
-             The type can be one of:
-             <ul>
-             <li>string, The content of the column is interpreted as a string.</li>
-             <li>image, The content of the column is interpreted as a blob describing an image.</li>
-             <li>image-uri, The content of the column is interpreted as a URI to an image.</li>
-             <li>drawable, The content of the column is interpreted as a resource id to a drawable.</li>
-             <li>A fully qualified class name, corresponding to an implementation of
-                 android.widget.Adapters.CursorBinder.</li>
-             </ul>
-         -->
-        <attr name="as" format="string" />
-    </declare-styleable>
-
-    <!-- Attributes used in select items for XML cursor adapters.
-         @hide XXX should remove? -->
-    <declare-styleable name="CursorAdapter_SelectItem">
-        <!-- The name of the column to select. Mandatory. -->
-        <attr name="column" format="string" />
-    </declare-styleable>
-
-    <!-- Attributes used to map values to new values in XML cursor adapters' bind items.
-         @hide XXX should remove? -->
-    <declare-styleable name="CursorAdapter_MapItem">
-        <!-- The original value from the column. Mandatory. -->
-        <attr name="fromValue" format="string" />
-        <!-- The new value from the column. Mandatory. -->
-        <attr name="toValue" format="string" />
-    </declare-styleable>
-
-    <!-- Attributes used to map values to new values in XML cursor adapters' bind items.
-         @hide XXX should remove? -->
-    <declare-styleable name="CursorAdapter_TransformItem">
-        <!-- The transformation expression. Mandatory if "withClass" is not specified. -->
-        <attr name="withExpression" format="string" />
-        <!-- The transformation class, an implementation of
-             android.widget.Adapters.CursorTransformation. Mandatory if "withExpression"
-             is not specified. -->
-        <attr name="withClass" format="string" />
-    </declare-styleable>
-
     <!-- Attributes used to style the Action Bar. -->
     <declare-styleable name="ActionBar">
         <!-- The type of navigation to use. -->
diff --git a/core/tests/coretests/src/android/widget/TextViewWordLimitsTest.java b/core/tests/coretests/src/android/widget/TextViewWordLimitsTest.java
index fbc9e1f..20305bf 100644
--- a/core/tests/coretests/src/android/widget/TextViewWordLimitsTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewWordLimitsTest.java
@@ -231,12 +231,22 @@
         final String SURROGATE_SYMBOL   = "\uD83D\uDE01\uD83D\uDE02\uD83D\uDE03"; // Three smileys
 
         // Letter Other is included even when coded as surrogate pairs
-        verifyWordLimits(SURROGATE_LETTER, 1, -1, -1);
-        verifyWordLimits(SURROGATE_LETTER, 2, -1, -1);
+        verifyWordLimits(SURROGATE_LETTER, 0, 0, 6);
+        verifyWordLimits(SURROGATE_LETTER, 1, 0, 6);
+        verifyWordLimits(SURROGATE_LETTER, 2, 0, 6);
+        verifyWordLimits(SURROGATE_LETTER, 3, 0, 6);
+        verifyWordLimits(SURROGATE_LETTER, 4, 0, 6);
+        verifyWordLimits(SURROGATE_LETTER, 5, 0, 6);
+        verifyWordLimits(SURROGATE_LETTER, 6, 0, 6);
 
         // Not included classes are ignored even when coded as surrogate pairs
+        verifyWordLimits(SURROGATE_SYMBOL, 0, -1, -1);
         verifyWordLimits(SURROGATE_SYMBOL, 1, -1, -1);
         verifyWordLimits(SURROGATE_SYMBOL, 2, -1, -1);
+        verifyWordLimits(SURROGATE_SYMBOL, 3, -1, -1);
+        verifyWordLimits(SURROGATE_SYMBOL, 4, -1, -1);
+        verifyWordLimits(SURROGATE_SYMBOL, 5, -1, -1);
+        verifyWordLimits(SURROGATE_SYMBOL, 6, -1, -1);
     }
 
     /**
diff --git a/graphics/java/android/renderscript/FileA3D.java b/graphics/java/android/renderscript/FileA3D.java
index c3e5faf..01a9a82 100644
--- a/graphics/java/android/renderscript/FileA3D.java
+++ b/graphics/java/android/renderscript/FileA3D.java
@@ -167,47 +167,57 @@
         return mFileEntries[index];
     }
 
-    // API cleanup stand-ins
-    // TODO: implement ermaining loading mechanisms
-    static public FileA3D createFromAsset(RenderScript rs, AssetManager mgr, String path)
-        throws IllegalArgumentException {
-        return null;
+    static public FileA3D createFromAsset(RenderScript rs, AssetManager mgr, String path) {
+        rs.validate();
+        int fileId = rs.nFileA3DCreateFromAsset(mgr, path);
+
+        if(fileId == 0) {
+            throw new RSRuntimeException("Unable to create a3d file from asset " + path);
+        }
+        FileA3D fa3d = new FileA3D(fileId, rs, null);
+        fa3d.initEntries();
+        return fa3d;
     }
 
-    static public FileA3D createFromFile(RenderScript rs, String path)
-        throws IllegalArgumentException {
-        return null;
+    static public FileA3D createFromFile(RenderScript rs, String path) {
+        int fileId = rs.nFileA3DCreateFromFile(path);
+
+        if(fileId == 0) {
+            throw new RSRuntimeException("Unable to create a3d file from " + path);
+        }
+        FileA3D fa3d = new FileA3D(fileId, rs, null);
+        fa3d.initEntries();
+        return fa3d;
     }
 
-    static public FileA3D createFromFile(RenderScript rs, File path)
-        throws IllegalArgumentException {
+    static public FileA3D createFromFile(RenderScript rs, File path) {
         return createFromFile(rs, path.getAbsolutePath());
     }
 
-    static public FileA3D createFromResource(RenderScript rs, Resources res, int id)
-        throws IllegalArgumentException {
+    static public FileA3D createFromResource(RenderScript rs, Resources res, int id) {
 
         rs.validate();
         InputStream is = null;
         try {
-            final TypedValue value = new TypedValue();
-            is = res.openRawResource(id, value);
-
-            int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
-
-            int fileId = rs.nFileA3DCreateFromAssetStream(asset);
-
-            if(fileId == 0) {
-                throw new IllegalStateException("Load failed.");
-            }
-            FileA3D fa3d = new FileA3D(fileId, rs, is);
-            fa3d.initEntries();
-            return fa3d;
-
+            is = res.openRawResource(id);
         } catch (Exception e) {
-            // Ignore
+            throw new RSRuntimeException("Unable to open resource " + id);
         }
 
-        return null;
+        int fileId = 0;
+        if (is instanceof AssetManager.AssetInputStream) {
+            int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
+            fileId = rs.nFileA3DCreateFromAssetStream(asset);
+        } else {
+            throw new RSRuntimeException("Unsupported asset stream");
+        }
+
+        if(fileId == 0) {
+            throw new RSRuntimeException("Unable to create a3d file from resource " + id);
+        }
+        FileA3D fa3d = new FileA3D(fileId, rs, is);
+        fa3d.initEntries();
+        return fa3d;
+
     }
 }
diff --git a/graphics/java/android/renderscript/Font.java b/graphics/java/android/renderscript/Font.java
index 0f7c24d..ae209fa 100644
--- a/graphics/java/android/renderscript/Font.java
+++ b/graphics/java/android/renderscript/Font.java
@@ -129,41 +129,62 @@
     /**
      * Takes a specific file name as an argument
      */
-    static public Font createFromFile(RenderScript rs, Resources res, String path, float pointSize)
-        throws IllegalArgumentException {
-
+    static public Font createFromFile(RenderScript rs, Resources res, String path, float pointSize) {
         rs.validate();
-        try {
-            int dpi = res.getDisplayMetrics().densityDpi;
-            int fontId = rs.nFontCreateFromFile(path, pointSize, dpi);
+        int dpi = res.getDisplayMetrics().densityDpi;
+        int fontId = rs.nFontCreateFromFile(path, pointSize, dpi);
 
-            if(fontId == 0) {
-                throw new IllegalStateException("Failed loading a font");
-            }
-            Font rsFont = new Font(fontId, rs);
-
-            return rsFont;
-
-        } catch (Exception e) {
-            // Ignore
+        if(fontId == 0) {
+            throw new RSRuntimeException("Unable to create font from file " + path);
         }
+        Font rsFont = new Font(fontId, rs);
 
-        return null;
+        return rsFont;
     }
 
-    static public Font createFromFile(RenderScript rs, Resources res, File path, float pointSize)
-        throws IllegalArgumentException {
+    static public Font createFromFile(RenderScript rs, Resources res, File path, float pointSize) {
         return createFromFile(rs, res, path.getAbsolutePath(), pointSize);
     }
 
-    static public Font createFromAsset(RenderScript rs, Resources res, AssetManager mgr, String path, float pointSize)
-        throws IllegalArgumentException {
-        return null;
+    static public Font createFromAsset(RenderScript rs, Resources res, String path, float pointSize) {
+        rs.validate();
+        AssetManager mgr = res.getAssets();
+        int dpi = res.getDisplayMetrics().densityDpi;
+
+        int fontId = rs.nFontCreateFromAsset(mgr, path, pointSize, dpi);
+        if(fontId == 0) {
+            throw new RSRuntimeException("Unable to create font from asset " + path);
+        }
+        Font rsFont = new Font(fontId, rs);
+        return rsFont;
     }
 
-    static public Font createFromResource(RenderScript rs, Resources res, int id, float pointSize)
-        throws IllegalArgumentException {
-        return null;
+    static public Font createFromResource(RenderScript rs, Resources res, int id, float pointSize) {
+        String name = "R." + Integer.toString(id);
+
+        rs.validate();
+        InputStream is = null;
+        try {
+            is = res.openRawResource(id);
+        } catch (Exception e) {
+            throw new RSRuntimeException("Unable to open resource " + id);
+        }
+
+        int dpi = res.getDisplayMetrics().densityDpi;
+
+        int fontId = 0;
+        if (is instanceof AssetManager.AssetInputStream) {
+            int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
+            fontId = rs.nFontCreateFromAssetStream(name, pointSize, dpi, asset);
+        } else {
+            throw new RSRuntimeException("Unsupported asset stream created");
+        }
+
+        if(fontId == 0) {
+            throw new RSRuntimeException("Unable to create font from resource " + id);
+        }
+        Font rsFont = new Font(fontId, rs);
+        return rsFont;
     }
 
     /**
@@ -175,8 +196,7 @@
      * "monospace" "courier" "courier new" "monaco"
      * Returns default font if no match could be found
      */
-    static public Font create(RenderScript rs, Resources res, String familyName, Style fontStyle, float pointSize)
-    throws IllegalArgumentException {
+    static public Font create(RenderScript rs, Resources res, String familyName, Style fontStyle, float pointSize) {
         String fileName = getFontFileName(familyName, fontStyle);
         String fontPath = Environment.getRootDirectory().getAbsolutePath();
         fontPath += "/fonts/" + fileName;
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 6a52810..665a893 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -19,6 +19,7 @@
 import java.lang.reflect.Field;
 
 import android.content.Context;
+import android.content.res.AssetManager;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.util.Config;
@@ -284,6 +285,14 @@
     synchronized int nFileA3DCreateFromAssetStream(int assetStream) {
         return rsnFileA3DCreateFromAssetStream(mContext, assetStream);
     }
+    native int  rsnFileA3DCreateFromFile(int con, String path);
+    synchronized int nFileA3DCreateFromFile(String path) {
+        return rsnFileA3DCreateFromFile(mContext, path);
+    }
+    native int  rsnFileA3DCreateFromAsset(int con, AssetManager mgr, String path);
+    synchronized int nFileA3DCreateFromAsset(AssetManager mgr, String path) {
+        return rsnFileA3DCreateFromAsset(mContext, mgr, path);
+    }
     native int  rsnFileA3DGetNumIndexEntries(int con, int fileA3D);
     synchronized int nFileA3DGetNumIndexEntries(int fileA3D) {
         return rsnFileA3DGetNumIndexEntries(mContext, fileA3D);
@@ -301,6 +310,14 @@
     synchronized int nFontCreateFromFile(String fileName, float size, int dpi) {
         return rsnFontCreateFromFile(mContext, fileName, size, dpi);
     }
+    native int  rsnFontCreateFromAssetStream(int con, String name, float size, int dpi, int assetStream);
+    synchronized int nFontCreateFromAssetStream(String name, float size, int dpi, int assetStream) {
+        return rsnFontCreateFromAssetStream(mContext, name, size, dpi, assetStream);
+    }
+    native int  rsnFontCreateFromAsset(int con, AssetManager mgr, String path, float size, int dpi);
+    synchronized int nFontCreateFromAsset(AssetManager mgr, String path, float size, int dpi) {
+        return rsnFontCreateFromAsset(mContext, mgr, path, size, dpi);
+    }
 
 
     native void rsnScriptBindAllocation(int con, int script, int alloc, int slot);
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index fe22269..1817a1b 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -32,12 +32,14 @@
 #include <images/SkImageDecoder.h>
 
 #include <utils/Asset.h>
+#include <utils/AssetManager.h>
 #include <utils/ResourceTypes.h>
 
 #include "jni.h"
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
 #include "android_runtime/android_view_Surface.h"
+#include "android_runtime/android_util_AssetManager.h"
 
 #include <RenderScript.h>
 #include <RenderScriptEnv.h>
@@ -47,6 +49,27 @@
 
 using namespace android;
 
+class AutoJavaStringToUTF8 {
+public:
+    AutoJavaStringToUTF8(JNIEnv* env, jstring str) : fEnv(env), fJStr(str)
+    {
+        fCStr = env->GetStringUTFChars(str, NULL);
+        fLength = env->GetStringUTFLength(str);
+    }
+    ~AutoJavaStringToUTF8()
+    {
+        fEnv->ReleaseStringUTFChars(fJStr, fCStr);
+    }
+    const char* c_str() const { return fCStr; }
+    jsize length() const { return fLength; }
+
+private:
+    JNIEnv*     fEnv;
+    jstring     fJStr;
+    const char* fCStr;
+    jsize       fLength;
+};
+
 // ---------------------------------------------------------------------------
 
 static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
@@ -572,7 +595,34 @@
 
     Asset* asset = reinterpret_cast<Asset*>(native_asset);
 
-    jint id = (jint)rsaFileA3DCreateFromAssetStream(con, asset->getBuffer(false), asset->getLength());
+    jint id = (jint)rsaFileA3DCreateFromMemory(con, asset->getBuffer(false), asset->getLength());
+    return id;
+}
+
+static int
+nFileA3DCreateFromAsset(JNIEnv *_env, jobject _this, RsContext con, jobject _assetMgr, jstring _path)
+{
+    AssetManager* mgr = assetManagerForJavaObject(_env, _assetMgr);
+    if (mgr == NULL) {
+        return 0;
+    }
+
+    AutoJavaStringToUTF8 str(_env, _path);
+    Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
+    if (asset == NULL) {
+        return 0;
+    }
+
+    jint id = (jint)rsaFileA3DCreateFromAsset(con, asset);
+    return id;
+}
+
+static int
+nFileA3DCreateFromFile(JNIEnv *_env, jobject _this, RsContext con, jstring fileName)
+{
+    AutoJavaStringToUTF8 fileNameUTF(_env, fileName);
+    jint id = (jint)rsaFileA3DCreateFromFile(con, fileNameUTF.c_str());
+
     return id;
 }
 
@@ -611,11 +661,45 @@
 // -----------------------------------
 
 static int
-nFontCreateFromFile(JNIEnv *_env, jobject _this, RsContext con, jstring fileName, jfloat fontSize, jint dpi)
+nFontCreateFromFile(JNIEnv *_env, jobject _this, RsContext con,
+                    jstring fileName, jfloat fontSize, jint dpi)
 {
-    const char* fileNameUTF = _env->GetStringUTFChars(fileName, NULL);
+    AutoJavaStringToUTF8 fileNameUTF(_env, fileName);
+    jint id = (jint)rsFontCreateFromFile(con, fileNameUTF.c_str(), fontSize, dpi);
 
-    jint id = (jint)rsFontCreateFromFile(con, fileNameUTF, fontSize, dpi);
+    return id;
+}
+
+static int
+nFontCreateFromAssetStream(JNIEnv *_env, jobject _this, RsContext con,
+                           jstring name, jfloat fontSize, jint dpi, jint native_asset)
+{
+    Asset* asset = reinterpret_cast<Asset*>(native_asset);
+    AutoJavaStringToUTF8 nameUTF(_env, name);
+
+    jint id = (jint)rsFontCreateFromMemory(con, nameUTF.c_str(), fontSize, dpi,
+                                           asset->getBuffer(false), asset->getLength());
+    return id;
+}
+
+static int
+nFontCreateFromAsset(JNIEnv *_env, jobject _this, RsContext con, jobject _assetMgr, jstring _path,
+                     jfloat fontSize, jint dpi)
+{
+    AssetManager* mgr = assetManagerForJavaObject(_env, _assetMgr);
+    if (mgr == NULL) {
+        return 0;
+    }
+
+    AutoJavaStringToUTF8 str(_env, _path);
+    Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
+    if (asset == NULL) {
+        return 0;
+    }
+
+    jint id = (jint)rsFontCreateFromMemory(con, str.c_str(), fontSize, dpi,
+                                           asset->getBuffer(false), asset->getLength());
+    delete asset;
     return id;
 }
 
@@ -764,13 +848,10 @@
 nScriptCCreate(JNIEnv *_env, jobject _this, RsContext con, jstring packageName, jstring resName, jstring cacheDir)
 {
     LOG_API("nScriptCCreate, con(%p)", con);
-    const char* packageNameUTF = _env->GetStringUTFChars(packageName, NULL);
-    const char* resNameUTF = _env->GetStringUTFChars(resName, NULL);
-    const char* cacheDirUTF = _env->GetStringUTFChars(cacheDir, NULL);
-    jint i = (jint)rsScriptCCreate(con, packageNameUTF, resNameUTF, cacheDirUTF);
-    _env->ReleaseStringUTFChars(packageName, packageNameUTF);
-    _env->ReleaseStringUTFChars(resName, resNameUTF);
-    _env->ReleaseStringUTFChars(cacheDir, cacheDirUTF);
+    AutoJavaStringToUTF8 packageNameUTF(_env, packageName);
+    AutoJavaStringToUTF8 resNameUTF(_env, resName);
+    AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
+    jint i = (jint)rsScriptCCreate(con, packageNameUTF.c_str(), resNameUTF.c_str(), cacheDirUTF.c_str());
     return i;
 }
 
@@ -853,15 +934,13 @@
 static jint
 nProgramFragmentCreate(JNIEnv *_env, jobject _this, RsContext con, jstring shader, jintArray params)
 {
-    const char* shaderUTF = _env->GetStringUTFChars(shader, NULL);
-    jint shaderLen = _env->GetStringUTFLength(shader);
+    AutoJavaStringToUTF8 shaderUTF(_env, shader);
     jint *paramPtr = _env->GetIntArrayElements(params, NULL);
     jint paramLen = _env->GetArrayLength(params);
 
     LOG_API("nProgramFragmentCreate, con(%p), shaderLen(%i), paramLen(%i)", con, shaderLen, paramLen);
 
-    jint ret = (jint)rsProgramFragmentCreate(con, shaderUTF, shaderLen, (uint32_t *)paramPtr, paramLen);
-    _env->ReleaseStringUTFChars(shader, shaderUTF);
+    jint ret = (jint)rsProgramFragmentCreate(con, shaderUTF.c_str(), shaderUTF.length(), (uint32_t *)paramPtr, paramLen);
     _env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT);
     return ret;
 }
@@ -872,15 +951,13 @@
 static jint
 nProgramVertexCreate(JNIEnv *_env, jobject _this, RsContext con, jstring shader, jintArray params)
 {
-    const char* shaderUTF = _env->GetStringUTFChars(shader, NULL);
-    jint shaderLen = _env->GetStringUTFLength(shader);
+    AutoJavaStringToUTF8 shaderUTF(_env, shader);
     jint *paramPtr = _env->GetIntArrayElements(params, NULL);
     jint paramLen = _env->GetArrayLength(params);
 
     LOG_API("nProgramVertexCreate, con(%p), shaderLen(%i), paramLen(%i)", con, shaderLen, paramLen);
 
-    jint ret = (jint)rsProgramVertexCreate(con, shaderUTF, shaderLen, (uint32_t *)paramPtr, paramLen);
-    _env->ReleaseStringUTFChars(shader, shaderUTF);
+    jint ret = (jint)rsProgramVertexCreate(con, shaderUTF.c_str(), shaderUTF.length(), (uint32_t *)paramPtr, paramLen);
     _env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT);
     return ret;
 }
@@ -1095,12 +1172,16 @@
 {"rsnGetName",                       "(II)Ljava/lang/String;",                (void*)nGetName },
 {"rsnObjDestroy",                    "(II)V",                                 (void*)nObjDestroy },
 
+{"rsnFileA3DCreateFromFile",         "(ILjava/lang/String;)I",                (void*)nFileA3DCreateFromFile },
 {"rsnFileA3DCreateFromAssetStream",  "(II)I",                                 (void*)nFileA3DCreateFromAssetStream },
+{"rsnFileA3DCreateFromAsset",        "(ILandroid/content/res/AssetManager;Ljava/lang/String;)I",            (void*)nFileA3DCreateFromAsset },
 {"rsnFileA3DGetNumIndexEntries",     "(II)I",                                 (void*)nFileA3DGetNumIndexEntries },
 {"rsnFileA3DGetIndexEntries",        "(III[I[Ljava/lang/String;)V",           (void*)nFileA3DGetIndexEntries },
 {"rsnFileA3DGetEntryByIndex",        "(III)I",                                (void*)nFileA3DGetEntryByIndex },
 
 {"rsnFontCreateFromFile",            "(ILjava/lang/String;FI)I",              (void*)nFontCreateFromFile },
+{"rsnFontCreateFromAssetStream",     "(ILjava/lang/String;FII)I",             (void*)nFontCreateFromAssetStream },
+{"rsnFontCreateFromAsset",        "(ILandroid/content/res/AssetManager;Ljava/lang/String;FI)I",            (void*)nFontCreateFromAsset },
 
 {"rsnElementCreate",                 "(IIIZI)I",                              (void*)nElementCreate },
 {"rsnElementCreate2",                "(I[I[Ljava/lang/String;[I)I",           (void*)nElementCreate2 },
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index ed54b37..03dd52d 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -56,6 +56,7 @@
     METADATA_KEY_MIMETYPE        = 22,
     METADATA_KEY_DISC_NUMBER     = 23,
     METADATA_KEY_ALBUMARTIST     = 24,
+    METADATA_KEY_COMPILATION     = 25,
     // Add more here...
 };
 
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 5f33739..5170a2c 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -80,6 +80,7 @@
     kKeyDiscNumber        = 'dnum',  // cstring
     kKeyDate              = 'date',  // cstring
     kKeyWriter            = 'writ',  // cstring
+    kKeyCompilation       = 'cpil',  // cstring
     kKeyTimeScale         = 'tmsl',  // int32_t
 
     // video profile and level
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index 87758e5..f160ef1 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -334,7 +334,9 @@
 // A3D loading and object update code.
 // Should only be called at object creation, not thread safe
 RsObjectBase rsaFileA3DGetEntryByIndex(RsContext, uint32_t idx, RsFile);
-RsFile rsaFileA3DCreateFromAssetStream(RsContext, const void *data, uint32_t len);
+RsFile rsaFileA3DCreateFromMemory(RsContext, const void *data, uint32_t len);
+RsFile rsaFileA3DCreateFromAsset(RsContext, void *asset);
+RsFile rsaFileA3DCreateFromFile(RsContext, const char *path);
 void rsaFileA3DGetNumIndexEntries(RsContext, int32_t *numEntries, RsFile);
 void rsaFileA3DGetIndexEntries(RsContext, RsFileIndexEntry *fileEntries,uint32_t numEntries, RsFile);
 void rsaGetName(RsContext, void * obj, const char **name);
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 3483a5d..33ac2f0 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -346,12 +346,6 @@
 	ret RsProgramVertex
 	}
 
-FileOpen {
-	ret RsFile
-	param const char *name
-	param size_t len
-	}
-
 FontCreateFromFile {
 	param const char *name
 	param float fontSize
@@ -359,6 +353,15 @@
 	ret RsFont
 	}
 
+FontCreateFromMemory {
+	param const char *name
+	param float fontSize
+	param uint32_t dpi
+    param const void *data
+    param uint32_t dataLen
+	ret RsFont
+	}
+
 MeshCreate {
 	ret RsMesh
 	param uint32_t vtxCount
diff --git a/libs/rs/rsFileA3D.cpp b/libs/rs/rsFileA3D.cpp
index 0c8692d..d34ddd6 100644
--- a/libs/rs/rsFileA3D.cpp
+++ b/libs/rs/rsFileA3D.cpp
@@ -35,6 +35,7 @@
     mData = NULL;
     mWriteStream = NULL;
     mReadStream = NULL;
+    mAsset = NULL;
 
     mMajorVersion = 0;
     mMinorVersion = 1;
@@ -57,6 +58,9 @@
     if (mAlloc) {
         free(mAlloc);
     }
+    if (mAsset) {
+        delete mAsset;
+    }
 }
 
 void FileA3D::parseHeader(IStream *headerStream) {
@@ -83,6 +87,11 @@
     }
 }
 
+bool FileA3D::load(Asset *asset) {
+    mAsset = asset;
+    return load(asset->getBuffer(false), asset->getLength());
+}
+
 bool FileA3D::load(const void *data, size_t length) {
     const uint8_t *localData = (const uint8_t *)data;
 
@@ -357,26 +366,6 @@
     mWriteStream->align(4);
 }
 
-namespace android {
-namespace renderscript {
-
-RsFile rsi_FileOpen(Context *rsc, char const *path, unsigned int len) {
-    FileA3D *fa3d = new FileA3D(rsc);
-
-    FILE *f = fopen("/sdcard/test.a3d", "rb");
-    if (f) {
-        fa3d->load(f);
-        fclose(f);
-        fa3d->incUserRef();
-        return fa3d;
-    }
-    delete fa3d;
-    return NULL;
-}
-
-}
-}
-
 RsObjectBase rsaFileA3DGetEntryByIndex(RsContext con, uint32_t index, RsFile file) {
     FileA3D *fa3d = static_cast<FileA3D *>(file);
     if (!fa3d) {
@@ -422,7 +411,7 @@
     }
 }
 
-RsFile rsaFileA3DCreateFromAssetStream(RsContext con, const void *data, uint32_t len) {
+RsFile rsaFileA3DCreateFromMemory(RsContext con, const void *data, uint32_t len) {
     if (data == NULL) {
         LOGE("File load failed. Asset stream is NULL");
         return NULL;
@@ -435,3 +424,35 @@
     fa3d->load(data, len);
     return fa3d;
 }
+
+RsFile rsaFileA3DCreateFromAsset(RsContext con, void *_asset) {
+    Context *rsc = static_cast<Context *>(con);
+    Asset *asset = static_cast<Asset *>(_asset);
+    FileA3D *fa3d = new FileA3D(rsc);
+    fa3d->incUserRef();
+
+    fa3d->load(asset);
+    return fa3d;
+}
+
+RsFile rsaFileA3DCreateFromFile(RsContext con, const char *path) {
+    if (path == NULL) {
+        LOGE("File load failed. Path is NULL");
+        return NULL;
+    }
+
+    Context *rsc = static_cast<Context *>(con);
+    FileA3D *fa3d = NULL;
+
+    FILE *f = fopen(path, "rb");
+    if (f) {
+        fa3d = new FileA3D(rsc);
+        fa3d->incUserRef();
+        fa3d->load(f);
+        fclose(f);
+    } else {
+        LOGE("Could not open file %s", path);
+    }
+
+    return fa3d;
+}
diff --git a/libs/rs/rsFileA3D.h b/libs/rs/rsFileA3D.h
index 3ece4c9..056b5af 100644
--- a/libs/rs/rsFileA3D.h
+++ b/libs/rs/rsFileA3D.h
@@ -21,6 +21,7 @@
 #include "rsMesh.h"
 
 #include <utils/String8.h>
+#include <utils/Asset.h>
 #include "rsStream.h"
 #include <stdio.h>
 
@@ -59,6 +60,7 @@
     };
 
     bool load(FILE *f);
+    bool load(Asset *asset);
     bool load(const void *data, size_t length);
 
     size_t getNumIndexEntries() const;
@@ -83,6 +85,7 @@
     const uint8_t * mData;
     void * mAlloc;
     uint64_t mDataSize;
+    Asset *mAsset;
 
     OStream *mWriteStream;
     Vector<A3DIndexEntry*> mWriteIndex;
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index 3dcf743..8571c32 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -40,13 +40,19 @@
     mFace = NULL;
 }
 
-bool Font::init(const char *name, float fontSize, uint32_t dpi) {
+bool Font::init(const char *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
     if (mInitialized) {
         LOGE("Reinitialization of fonts not supported");
         return false;
     }
 
-    FT_Error error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
+    FT_Error error = 0;
+    if (data != NULL && dataLen > 0) {
+        error = FT_New_Memory_Face(mRSC->mStateFont.getLib(), (const FT_Byte*)data, dataLen, 0, &mFace);
+    } else {
+        error = FT_New_Face(mRSC->mStateFont.getLib(), name, 0, &mFace);
+    }
+
     if (error) {
         LOGE("Unable to initialize font %s", name);
         return false;
@@ -127,7 +133,8 @@
     int32_t width = (int32_t) glyph->mBitmapWidth;
     int32_t height = (int32_t) glyph->mBitmapHeight;
 
-    if (bounds->bottom > nPenY) {
+    // 0, 0 is top left, so bottom is a positive number
+    if (bounds->bottom < nPenY) {
         bounds->bottom = nPenY;
     }
     if (bounds->left > nPenX) {
@@ -136,8 +143,8 @@
     if (bounds->right < nPenX + width) {
         bounds->right = nPenX + width;
     }
-    if (bounds->top < nPenY + height) {
-        bounds->top = nPenY + height;
+    if (bounds->top > nPenY - height) {
+        bounds->top = nPenY - height;
     }
 }
 
@@ -155,7 +162,7 @@
             return;
         }
         // Reset min and max of the bounding box to something large
-        bounds->set(1e6, -1e6, -1e6, 1e6);
+        bounds->set(1e6, -1e6, 1e6, -1e6);
     }
 
     int32_t penX = x, penY = y;
@@ -273,7 +280,8 @@
     return newGlyph;
 }
 
-Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi) {
+Font * Font::create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
+                    const void *data, uint32_t dataLen) {
     rsc->mStateFont.checkInit();
     Vector<Font*> &activeFonts = rsc->mStateFont.mActiveFonts;
 
@@ -285,7 +293,7 @@
     }
 
     Font *newFont = new Font(rsc);
-    bool isInitialized = newFont->init(name, fontSize, dpi);
+    bool isInitialized = newFont->init(name, fontSize, dpi, data, dataLen);
     if (isInitialized) {
         activeFonts.push(newFont);
         rsc->mStateFont.precacheLatin(newFont);
@@ -743,6 +751,8 @@
 
 void FontState::measureText(const char *text, uint32_t len, Font::Rect *bounds) {
     renderText(text, len, 0, 0, 0, -1, Font::MEASURE, bounds);
+    bounds->bottom = - bounds->bottom;
+    bounds->top = - bounds->top;
 }
 
 void FontState::setFontColor(float r, float g, float b, float a) {
@@ -811,5 +821,13 @@
     return newFont;
 }
 
+RsFont rsi_FontCreateFromMemory(Context *rsc, char const *name, float fontSize, uint32_t dpi, const void *data, uint32_t dataLen) {
+    Font *newFont = Font::create(rsc, name, fontSize, dpi, data, dataLen);
+    if (newFont) {
+        newFont->incUserRef();
+    }
+    return newFont;
+}
+
 } // renderscript
 } // android
diff --git a/libs/rs/rsFont.h b/libs/rs/rsFont.h
index c24c9f1..00d77c8 100644
--- a/libs/rs/rsFont.h
+++ b/libs/rs/rsFont.h
@@ -73,7 +73,8 @@
         return RS_A3D_CLASS_ID_UNKNOWN;
     }
 
-    static Font * create(Context *rsc, const char *name, float fontSize, uint32_t dpi);
+    static Font * create(Context *rsc, const char *name, float fontSize, uint32_t dpi,
+                         const void *data = NULL, uint32_t dataLen = 0);
 
 protected:
 
@@ -116,7 +117,7 @@
     uint32_t mDpi;
 
     Font(Context *rsc);
-    bool init(const char *name, float fontSize, uint32_t dpi);
+    bool init(const char *name, float fontSize, uint32_t dpi, const void *data = NULL, uint32_t dataLen = 0);
 
     FT_Face mFace;
     bool mInitialized;
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 6209dc0..b99f7ed 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -345,5 +345,6 @@
     public static final int METADATA_KEY_MIMETYPE        = 22;
     public static final int METADATA_KEY_DISCNUMBER      = 23;
     public static final int METADATA_KEY_ALBUMARTIST     = 24;
+    public static final int METADATA_KEY_COMPILATION     = 25;
     // Add more here...
 }
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 9610f90..0bb3a86 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -614,6 +614,7 @@
         { kKeyAuthor, "TXT", "TEXT" },
         { kKeyCDTrackNumber, "TRK", "TRCK" },
         { kKeyDiscNumber, "TPA", "TPOS" },
+        { kKeyCompilation, "TCP", "TCMP" },
     };
     static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
 
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index dfc9b5a..bafa243 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1392,6 +1392,17 @@
             metadataKey = kKeyGenre;
             break;
         }
+        case FOURCC('c', 'p', 'i', 'l'):
+        {
+            if (size == 9 && flags == 21) {
+                char tmp[16];
+                sprintf(tmp, "%d",
+                        (int)buffer[size - 1]);
+
+                mFileMetaData->setCString(kKeyCompilation, tmp);
+            }
+            break;
+        }
         case FOURCC('t', 'r', 'k', 'n'):
         {
             if (size == 16 && flags == 0) {
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 4b8a014..cf622af 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -660,6 +660,9 @@
     } kMap[] = {
         { "TITLE", kKeyTitle },
         { "ARTIST", kKeyArtist },
+        { "ALBUMARTIST", kKeyAlbumArtist },
+        { "ALBUM ARTIST", kKeyAlbumArtist },
+        { "COMPILATION", kKeyCompilation },
         { "ALBUM", kKeyAlbum },
         { "COMPOSER", kKeyComposer },
         { "GENRE", kKeyGenre },
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index 86e0e73..5d15246 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -156,6 +156,7 @@
             { "year", METADATA_KEY_YEAR },
             { "duration", METADATA_KEY_DURATION },
             { "writer", METADATA_KEY_WRITER },
+            { "compilation", METADATA_KEY_COMPILATION },
         };
         static const size_t kNumEntries = sizeof(kKeyMap) / sizeof(kKeyMap[0]);
 
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 8cd2998..4f483ac 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -394,6 +394,7 @@
         { kKeyTitle, METADATA_KEY_TITLE },
         { kKeyYear, METADATA_KEY_YEAR },
         { kKeyWriter, METADATA_KEY_WRITER },
+        { kKeyCompilation, METADATA_KEY_COMPILATION },
     };
     static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
 
diff --git a/opengl/tests/hwc/Android.mk b/opengl/tests/hwc/Android.mk
index 743dbf1..93a5545 100644
--- a/opengl/tests/hwc/Android.mk
+++ b/opengl/tests/hwc/Android.mk
@@ -1,7 +1,40 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= hwc_stress.cpp
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE:= libhwcTest
+LOCAL_SRC_FILES:= hwcTestLib.cpp
+LOCAL_C_INCLUDES += system/extras/tests/include \
+    bionic \
+    bionic/libstdc++/include \
+    external/stlport/stlport \
+    frameworks/base/opengl/tests \
+    frameworks/base/opengl/tests/include \
+
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
+LOCAL_SHARED_LIBRARIES += libcutils libutils libstlport
+LOCAL_STATIC_LIBRARIES += libglTest
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= hwcStress.cpp
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
@@ -12,12 +45,18 @@
 
 LOCAL_STATIC_LIBRARIES := \
     libtestUtil \
+    libglTest \
+    libhwcTest \
 
 LOCAL_C_INCLUDES += \
     system/extras/tests/include \
     hardware/libhardware/include \
+    frameworks/base/opengl/tests \
+    frameworks/base/opengl/tests/include \
 
-LOCAL_MODULE:= hwc_stress
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
+LOCAL_MODULE:= hwcStress
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativestresstest
 
 LOCAL_MODULE_TAGS := tests
@@ -25,3 +64,63 @@
 LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 
 include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= hwcRects.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    libEGL \
+    libGLESv2 \
+    libui \
+    libhardware \
+
+LOCAL_STATIC_LIBRARIES := \
+    libtestUtil \
+    libglTest \
+    libhwcTest \
+
+LOCAL_C_INCLUDES += \
+    system/extras/tests/include \
+    hardware/libhardware/include \
+    frameworks/base/opengl/tests \
+    frameworks/base/opengl/tests/include \
+
+LOCAL_MODULE:= hwcRects
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativeutil
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= hwcColorEquiv.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    libEGL \
+    libGLESv2 \
+    libui \
+    libhardware \
+
+LOCAL_STATIC_LIBRARIES := \
+    libtestUtil \
+    libglTest \
+    libhwcTest \
+
+LOCAL_C_INCLUDES += \
+    system/extras/tests/include \
+    hardware/libhardware/include \
+    frameworks/base/opengl/tests \
+    frameworks/base/opengl/tests/include \
+
+LOCAL_MODULE:= hwcColorEquiv
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativeutil
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
+include $(BUILD_NATIVE_TEST)
diff --git a/opengl/tests/hwc/hwcColorEquiv.cpp b/opengl/tests/hwc/hwcColorEquiv.cpp
new file mode 100644
index 0000000..4a87a05
--- /dev/null
+++ b/opengl/tests/hwc/hwcColorEquiv.cpp
@@ -0,0 +1,436 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ * Hardware Composer Color Equivalence
+ *
+ * Synopsis
+ *   hwc_colorequiv [options] eFmt
+ *
+ *     options:
+         -v - verbose
+ *       -s <0.##, 0.##, 0.##> - Start color (default: <0.0, 0.0, 0.0>
+ *       -e <0.##, 0.##, 0.##> - Ending color (default: <1.0, 1.0, 1.0>
+ *       -r fmt - reference graphic format
+ *       -D #.## - End of test delay
+ *
+ *     graphic formats:
+ *       RGBA8888 (reference frame default)
+ *       RGBX8888
+ *       RGB888
+ *       RGB565
+ *       BGRA8888
+ *       RGBA5551
+ *       RGBA4444
+ *       YV12
+ *
+ * Description
+ *   Renders a horizontal blend in two frames.  The first frame is rendered
+ *   in the upper third of the display and is called the reference frame.
+ *   The second frame is displayed in the middle third and is called the
+ *   equivalence frame.  The primary purpose of this utility is to verify
+ *   that the colors produced in the reference and equivalence frames are
+ *   the same.  The colors are the same when the colors are the same
+ *   vertically between the reference and equivalence frames.
+ *
+ *   By default the reference frame is rendered through the use of the
+ *   RGBA8888 graphic format.  The -r option can be used to specify a
+ *   non-default reference frame graphic format.  The graphic format of
+ *   the equivalence frame is determined by a single required positional
+ *   parameter.  Intentionally there is no default for the graphic format
+ *   of the equivalence frame.
+ *
+ *   The horizontal blend in the reference frame is produced from a linear
+ *   interpolation from a start color (default: <0.0, 0.0, 0.0> on the left
+ *   side to an end color (default <1.0, 1.0, 1.0> on the right side.  Where
+ *   possible the equivalence frame is rendered with the equivalent color
+ *   from the reference frame.  A color of black is used in the equivalence
+ *   frame for cases where an equivalent color does not exist.
+ */
+
+#include <algorithm>
+#include <assert.h>
+#include <cerrno>
+#include <cmath>
+#include <cstdlib>
+#include <ctime>
+#include <libgen.h>
+#include <sched.h>
+#include <sstream>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <vector>
+
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/EGLUtils.h>
+
+#define LOG_TAG "hwcColorEquivTest"
+#include <utils/Log.h>
+#include <testUtil.h>
+
+#include <hardware/hwcomposer.h>
+
+#include "hwcTestLib.h"
+
+using namespace std;
+using namespace android;
+
+// Defaults for command-line options
+const bool defaultVerbose = false;
+const ColorFract defaultStartColor(0.0, 0.0, 0.0);
+const ColorFract defaultEndColor(1.0, 1.0, 1.0);
+const char *defaultRefFormat = "RGBA8888";
+const float defaultEndDelay = 2.0; // Default delay after rendering graphics
+
+// Defines
+#define MAXSTR               100
+#define MAXCMD               200
+#define BITSPERBYTE            8 // TODO: Obtain from <values.h>, once
+                                 // it has been added
+
+#define CMD_STOP_FRAMEWORK   "stop 2>&1"
+#define CMD_START_FRAMEWORK  "start 2>&1"
+
+// Macros
+#define NUMA(a) (sizeof(a) / sizeof(a [0])) // Num elements in an array
+#define MEMCLR(addr, size) do { \
+        memset((addr), 0, (size)); \
+    } while (0)
+
+// Globals
+static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE |
+        GraphicBuffer::USAGE_SW_WRITE_RARELY;
+static hwc_composer_device_t *hwcDevice;
+static EGLDisplay dpy;
+static EGLSurface surface;
+static EGLint width, height;
+
+// Functions prototypes
+void init(void);
+void printSyntax(const char *cmd);
+
+// Command-line option settings
+static bool verbose = defaultVerbose;
+static ColorFract startRefColor = defaultStartColor;
+static ColorFract endRefColor = defaultEndColor;
+static float endDelay = defaultEndDelay;
+static const struct hwcTestGraphicFormat *refFormat
+    = hwcTestGraphicFormatLookup(defaultRefFormat);
+static const struct hwcTestGraphicFormat *equivFormat;
+
+/*
+ * Main
+ *
+ * Performs the following high-level sequence of operations:
+ *
+ *   1. Command-line parsing
+ *
+ *   2. Stop framework
+ *
+ *   3. Initialization
+ *
+ *   4. Create Hardware Composer description of reference and equivalence frames
+ *
+ *   5. Have Hardware Composer render the reference and equivalence frames
+ *
+ *   6. Delay for amount of time given by endDelay
+ *
+ *   7. Start framework
+ */
+int
+main(int argc, char *argv[])
+{
+    int rv, opt;
+    bool error;
+    char *chptr;
+    unsigned int pass;
+    char cmd[MAXCMD];
+    string str;
+
+    testSetLogCatTag(LOG_TAG);
+
+    assert(refFormat != NULL);
+
+    // Parse command line arguments
+    while ((opt = getopt(argc, argv, "vs:e:r:D:?h")) != -1) {
+        switch (opt) {
+          case 'D': // End of test delay
+                    // Delay between completion of final pass and restart
+                    // of framework
+            endDelay = strtod(optarg, &chptr);
+            if ((*chptr != '\0') || (endDelay < 0.0)) {
+                testPrintE("Invalid command-line specified end of test delay "
+                           "of: %s", optarg);
+                exit(1);
+            }
+            break;
+
+          case 's': // Starting reference color
+            str = optarg;
+            while (optind < argc) {
+                if (*argv[optind] == '-') { break; }
+                char endChar = (str.length() > 1) ? str[str.length() - 1] : 0;
+                if ((endChar == '>') || (endChar == ']')) { break; }
+                str += " " + string(argv[optind++]);
+            }
+            {
+                istringstream in(str);
+                startRefColor = hwcTestParseColor(in, error);
+                // Any parse error or characters not used by parser
+                if (error
+                    || (((unsigned int) in.tellg() != in.str().length())
+                        && (in.tellg() != (streampos) -1))) {
+                    testPrintE("Invalid command-line specified start "
+                               "reference color of: %s", str.c_str());
+                    exit(2);
+                }
+            }
+            break;
+
+          case 'e': // Ending reference color
+            str = optarg;
+            while (optind < argc) {
+                if (*argv[optind] == '-') { break; }
+                char endChar = (str.length() > 1) ? str[str.length() - 1] : 0;
+                if ((endChar == '>') || (endChar == ']')) { break; }
+                str += " " + string(argv[optind++]);
+            }
+            {
+                istringstream in(str);
+                endRefColor = hwcTestParseColor(in, error);
+                // Any parse error or characters not used by parser
+                if (error
+                    || (((unsigned int) in.tellg() != in.str().length())
+                        && (in.tellg() != (streampos) -1))) {
+                    testPrintE("Invalid command-line specified end "
+                               "reference color of: %s", str.c_str());
+                    exit(3);
+                }
+            }
+            break;
+
+          case 'r': // Reference graphic format
+            refFormat = hwcTestGraphicFormatLookup(optarg);
+            if (refFormat == NULL) {
+                testPrintE("Unkown command-line specified reference graphic "
+                           "format of: %s", optarg);
+                printSyntax(basename(argv[0]));
+                exit(4);
+            }
+            break;
+
+          case 'v': // Verbose
+            verbose = true;
+            break;
+
+          case 'h': // Help
+          case '?':
+          default:
+            printSyntax(basename(argv[0]));
+            exit(((optopt == 0) || (optopt == '?')) ? 0 : 5);
+        }
+    }
+
+    // Expect a single positional parameter, which specifies the
+    // equivalence graphic format.
+    if (argc != (optind + 1)) {
+        testPrintE("Expected a single command-line postional parameter");
+        printSyntax(basename(argv[0]));
+        exit(6);
+    }
+    equivFormat = hwcTestGraphicFormatLookup(argv[optind]);
+    if (equivFormat == NULL) {
+        testPrintE("Unkown command-line specified equivalence graphic "
+                   "format of: %s", argv[optind]);
+        printSyntax(basename(argv[0]));
+        exit(7);
+    }
+
+    testPrintI("refFormat: %u %s", refFormat->format, refFormat->desc);
+    testPrintI("equivFormat: %u %s", equivFormat->format, equivFormat->desc);
+    testPrintI("startRefColor: %s", ((string) startRefColor).c_str());
+    testPrintI("endRefColor: %s", ((string) endRefColor).c_str());
+    testPrintI("endDelay: %f", endDelay);
+
+    // Stop framework
+    rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK);
+    if (rv >= (signed) sizeof(cmd) - 1) {
+        testPrintE("Command too long for: %s", CMD_STOP_FRAMEWORK);
+        exit(8);
+    }
+    testExecCmd(cmd);
+    testDelay(1.0); // TODO - needs means to query whether asynchronous stop
+                    // framework operation has completed.  For now, just wait
+                    // a long time.
+
+    init();
+
+    // Use the upper third of the display for the reference frame and
+    // the middle third for the equivalence frame.
+    unsigned int refHeight = height / 3;
+    unsigned int refPosY = 0; // Reference frame Y position
+    unsigned int refPosX = 0; // Reference frame X position
+    unsigned int refWidth = width - refPosX;
+    if ((refWidth & refFormat->wMod) != 0) {
+        refWidth += refFormat->wMod - (refWidth % refFormat->wMod);
+    }
+    unsigned int equivHeight = height / 3;
+    unsigned int equivPosY = refHeight; // Equivalence frame Y position
+    unsigned int equivPosX = 0;         // Equivalence frame X position
+    unsigned int equivWidth = width - equivPosX;
+    if ((equivWidth & equivFormat->wMod) != 0) {
+        equivWidth += equivFormat->wMod - (equivWidth % equivFormat->wMod);
+    }
+
+    // Create reference and equivalence graphic buffers
+    const unsigned int numFrames = 2;
+    sp<GraphicBuffer> refFrame;
+    refFrame = new GraphicBuffer(refWidth, refHeight,
+                                 refFormat->format, texUsage);
+    if ((rv = refFrame->initCheck()) != NO_ERROR) {
+        testPrintE("refFrame initCheck failed, rv: %i", rv);
+        testPrintE("  width %u height: %u format: %u %s", refWidth, refHeight,
+                   refFormat->format,
+                   hwcTestGraphicFormat2str(refFormat->format));
+        exit(9);
+    }
+    testPrintI("refFrame width: %u height: %u format: %u %s",
+               refWidth, refHeight, refFormat->format,
+               hwcTestGraphicFormat2str(refFormat->format));
+
+    sp<GraphicBuffer> equivFrame;
+    equivFrame = new GraphicBuffer(equivWidth, equivHeight,
+                                   equivFormat->format, texUsage);
+    if ((rv = refFrame->initCheck()) != NO_ERROR) {
+        testPrintE("refFrame initCheck failed, rv: %i", rv);
+        testPrintE("  width %u height: %u format: %u %s", refWidth, refHeight,
+                   refFormat->format,
+                   hwcTestGraphicFormat2str(refFormat->format));
+        exit(10);
+    }
+    testPrintI("equivFrame width: %u height: %u format: %u %s",
+               equivWidth, equivHeight, equivFormat->format,
+               hwcTestGraphicFormat2str(equivFormat->format));
+
+    // Fill the frames with a horizontal blend
+    hwcTestFillColorHBlend(refFrame.get(), refFormat->format,
+                           startRefColor, endRefColor);
+    hwcTestFillColorHBlend(equivFrame.get(), refFormat->format,
+                           startRefColor, endRefColor);
+
+    hwc_layer_list_t *list;
+    size_t size = sizeof(hwc_layer_list) + numFrames * sizeof(hwc_layer_t);
+    if ((list = (hwc_layer_list_t *) calloc(1, size)) == NULL) {
+        testPrintE("Allocate list failed");
+        exit(11);
+    }
+    list->flags = HWC_GEOMETRY_CHANGED;
+    list->numHwLayers = numFrames;
+
+    hwc_layer_t *layer = &list->hwLayers[0];
+    layer->handle = refFrame->handle;
+    layer->blending = HWC_BLENDING_NONE;
+    layer->sourceCrop.left = 0;
+    layer->sourceCrop.top = 0;
+    layer->sourceCrop.right = width;
+    layer->sourceCrop.bottom = refHeight;
+    layer->displayFrame.left = 0;
+    layer->displayFrame.top = 0;
+    layer->displayFrame.right = width;
+    layer->displayFrame.bottom = refHeight;
+    layer->visibleRegionScreen.numRects = 1;
+    layer->visibleRegionScreen.rects = &layer->displayFrame;
+
+    layer++;
+    layer->handle = equivFrame->handle;
+    layer->blending = HWC_BLENDING_NONE;
+    layer->sourceCrop.left = 0;
+    layer->sourceCrop.top = 0;
+    layer->sourceCrop.right = width;
+    layer->sourceCrop.bottom = equivHeight;
+    layer->displayFrame.left = 0;
+    layer->displayFrame.top = refHeight;
+    layer->displayFrame.right = width;
+    layer->displayFrame.bottom = layer->displayFrame.top + equivHeight;
+    layer->visibleRegionScreen.numRects = 1;
+    layer->visibleRegionScreen.rects = &layer->displayFrame;
+
+    // Perform prepare operation
+    if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(list); }
+    hwcDevice->prepare(hwcDevice, list);
+    if (verbose) {
+        testPrintI("Post Prepare:");
+        hwcTestDisplayListPrepareModifiable(list);
+    }
+
+    // Turn off the geometry changed flag
+    list->flags &= ~HWC_GEOMETRY_CHANGED;
+
+    if (verbose) {hwcTestDisplayListHandles(list); }
+    hwcDevice->set(hwcDevice, dpy, surface, list);
+
+    testDelay(endDelay);
+
+    // Start framework
+    rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK);
+    if (rv >= (signed) sizeof(cmd) - 1) {
+        testPrintE("Command too long for: %s", CMD_START_FRAMEWORK);
+        exit(12);
+    }
+    testExecCmd(cmd);
+
+    return 0;
+}
+
+void init(void)
+{
+    // Seed pseudo random number generator
+    // Seeding causes fill horizontal blend to fill the pad area with
+    // a deterministic set of values.
+    srand48(0);
+
+    hwcTestInitDisplay(verbose, &dpy, &surface, &width, &height);
+
+    hwcTestOpenHwc(&hwcDevice);
+}
+
+void printSyntax(const char *cmd)
+{
+    testPrintE("  %s [options] graphicFormat", cmd);
+    testPrintE("    options:");
+    testPrintE("      -s <0.##, 0.##, 0.##> - Starting reference color");
+    testPrintE("      -e <0.##, 0.##, 0.##> - Ending reference color");
+    testPrintE("      -r format - Reference graphic format");
+    testPrintE("      -D #.## - End of test delay");
+    testPrintE("      -v Verbose");
+    testPrintE("");
+    testPrintE("    graphic formats:");
+    for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) {
+        testPrintE("      %s", hwcTestGraphicFormat[n1].desc);
+    }
+}
diff --git a/opengl/tests/hwc/hwcRects.cpp b/opengl/tests/hwc/hwcRects.cpp
new file mode 100644
index 0000000..c93124e
--- /dev/null
+++ b/opengl/tests/hwc/hwcRects.cpp
@@ -0,0 +1,575 @@
+/*
+ * 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.
+ */
+
+/*
+ * Hardware Composer Rectangles
+ *
+ * Synopsis
+ *   hwcRects [options] (graphicFormat displayFrame [attributes],)...
+ *     options:
+ *       -D #.## - End of test delay
+ *       -v Verbose");
+ *
+ *      graphic formats:
+ *        RGBA8888 (reference frame default)
+ *        RGBX8888
+ *        RGB888
+ *        RGB565
+ *        BGRA8888
+ *        RGBA5551
+ *        RGBA4444
+ *        YV12
+ *
+ *      displayFrame
+ *        [left, top, right, bottom]
+ *
+ *      attributes:
+ *        transform: none | fliph | flipv | rot90 | rot180 | rot270
+ *        blend: none | premult | coverage
+ *        color: [0.##, 0.##, 0.##]
+ *        alpha: 0.##
+ *        sourceDim: [width, height]
+ *        sourceCrop: [left, top, right, bottom]
+ *
+ *      Example:
+ *        # White YV12 rectangle, with overlapping turquoise
+ *        #  RGBA8888 rectangle at 30%% (alpha: 0.7) transparency
+ *        hwcRects -v -D 30.0 \
+ *          YV12 [50, 80, 200, 300] transform: none \
+ *            color: [1.0, 0.5, 0.5], \
+ *          RGBA8888 [100, 150, 300, 400] blend: coverage \
+ *            color: [0.251, 0.878, 0.816] alpha: 0.7 \
+ *            sourceDim: [50, 60] sourceCrop: [5, 8, 12, 15]
+ *
+ * Description
+ *   Constructs a Hardware Composer (HWC) list of frames from
+ *   command-line specified parameters.  Then sends it to the HWC
+ *   be rendered.  The intended purpose of this tool is as a means to
+ *   reproduce and succinctly specify an observed HWC operation, with
+ *   no need to modify/compile a program.
+ *
+ *   The command-line syntax consists of a few standard command-line
+ *   options and then a description of one or more frames.  The frame
+ *   descriptions are separated from one another via a comma.  The
+ *   beginning of a frame description requires the specification
+ *   of the graphic format and then the display frame rectangle where
+ *   the frame will be displayed.  The display frame rectangle is
+ *   specified as follows, with the right and bottom coordinates being
+ *   exclusive values:
+ *
+ *     [left, top, right, bottom]
+ *    
+ *   After these two required parameters each frame description can
+ *   specify 1 or more optional attributes.  The name of each optional
+ *   attribute is preceded by a colon.  The current implementation
+ *   then requires white space after the colon and then the value of
+ *   the attribute is specified.  See the synopsis section above for
+ *   a list of attributes and the format of their expected value.
+ */
+
+#include <algorithm>
+#include <assert.h>
+#include <cerrno>
+#include <cmath>
+#include <cstdlib>
+#include <ctime>
+#include <istream>
+#include <libgen.h>
+#include <list>
+#include <sched.h>
+#include <sstream>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/EGLUtils.h>
+
+#define LOG_TAG "hwcColorEquivTest"
+#include <utils/Log.h>
+#include <testUtil.h>
+
+#include <hardware/hwcomposer.h>
+
+#include <glTestLib.h>
+#include <hwc/hwcTestLib.h>
+
+using namespace std;
+using namespace android;
+
+// Defaults
+const bool defaultVerbose = false;
+const float defaultEndDelay = 2.0; // Default delay after rendering graphics
+
+const uint32_t   defaultFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+const int32_t    defaultTransform = 0;
+const uint32_t   defaultBlend = HWC_BLENDING_NONE;
+const ColorFract defaultColor(0.5, 0.5, 0.5);
+const float      defaultAlpha = 1.0; // Opaque
+const HwcTestDim defaultSourceDim(1, 1);
+const struct hwc_rect defaultSourceCrop = {0, 0, 1, 1};
+const struct hwc_rect defaultDisplayFrame = {0, 0, 100, 100};
+
+// Defines
+#define MAXCMD               200
+#define CMD_STOP_FRAMEWORK   "stop 2>&1"
+#define CMD_START_FRAMEWORK  "start 2>&1"
+
+// Macros
+#define NUMA(a) (sizeof(a) / sizeof(a [0])) // Num elements in an array
+
+// Local types
+class Rectangle {
+public:
+    Rectangle() : format(defaultFormat), transform(defaultTransform),
+                  blend(defaultBlend), color(defaultColor),
+                  alpha(defaultAlpha), sourceDim(defaultSourceDim),
+                  sourceCrop(defaultSourceCrop),
+                  displayFrame(defaultDisplayFrame) {};
+
+    uint32_t     format;
+    uint32_t     transform;
+    int32_t      blend;
+    ColorFract   color;
+    float        alpha;
+    HwcTestDim   sourceDim;
+    struct hwc_rect   sourceCrop;
+    struct hwc_rect   displayFrame;
+
+    sp<GraphicBuffer> texture;
+};
+
+// Globals
+list<Rectangle> rectangle;
+static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE |
+        GraphicBuffer::USAGE_SW_WRITE_RARELY;
+static hwc_composer_device_t *hwcDevice;
+static EGLDisplay dpy;
+static EGLSurface surface;
+static EGLint width, height;
+
+// Function prototypes
+static Rectangle parseRect(string rectStr);
+void init(void);
+void printSyntax(const char *cmd);
+
+// Command-line option settings
+static bool verbose = defaultVerbose;
+static float endDelay = defaultEndDelay;
+
+/*
+ * Main
+ *
+ * Performs the following high-level sequence of operations:
+ *
+ *   1. Parse command-line options
+ *
+ *   2. Stop framework
+ *
+ *   3. Initialization
+ *
+ *   4. Parse frame descriptions
+ *
+ *   5. Create HWC list from frame descriptions
+ *
+ *   6. Have HWC render the list description of the frames
+ *
+ *   7. Delay for amount of time given by endDelay
+ *
+ *   8. Start framework
+ */
+int
+main(int argc, char *argv[])
+{
+    int     rv, opt;
+    char   *chptr;
+    bool    error;
+    string  str;
+    char cmd[MAXCMD];
+
+    // Parse command line arguments
+    while ((opt = getopt(argc, argv, "D:v?h")) != -1) {
+        switch (opt) {
+          case 'D': // End of test delay
+            endDelay = strtod(optarg, &chptr);
+            if ((*chptr != '\0') || (endDelay < 0.0)) {
+                testPrintE("Invalid command-line specified end of test delay "
+                           "of: %s", optarg);
+                exit(1);
+            }
+            break;
+
+          case 'v': // Verbose
+            verbose = true;
+            break;
+
+          case 'h': // Help
+          case '?':
+          default:
+            printSyntax(basename(argv[0]));
+            exit(((optopt == 0) || (optopt == '?')) ? 0 : 2);
+        }
+    }
+
+    // Stop framework
+    rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK);
+    if (rv >= (signed) sizeof(cmd) - 1) {
+        testPrintE("Command too long for: %s", CMD_STOP_FRAMEWORK);
+        exit(3);
+    }
+    testExecCmd(cmd);
+    testDelay(1.0); // TODO - needs means to query whether asyncronous stop
+                    // framework operation has completed.  For now, just wait
+                    // a long time.
+
+    init();
+
+    // Parse rectangle descriptions
+    int numOpen = 0; // Current number of unmatched <[
+    string rectDesc(""); // String description of a single rectangle
+    while (optind < argc) {
+        string argNext = string(argv[optind++]);
+
+        if (rectDesc.length()) { rectDesc += ' '; }
+        rectDesc += argNext;
+
+        // Count number of opening <[ and matching >]
+        // At this point not worried about an opening character being
+        // matched by it's corresponding closing character.  For example,
+        // "<1.0, 2.0]" is incorrect because the opening < should be matched
+        // with a closing >, instead of the closing ].  Such errors are
+        // detected when the actual value is parsed.
+        for (unsigned int n1 = 0; n1 < argNext.length(); n1++) {
+            switch(argNext[n1]) {
+              case '[':
+              case '<':
+                numOpen++;
+                break;
+
+              case ']':
+              case '>':
+                numOpen--;
+                break;
+            }
+
+            // Error anytime there is more closing then opening characters
+            if (numOpen < 0) {
+                testPrintI("Mismatched number of opening <[ with "
+                           "closing >] in: %s", rectDesc.c_str());
+                exit(4);
+            }
+        }
+
+        // Description of a rectangle is complete when all opening
+        // <[ are closed with >] and the string ends with a comma or
+        // there are no more args.
+        if ((numOpen == 0) && rectDesc.length()
+            && ((rectDesc[rectDesc.length() - 1] == ',')
+                || (optind == argc))) {
+            // Remove trailing comma if it is present
+            if (rectDesc[rectDesc.length() - 1] == ',') {
+                rectDesc.erase(rectDesc.length() - 1);
+            }
+
+            // Parse string description of rectangle
+            Rectangle rect = parseRect(rectDesc);
+
+            // Add to the list of rectangles
+            rectangle.push_back(rect);
+
+            // Prepare for description of another rectangle
+            rectDesc = string("");
+        }
+    }
+
+    // Create list of frames
+    hwc_layer_list_t *list;
+    list = hwcTestCreateLayerList(rectangle.size());
+    if (list == NULL) {
+        testPrintE("hwcTestCreateLayerList failed");
+        exit(5);
+    }
+
+    hwc_layer_t *layer = &list->hwLayers[0];
+    for (std::list<Rectangle>::iterator it = rectangle.begin();
+         it != rectangle.end(); ++it, ++layer) {
+        layer->handle = it->texture->handle;
+        layer->blending = it->blend;
+        layer->transform = it->transform;
+        layer->sourceCrop = it->sourceCrop;
+        layer->displayFrame = it->displayFrame;
+
+        layer->visibleRegionScreen.numRects = 1;
+        layer->visibleRegionScreen.rects = &layer->displayFrame;
+    }
+
+    // Perform prepare operation
+    if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(list); }
+    hwcDevice->prepare(hwcDevice, list);
+    if (verbose) {
+        testPrintI("Post Prepare:");
+        hwcTestDisplayListPrepareModifiable(list);
+    }
+
+    // Turn off the geometry changed flag
+    list->flags &= ~HWC_GEOMETRY_CHANGED;
+
+    // Perform the set operation(s)
+    if (verbose) {testPrintI("Set:"); }
+    if (verbose) { hwcTestDisplayListHandles(list); }
+    hwcDevice->set(hwcDevice, dpy, surface, list);
+
+    testDelay(endDelay);
+
+    // Start framework
+    rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK);
+    if (rv >= (signed) sizeof(cmd) - 1) {
+        testPrintE("Command too long for: %s", CMD_START_FRAMEWORK);
+        exit(6);
+    }
+    testExecCmd(cmd);
+
+    return 0;
+}
+
+// Parse string description of rectangle and add it to list of rectangles
+// to be rendered.
+static Rectangle parseRect(string rectStr)
+{
+    int rv;
+    string str;
+    bool   error;
+    istringstream in(rectStr);
+    const struct hwcTestGraphicFormat *format;
+    Rectangle rect;
+    struct hwc_rect hwcRect;
+
+    // Graphic Format
+    in >> str;
+    if (!in) {
+        testPrintE("Error parsing format from: %s", rectStr.c_str());
+        exit(20);
+    }
+    format = hwcTestGraphicFormatLookup(str.c_str());
+    if (format == NULL) {
+        testPrintE("Unknown graphic format in: %s", rectStr.c_str());
+        exit(21);
+    }
+    rect.format = format->format;
+
+    // Display Frame
+    rect.displayFrame = hwcTestParseHwcRect(in, error);
+    if (error) {
+        testPrintE("Invalid display frame in: %s", rectStr.c_str());
+        exit(22);
+    }
+
+    // Set default sourceDim and sourceCrop based on size of display frame.
+    // Default is source size equal to the size of the display frame, with
+    // the source crop being the entire size of the source frame.
+    rect.sourceDim = HwcTestDim(rect.displayFrame.right
+                                     - rect.displayFrame.left,
+                                 rect.displayFrame.bottom
+                                     - rect.displayFrame.top);
+    rect.sourceCrop.left = 0;
+    rect.sourceCrop.top = 0;
+    rect.sourceCrop.right = rect.sourceDim.width();
+    rect.sourceCrop.bottom = rect.sourceDim.height();
+
+    // Optional settings
+    while ((in.tellg() < (streampos) in.str().length())
+           && (in.tellg() != (streampos) -1)) {
+        string attrName;
+
+        in >> attrName;
+        if (in.eof()) { break; }
+        if (!in) {
+            testPrintE("Error reading attribute name in: %s",
+                       rectStr.c_str());
+            exit(23);
+        }
+
+        // Transform
+        if (attrName == "transform:") { // Transform
+            string str;
+
+            in >> str;
+            if (str == "none") {
+                rect.transform = 0;
+            } else if (str == "fliph") {
+                rect.transform = HWC_TRANSFORM_FLIP_H;
+            } else if (str == "flipv") {
+                rect.transform = HWC_TRANSFORM_FLIP_V;
+            } else if (str == "rot90") {
+                rect.transform = HWC_TRANSFORM_ROT_90;
+            } else if (str == "rot180") {
+                rect.transform = HWC_TRANSFORM_ROT_180;
+            } else if (str == "rot270") {
+                rect.transform = HWC_TRANSFORM_ROT_270;
+            } else {
+                testPrintE("Unknown transform of \"%s\" in: %s", str.c_str(),
+                           rectStr.c_str());
+                exit(24);
+            }
+        } else if (attrName == "blend:") { // Blend
+            string str;
+
+            in >> str;
+            if (str == string("none")) {
+                rect.blend = HWC_BLENDING_NONE;
+            } else if (str == "premult") {
+                rect.blend = HWC_BLENDING_PREMULT;
+            } else if (str == "coverage") {
+                rect.blend = HWC_BLENDING_COVERAGE;
+            } else {
+                testPrintE("Unknown blend of \"%s\" in: %s", str.c_str(),
+                           rectStr.c_str());
+                exit(25);
+            }
+        } else if (attrName == "color:") { // Color
+            rect.color = hwcTestParseColor(in, error);
+            if (error) {
+                testPrintE("Error parsing color in: %s", rectStr.c_str());
+                exit(26);
+            }
+        } else if (attrName == "alpha:") { // Alpha
+            in >> rect.alpha;
+            if (!in) {
+                testPrintE("Error parsing value for alpha attribute in: %s",
+                           rectStr.c_str());
+                exit(27);
+            }
+        } else if (attrName == "sourceDim:") { // Source Dimension
+           rect.sourceDim = hwcTestParseDim(in, error);
+            if (error) {
+                testPrintE("Error parsing source dimenision in: %s",
+                           rectStr.c_str());
+                exit(28);
+            }
+        } else if (attrName == "sourceCrop:") { // Source Crop
+            rect.sourceCrop = hwcTestParseHwcRect(in, error);
+            if (error) {
+                testPrintE("Error parsing source crop in: %s",
+                           rectStr.c_str());
+                exit(29);
+            }
+        } else { // Unknown attribute
+            testPrintE("Unknown attribute of \"%s\" in: %s", attrName.c_str(),
+                       rectStr.c_str());
+            exit(30);
+        }
+    }
+
+    // Validate
+    if (((uint32_t) rect.sourceCrop.left >= rect.sourceDim.width())
+        || ((uint32_t) rect.sourceCrop.right > rect.sourceDim.width())
+        || ((uint32_t) rect.sourceCrop.top >= rect.sourceDim.height())
+        || ((uint32_t) rect.sourceCrop.bottom > rect.sourceDim.height())) {
+        testPrintE("Invalid source crop in: %s", rectStr.c_str());
+        exit(31);
+    }
+    if ((rect.displayFrame.left >= width)
+        || (rect.displayFrame.right > width)
+        || (rect.displayFrame.top >= height)
+        || (rect.displayFrame.bottom > height)) {
+        testPrintE("Invalid display frame in: %s", rectStr.c_str());
+        exit(32);
+    }
+    if ((rect.alpha < 0.0) || (rect.alpha > 1.0)) {
+        testPrintE("Invalid alpha in: %s", rectStr.c_str());
+        exit(33);
+    }
+
+    // Create source texture
+    rect.texture = new GraphicBuffer(rect.sourceDim.width(),
+                                     rect.sourceDim.height(),
+                                     rect.format, texUsage);
+    if ((rv = rect.texture->initCheck()) != NO_ERROR) {
+        testPrintE("source texture initCheck failed, rv: %i", rv);
+        testPrintE("  %s", rectStr.c_str());
+
+    }
+
+    // Fill with uniform color
+    hwcTestFillColor(rect.texture.get(), rect.color, rect.alpha);
+    if (verbose) {
+        testPrintI("    buf: %p handle: %p format: %s width: %u height: %u "
+                   "color: %s alpha: %f",
+                   rect.texture.get(), rect.texture->handle, format->desc,
+                   rect.sourceDim.width(), rect.sourceDim.height(),
+                   string(rect.color).c_str(), rect.alpha);
+    }
+
+    return rect;
+}
+
+void init(void)
+{
+    // Seed pseudo random number generator
+    // Needed so that the pad areas of frames are filled with a deterministic
+    // pseudo random value.
+    srand48(0);
+
+    hwcTestInitDisplay(verbose, &dpy, &surface, &width, &height);
+
+    hwcTestOpenHwc(&hwcDevice);
+}
+
+void printSyntax(const char *cmd)
+{
+    testPrintE("  %s [options] (graphicFormat displayFrame [attributes],)...",
+               cmd);
+    testPrintE("    options:");
+    testPrintE("      -D End of test delay");
+    testPrintE("      -v Verbose");
+    testPrintE("");
+    testPrintE("    graphic formats:");
+    for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) {
+        testPrintE("      %s", hwcTestGraphicFormat[n1].desc);
+    }
+    testPrintE("");
+    testPrintE("    displayFrame");
+    testPrintE("      [left, top, right, bottom]");
+    testPrintE("");
+    testPrintE("    attributes:");
+    testPrintE("      transform: none | fliph | flipv | rot90 | rot180 "
+               " | rot270");
+    testPrintE("      blend: none | premult | coverage");
+    testPrintE("      color: [0.##, 0.##, 0.##]");
+    testPrintE("      alpha: 0.##");
+    testPrintE("      sourceDim: [width, height]");
+    testPrintE("      sourceCrop: [left, top, right, bottom]");
+    testPrintE("");
+    testPrintE("    Example:");
+    testPrintE("      # White YV12 rectangle, with overlapping turquoise ");
+    testPrintE("      #  RGBA8888 rectangle at 30%% (alpha: 0.7) transparency");
+    testPrintE("      %s -v -D 30.0 \\", cmd);
+    testPrintE("        YV12 [50, 80, 200, 300] transform: none \\");
+    testPrintE("          color: [1.0, 0.5, 0.5], \\");
+    testPrintE("        RGBA8888 [100, 150, 300, 400] blend: coverage \\");
+    testPrintE("          color: [0.251, 0.878, 0.816] alpha: 0.7 \\");
+    testPrintE("          sourceDim: [50, 60] sourceCrop: [5, 8, 12, 15]");
+}
diff --git a/opengl/tests/hwc/hwcStress.cpp b/opengl/tests/hwc/hwcStress.cpp
new file mode 100644
index 0000000..1cefb4b
--- /dev/null
+++ b/opengl/tests/hwc/hwcStress.cpp
@@ -0,0 +1,645 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*
+ * Hardware Composer stress test
+ *
+ * Performs a pseudo-random (prandom) sequence of operations to the
+ * Hardware Composer (HWC), for a specified number of passes or for
+ * a specified period of time.  By default the period of time is FLT_MAX,
+ * so that the number of passes will take precedence.
+ *
+ * The passes are grouped together, where (pass / passesPerGroup) specifies
+ * which group a particular pass is in.  This causes every passesPerGroup
+ * worth of sequential passes to be within the same group.  Computationally
+ * intensive operations are performed just once at the beginning of a group
+ * of passes and then used by all the passes in that group.  This is done
+ * so as to increase both the average and peak rate of graphic operations,
+ * by moving computationally intensive operations to the beginning of a group.
+ * In particular, at the start of each group of passes a set of
+ * graphic buffers are created, then used by the first and remaining
+ * passes of that group of passes.
+ *
+ * The per-group initialization of the graphic buffers is performed
+ * by a function called initFrames.  This function creates an array
+ * of smart pointers to the graphic buffers, in the form of a vector
+ * of vectors.  The array is accessed in row major order, so each
+ * row is a vector of smart pointers.  All the pointers of a single
+ * row point to graphic buffers which use the same pixel format and
+ * have the same dimension, although it is likely that each one is
+ * filled with a different color.  This is done so that after doing
+ * the first HWC prepare then set call, subsequent set calls can
+ * be made with each of the layer handles changed to a different
+ * graphic buffer within the same row.  Since the graphic buffers
+ * in a particular row have the same pixel format and dimension,
+ * additional HWC set calls can be made, without having to perform
+ * an HWC prepare call.
+ *
+ * This test supports the following command-line options:
+ *
+ *   -v        Verbose
+ *   -s num    Starting pass
+ *   -e num    Ending pass
+ *   -p num    Execute the single pass specified by num
+ *   -n num    Number of set operations to perform after each prepare operation
+ *   -t float  Maximum time in seconds to execute the test
+ *   -d float  Delay in seconds performed after each set operation
+ *   -D float  Delay in seconds performed after the last pass is executed
+ *
+ * Typically the test is executed for a large range of passes.  By default
+ * passes 0 through 99999 (100,000 passes) are executed.  Although this test
+ * does not validate the generated image, at times it is useful to reexecute
+ * a particular pass and leave the displayed image on the screen for an
+ * extended period of time.  This can be done either by setting the -s
+ * and -e options to the desired pass, along with a large value for -D.
+ * This can also be done via the -p option, again with a large value for
+ * the -D options.
+ *
+ * So far this test only contains code to create graphic buffers with
+ * a continuous solid color.  Although this test is unable to validate the
+ * image produced, any image that contains other than rectangles of a solid
+ * color are incorrect.  Note that the rectangles may use a transparent
+ * color and have a blending operation that causes the color in overlapping
+ * rectangles to be mixed.  In such cases the overlapping portions may have
+ * a different color from the rest of the rectangle.
+ */
+
+#include <algorithm>
+#include <assert.h>
+#include <cerrno>
+#include <cmath>
+#include <cstdlib>
+#include <ctime>
+#include <libgen.h>
+#include <sched.h>
+#include <sstream>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <vector>
+
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/EGLUtils.h>
+
+#define LOG_TAG "hwcStressTest"
+#include <utils/Log.h>
+#include <testUtil.h>
+
+#include <hardware/hwcomposer.h>
+
+#include <glTestLib.h>
+#include <hwc/hwcTestLib.h>
+
+using namespace std;
+using namespace android;
+
+const float maxSizeRatio = 1.3;  // Graphic buffers can be upto this munch
+                                 // larger than the default screen size
+const unsigned int passesPerGroup = 10; // A group of passes all use the same
+                                        // graphic buffers
+
+// Ratios at which rare and frequent conditions should be produced
+const float rareRatio = 0.1;
+const float freqRatio = 0.9;
+
+// Defaults for command-line options
+const bool defaultVerbose = false;
+const unsigned int defaultStartPass = 0;
+const unsigned int defaultEndPass = 99999;
+const unsigned int defaultPerPassNumSet = 10;
+const float defaultPerSetDelay = 0.0; // Default delay after each set
+                                      // operation.  Default delay of
+                                      // zero used so as to perform the
+                                      // the set operations as quickly
+                                      // as possible.
+const float defaultEndDelay = 2.0; // Default delay between completion of
+                                   // final pass and restart of framework
+const float defaultDuration = FLT_MAX; // A fairly long time, so that
+                                       // range of passes will have
+                                       // precedence
+
+// Command-line option settings
+static bool verbose = defaultVerbose;
+static unsigned int startPass = defaultStartPass;
+static unsigned int endPass = defaultEndPass;
+static unsigned int numSet = defaultPerPassNumSet;
+static float perSetDelay = defaultPerSetDelay;
+static float endDelay = defaultEndDelay;
+static float duration = defaultDuration;
+
+// Command-line mutual exclusion detection flags.
+// Corresponding flag set true once an option is used.
+bool eFlag, sFlag, pFlag;
+
+#define MAXSTR               100
+#define MAXCMD               200
+#define BITSPERBYTE            8 // TODO: Obtain from <values.h>, once
+                                 // it has been added
+
+#define CMD_STOP_FRAMEWORK   "stop 2>&1"
+#define CMD_START_FRAMEWORK  "start 2>&1"
+
+#define NUMA(a) (sizeof(a) / sizeof(a [0]))
+#define MEMCLR(addr, size) do { \
+        memset((addr), 0, (size)); \
+    } while (0)
+
+// File scope constants
+const unsigned int blendingOps[] = {
+    HWC_BLENDING_NONE,
+    HWC_BLENDING_PREMULT,
+    HWC_BLENDING_COVERAGE,
+};
+const unsigned int layerFlags[] = {
+    HWC_SKIP_LAYER,
+};
+const vector<unsigned int> vecLayerFlags(layerFlags,
+    layerFlags + NUMA(layerFlags));
+
+const unsigned int transformFlags[] = {
+    HWC_TRANSFORM_FLIP_H,
+    HWC_TRANSFORM_FLIP_V,
+    HWC_TRANSFORM_ROT_90,
+    // ROT_180 & ROT_270 intentionally not listed, because they
+    // they are formed from combinations of the flags already listed.
+};
+const vector<unsigned int> vecTransformFlags(transformFlags,
+    transformFlags + NUMA(transformFlags));
+
+// File scope globals
+static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE |
+        GraphicBuffer::USAGE_SW_WRITE_RARELY;
+static hwc_composer_device_t *hwcDevice;
+static EGLDisplay dpy;
+static EGLSurface surface;
+static EGLint width, height;
+static vector <vector <sp<GraphicBuffer> > > frames;
+
+// File scope prototypes
+void init(void);
+void initFrames(unsigned int seed);
+template <class T> vector<T> vectorRandSelect(const vector<T>& vec, size_t num);
+template <class T> T vectorOr(const vector<T>& vec);
+
+/*
+ * Main
+ *
+ * Performs the following high-level sequence of operations:
+ *
+ *   1. Command-line parsing
+ *
+ *   2. Initialization
+ *
+ *   3. For each pass:
+ *
+ *        a. If pass is first pass or in a different group from the
+ *           previous pass, initialize the array of graphic buffers.
+ *
+ *        b. Create a HWC list with room to specify a prandomly
+ *           selected number of layers.
+ *
+ *        c. Select a subset of the rows from the graphic buffer array,
+ *           such that there is a unique row to be used for each
+ *           of the layers in the HWC list.
+ *
+ *        d. Prandomly fill in the HWC list with handles
+ *           selected from any of the columns of the selected row.
+ *
+ *        e. Pass the populated list to the HWC prepare call.
+ *
+ *        f. Pass the populated list to the HWC set call.
+ *
+ *        g. If additional set calls are to be made, then for each
+ *           additional set call, select a new set of handles and
+ *           perform the set call.
+ */
+int
+main(int argc, char *argv[])
+{
+    int rv, opt;
+    char *chptr;
+    unsigned int pass;
+    char cmd[MAXCMD];
+    struct timeval startTime, currentTime, delta;
+
+    testSetLogCatTag(LOG_TAG);
+
+    // Parse command line arguments
+    while ((opt = getopt(argc, argv, "vp:d:D:n:s:e:t:?h")) != -1) {
+        switch (opt) {
+          case 'd': // Delay after each set operation
+            perSetDelay = strtod(optarg, &chptr);
+            if ((*chptr != '\0') || (perSetDelay < 0.0)) {
+                testPrintE("Invalid command-line specified per pass delay of: "
+                           "%s", optarg);
+                exit(1);
+            }
+            break;
+
+          case 'D': // End of test delay
+                    // Delay between completion of final pass and restart
+                    // of framework
+            endDelay = strtod(optarg, &chptr);
+            if ((*chptr != '\0') || (endDelay < 0.0)) {
+                testPrintE("Invalid command-line specified end of test delay "
+                           "of: %s", optarg);
+                exit(2);
+            }
+            break;
+
+          case 't': // Duration
+            duration = strtod(optarg, &chptr);
+            if ((*chptr != '\0') || (duration < 0.0)) {
+                testPrintE("Invalid command-line specified duration of: %s",
+                           optarg);
+                exit(3);
+            }
+            break;
+
+          case 'n': // Num set operations per pass
+            numSet = strtoul(optarg, &chptr, 10);
+            if (*chptr != '\0') {
+                testPrintE("Invalid command-line specified num set per pass "
+                           "of: %s", optarg);
+                exit(4);
+            }
+            break;
+
+          case 's': // Starting Pass
+            sFlag = true;
+            if (pFlag) {
+                testPrintE("Invalid combination of command-line options.");
+                testPrintE("  The -p option is mutually exclusive from the");
+                testPrintE("  -s and -e options.");
+                exit(5);
+            }
+            startPass = strtoul(optarg, &chptr, 10);
+            if (*chptr != '\0') {
+                testPrintE("Invalid command-line specified starting pass "
+                           "of: %s", optarg);
+                exit(6);
+            }
+            break;
+
+          case 'e': // Ending Pass
+            eFlag = true;
+            if (pFlag) {
+                testPrintE("Invalid combination of command-line options.");
+                testPrintE("  The -p option is mutually exclusive from the");
+                testPrintE("  -s and -e options.");
+                exit(7);
+            }
+            endPass = strtoul(optarg, &chptr, 10);
+            if (*chptr != '\0') {
+                testPrintE("Invalid command-line specified ending pass "
+                           "of: %s", optarg);
+                exit(8);
+            }
+            break;
+
+          case 'p': // Run a single specified pass
+            pFlag = true;
+            if (sFlag || eFlag) {
+                testPrintE("Invalid combination of command-line options.");
+                testPrintE("  The -p option is mutually exclusive from the");
+                testPrintE("  -s and -e options.");
+                exit(9);
+            }
+            startPass = endPass = strtoul(optarg, &chptr, 10);
+            if (*chptr != '\0') {
+                testPrintE("Invalid command-line specified pass of: %s",
+                           optarg);
+                exit(10);
+            }
+            break;
+
+          case 'v': // Verbose
+            verbose = true;
+            break;
+
+          case 'h': // Help
+          case '?':
+          default:
+            testPrintE("  %s [options]", basename(argv[0]));
+            testPrintE("    options:");
+            testPrintE("      -p Execute specified pass");
+            testPrintE("      -s Starting pass");
+            testPrintE("      -e Ending pass");
+            testPrintE("      -t Duration");
+            testPrintE("      -d Delay after each set operation");
+            testPrintE("      -D End of test delay");
+            testPrintE("      -n Num set operations per pass");
+            testPrintE("      -v Verbose");
+            exit(((optopt == 0) || (optopt == '?')) ? 0 : 11);
+        }
+    }
+    if (endPass < startPass) {
+        testPrintE("Unexpected ending pass before starting pass");
+        testPrintE("  startPass: %u endPass: %u", startPass, endPass);
+        exit(12);
+    }
+    if (argc != optind) {
+        testPrintE("Unexpected command-line postional argument");
+        testPrintE("  %s [-s start_pass] [-e end_pass] [-t duration]",
+            basename(argv[0]));
+        exit(13);
+    }
+    testPrintI("duration: %g", duration);
+    testPrintI("startPass: %u", startPass);
+    testPrintI("endPass: %u", endPass);
+    testPrintI("numSet: %u", numSet);
+
+    // Stop framework
+    rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK);
+    if (rv >= (signed) sizeof(cmd) - 1) {
+        testPrintE("Command too long for: %s", CMD_STOP_FRAMEWORK);
+        exit(14);
+    }
+    testExecCmd(cmd);
+    testDelay(1.0); // TODO - need means to query whether asyncronous stop
+                    // framework operation has completed.  For now, just wait
+                    // a long time.
+
+    init();
+
+    // For each pass
+    gettimeofday(&startTime, NULL);
+    for (pass = startPass; pass <= endPass; pass++) {
+        // Stop if duration of work has already been performed
+        gettimeofday(&currentTime, NULL);
+        delta = tvDelta(&startTime, &currentTime);
+        if (tv2double(&delta) > duration) { break; }
+
+        // Regenerate a new set of test frames when this pass is
+        // either the first pass or is in a different group then
+        // the previous pass.  A group of passes are passes that
+        // all have the same quotient when their pass number is
+        // divided by passesPerGroup.
+        if ((pass == startPass)
+            || ((pass / passesPerGroup) != ((pass - 1) / passesPerGroup))) {
+            initFrames(pass / passesPerGroup);
+        }
+
+        testPrintI("==== Starting pass: %u", pass);
+
+        // Cause deterministic sequence of prandom numbers to be
+        // generated for this pass.
+        srand48(pass);
+
+        hwc_layer_list_t *list;
+        list = hwcTestCreateLayerList(testRandMod(frames.size()) + 1);
+        if (list == NULL) {
+            testPrintE("hwcTestCreateLayerList failed");
+            exit(20);
+        }
+
+        // Prandomly select a subset of frames to be used by this pass.
+        vector <vector <sp<GraphicBuffer> > > selectedFrames;
+        selectedFrames = vectorRandSelect(frames, list->numHwLayers);
+
+        // Any transform tends to create a layer that the hardware
+        // composer is unable to support and thus has to leave for
+        // SurfaceFlinger.  Place heavy bias on specifying no transforms.
+        bool noTransform = testRandFract() > rareRatio;
+
+        for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) {
+            unsigned int idx = testRandMod(selectedFrames[n1].size());
+            sp<GraphicBuffer> gBuf = selectedFrames[n1][idx];
+            hwc_layer_t *layer = &list->hwLayers[n1];
+            layer->handle = gBuf->handle;
+
+            layer->blending = blendingOps[testRandMod(NUMA(blendingOps))];
+            layer->flags = (testRandFract() > rareRatio) ? 0
+                : vectorOr(vectorRandSelect(vecLayerFlags,
+                           testRandMod(vecLayerFlags.size() + 1)));
+            layer->transform = (noTransform || testRandFract() > rareRatio) ? 0
+                : vectorOr(vectorRandSelect(vecTransformFlags,
+                           testRandMod(vecTransformFlags.size() + 1)));
+            layer->sourceCrop.left = testRandMod(gBuf->getWidth());
+            layer->sourceCrop.top = testRandMod(gBuf->getHeight());
+            layer->sourceCrop.right = layer->sourceCrop.left
+                + testRandMod(gBuf->getWidth() - layer->sourceCrop.left) + 1;
+            layer->sourceCrop.bottom = layer->sourceCrop.top
+                + testRandMod(gBuf->getHeight() - layer->sourceCrop.top) + 1;
+            layer->displayFrame.left = testRandMod(width);
+            layer->displayFrame.top = testRandMod(height);
+            layer->displayFrame.right = layer->displayFrame.left
+                + testRandMod(width - layer->displayFrame.left) + 1;
+            layer->displayFrame.bottom = layer->displayFrame.top
+                + testRandMod(height - layer->displayFrame.top) + 1;
+
+            // Increase the frequency that a scale factor of 1.0 from
+            // the sourceCrop to displayFrame occurs.  This is the
+            // most common scale factor used by applications and would
+            // be rarely produced by this stress test without this
+            // logic.
+            if (testRandFract() <= freqRatio) {
+                // Only change to scale factor to 1.0 if both the
+                // width and height will fit.
+                int sourceWidth = layer->sourceCrop.right
+                                  - layer->sourceCrop.left;
+                int sourceHeight = layer->sourceCrop.bottom
+                                   - layer->sourceCrop.top;
+                if (((layer->displayFrame.left + sourceWidth) <= width)
+                    && ((layer->displayFrame.top + sourceHeight) <= height)) {
+                    layer->displayFrame.right = layer->displayFrame.left
+                                                + sourceWidth;
+                    layer->displayFrame.bottom = layer->displayFrame.top
+                                                 + sourceHeight;
+                }
+            }
+
+            layer->visibleRegionScreen.numRects = 1;
+            layer->visibleRegionScreen.rects = &layer->displayFrame;
+        }
+
+        // Perform prepare operation
+        if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(list); }
+        hwcDevice->prepare(hwcDevice, list);
+        if (verbose) {
+            testPrintI("Post Prepare:");
+            hwcTestDisplayListPrepareModifiable(list);
+        }
+
+        // Turn off the geometry changed flag
+        list->flags &= ~HWC_GEOMETRY_CHANGED;
+
+        // Perform the set operation(s)
+        if (verbose) {testPrintI("Set:"); }
+        for (unsigned int n1 = 0; n1 < numSet; n1++) {
+            if (verbose) { hwcTestDisplayListHandles(list); }
+            hwcDevice->set(hwcDevice, dpy, surface, list);
+
+            // Prandomly select a new set of handles
+            for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) {
+                unsigned int idx = testRandMod(selectedFrames[n1].size());
+                sp<GraphicBuffer> gBuf = selectedFrames[n1][idx];
+                hwc_layer_t *layer = &list->hwLayers[n1];
+                layer->handle = (native_handle_t *) gBuf->handle;
+            }
+
+            testDelay(perSetDelay);
+        }
+
+        hwcTestFreeLayerList(list);
+        testPrintI("==== Completed pass: %u", pass);
+    }
+
+    testDelay(endDelay);
+
+    // Start framework
+    rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK);
+    if (rv >= (signed) sizeof(cmd) - 1) {
+        testPrintE("Command too long for: %s", CMD_START_FRAMEWORK);
+        exit(21);
+    }
+    testExecCmd(cmd);
+
+    testPrintI("Successfully completed %u passes", pass - startPass);
+
+    return 0;
+}
+
+void init(void)
+{
+    srand48(0); // Defensively set pseudo random number generator.
+                // Should not need to set this, because a stress test
+                // sets the seed on each pass.  Defensively set it here
+                // so that future code that uses pseudo random numbers
+                // before the first pass will be deterministic.
+
+    hwcTestInitDisplay(verbose, &dpy, &surface, &width, &height);
+
+    hwcTestOpenHwc(&hwcDevice);
+}
+
+/*
+ * Initialize Frames
+ *
+ * Creates an array of graphic buffers, within the global variable
+ * named frames.  The graphic buffers are contained within a vector of
+ * vectors.  All the graphic buffers in a particular row are of the same
+ * format and dimension.  Each graphic buffer is uniformly filled with a
+ * prandomly selected color.  It is likely that each buffer, even
+ * in the same row, will be filled with a unique color.
+ */
+void initFrames(unsigned int seed)
+{
+    int rv;
+    const size_t maxRows = 5;
+    const size_t minCols = 2;  // Need at least double buffering
+    const size_t maxCols = 4;  // One more than triple buffering
+
+    if (verbose) { testPrintI("initFrames seed: %u", seed); }
+    srand48(seed);
+    size_t rows = testRandMod(maxRows) + 1;
+
+    frames.clear();
+    frames.resize(rows);
+
+    for (unsigned int row = 0; row < rows; row++) {
+        // All frames within a row have to have the same format and
+        // dimensions.  Width and height need to be >= 1.
+        unsigned int formatIdx = testRandMod(NUMA(hwcTestGraphicFormat));
+        const struct hwcTestGraphicFormat *formatPtr
+            = &hwcTestGraphicFormat[formatIdx];
+        int format = formatPtr->format;
+
+        // Pick width and height, which must be >= 1 and the size
+        // mod the wMod/hMod value must be equal to 0.
+        size_t w = (width * maxSizeRatio) * testRandFract();
+        size_t h = (height * maxSizeRatio) * testRandFract();
+        w = max(1u, w);
+        h = max(1u, h);
+        if ((w % formatPtr->wMod) != 0) {
+            w += formatPtr->wMod - (w % formatPtr->wMod);
+        }
+        if ((h % formatPtr->hMod) != 0) {
+            h += formatPtr->hMod - (h % formatPtr->hMod);
+        }
+        if (verbose) {
+            testPrintI("  frame %u width: %u height: %u format: %u %s",
+                       row, w, h, format, hwcTestGraphicFormat2str(format));
+        }
+
+        size_t cols = testRandMod((maxCols + 1) - minCols) + minCols;
+        frames[row].resize(cols);
+        for (unsigned int col = 0; col < cols; col++) {
+            ColorFract color(testRandFract(), testRandFract(), testRandFract());
+            float alpha = testRandFract();
+
+            frames[row][col] = new GraphicBuffer(w, h, format, texUsage);
+            if ((rv = frames[row][col]->initCheck()) != NO_ERROR) {
+                testPrintE("GraphicBuffer initCheck failed, rv: %i", rv);
+                testPrintE("  frame %u width: %u height: %u format: %u %s",
+                           row, w, h, format, hwcTestGraphicFormat2str(format));
+                exit(80);
+            }
+
+            hwcTestFillColor(frames[row][col].get(), color, alpha);
+            if (verbose) {
+                testPrintI("    buf: %p handle: %p color: %s alpha: %f",
+                           frames[row][col].get(), frames[row][col]->handle,
+                           string(color).c_str(), alpha);
+            }
+        }
+    }
+}
+
+/*
+ * Vector Random Select
+ *
+ * Prandomly selects and returns num elements from vec.
+ */
+template <class T>
+vector<T> vectorRandSelect(const vector<T>& vec, size_t num)
+{
+    vector<T> rv = vec;
+
+    while (rv.size() > num) {
+        rv.erase(rv.begin() + testRandMod(rv.size()));
+    }
+
+    return rv;
+}
+
+/*
+ * Vector Or
+ *
+ * Or's togethen the values of each element of vec and returns the result.
+ */
+template <class T>
+T vectorOr(const vector<T>& vec)
+{
+    T rv = 0;
+
+    for (size_t n1 = 0; n1 < vec.size(); n1++) {
+        rv |= vec[n1];
+    }
+
+    return rv;
+}
diff --git a/opengl/tests/hwc/hwcTestLib.cpp b/opengl/tests/hwc/hwcTestLib.cpp
new file mode 100644
index 0000000..575af89
--- /dev/null
+++ b/opengl/tests/hwc/hwcTestLib.cpp
@@ -0,0 +1,995 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ * Hardware Composer Test Library
+ * Utility library functions for use by the Hardware Composer test cases
+ */
+
+#include <sstream>
+#include <string>
+
+#include <arpa/inet.h> // For ntohl() and htonl()
+
+#include <hwc/hwcTestLib.h>
+
+// Defines
+#define NUMA(a) (sizeof(a) / sizeof(a [0]))
+
+// Function Prototypes
+static void printGLString(const char *name, GLenum s);
+static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE);
+static void checkGlError(const char* op);
+static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config);
+
+using namespace std;
+using namespace android;
+
+
+#define BITSPERBYTE            8 // TODO: Obtain from <values.h>, once
+                                 // it has been added
+
+// Initialize Display
+void hwcTestInitDisplay(bool verbose, EGLDisplay *dpy, EGLSurface *surface,
+    EGLint *width, EGLint *height)
+{
+    static EGLContext context;
+
+    int rv;
+
+    EGLBoolean returnValue;
+    EGLConfig myConfig = {0};
+    EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+    EGLint sConfigAttribs[] = {
+        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+        EGL_NONE };
+    EGLint majorVersion, minorVersion;
+
+    checkEglError("<init>");
+    *dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    checkEglError("eglGetDisplay");
+    if (*dpy == EGL_NO_DISPLAY) {
+        testPrintE("eglGetDisplay returned EGL_NO_DISPLAY");
+        exit(70);
+    }
+
+    returnValue = eglInitialize(*dpy, &majorVersion, &minorVersion);
+    checkEglError("eglInitialize", returnValue);
+    if (verbose) {
+        testPrintI("EGL version %d.%d", majorVersion, minorVersion);
+    }
+    if (returnValue != EGL_TRUE) {
+        testPrintE("eglInitialize failed");
+        exit(71);
+    }
+
+    EGLNativeWindowType window = android_createDisplaySurface();
+    if (window == NULL) {
+        testPrintE("android_createDisplaySurface failed");
+        exit(72);
+    }
+    returnValue = EGLUtils::selectConfigForNativeWindow(*dpy,
+        sConfigAttribs, window, &myConfig);
+    if (returnValue) {
+        testPrintE("EGLUtils::selectConfigForNativeWindow() returned %d",
+            returnValue);
+        exit(73);
+    }
+    checkEglError("EGLUtils::selectConfigForNativeWindow");
+
+    if (verbose) {
+        testPrintI("Chose this configuration:");
+        printEGLConfiguration(*dpy, myConfig);
+    }
+
+    *surface = eglCreateWindowSurface(*dpy, myConfig, window, NULL);
+    checkEglError("eglCreateWindowSurface");
+    if (*surface == EGL_NO_SURFACE) {
+        testPrintE("gelCreateWindowSurface failed.");
+        exit(74);
+    }
+
+    context = eglCreateContext(*dpy, myConfig, EGL_NO_CONTEXT, contextAttribs);
+    checkEglError("eglCreateContext");
+    if (context == EGL_NO_CONTEXT) {
+        testPrintE("eglCreateContext failed");
+        exit(75);
+    }
+    returnValue = eglMakeCurrent(*dpy, *surface, *surface, context);
+    checkEglError("eglMakeCurrent", returnValue);
+    if (returnValue != EGL_TRUE) {
+        testPrintE("eglMakeCurrent failed");
+        exit(76);
+    }
+    eglQuerySurface(*dpy, *surface, EGL_WIDTH, width);
+    checkEglError("eglQuerySurface");
+    eglQuerySurface(*dpy, *surface, EGL_HEIGHT, height);
+    checkEglError("eglQuerySurface");
+
+    if (verbose) {
+        testPrintI("Window dimensions: %d x %d", *width, *height);
+
+        printGLString("Version", GL_VERSION);
+        printGLString("Vendor", GL_VENDOR);
+        printGLString("Renderer", GL_RENDERER);
+        printGLString("Extensions", GL_EXTENSIONS);
+    }
+}
+
+// Open Hardware Composer Device
+void hwcTestOpenHwc(hwc_composer_device_t **hwcDevicePtr)
+{
+    int rv;
+    hw_module_t const *hwcModule;
+
+    if ((rv = hw_get_module(HWC_HARDWARE_MODULE_ID, &hwcModule)) != 0) {
+        testPrintE("hw_get_module failed, rv: %i", rv);
+        errno = -rv;
+        perror(NULL);
+        exit(77);
+    }
+    if ((rv = hwc_open(hwcModule, hwcDevicePtr)) != 0) {
+        testPrintE("hwc_open failed, rv: %i", rv);
+        errno = -rv;
+        perror(NULL);
+        exit(78);
+    }
+}
+
+// Color fraction class to string conversion
+ColorFract::operator string()
+{
+    ostringstream out;
+
+    out << '[' << this->c1() << ", "
+        << this->c2() << ", "
+        << this->c3() << ']';
+
+    return out.str();
+}
+
+// Dimension class to string conversion
+HwcTestDim::operator string()
+{
+    ostringstream out;
+
+    out << '[' << this->width() << ", "
+        << this->height() << ']';
+
+    return out.str();
+}
+
+// Hardware Composer rectangle to string conversion
+string hwcTestRect2str(const struct hwc_rect& rect)
+{
+    ostringstream out;
+
+    out << '[';
+    out << rect.left << ", ";
+    out << rect.top << ", ";
+    out << rect.right << ", ";
+    out << rect.bottom;
+    out << ']';
+
+    return out.str();
+}
+
+// Parse HWC rectangle description of form [left, top, right, bottom]
+struct hwc_rect hwcTestParseHwcRect(istringstream& in, bool& error)
+{
+    struct hwc_rect rect;
+    char chStart, ch;
+
+    // Defensively specify that an error occurred.  Will clear
+    // error flag if all of parsing succeeds.
+    error = true;
+
+    // First character should be a [ or <
+    in >> chStart;
+    if (!in || ((chStart != '<') && (chStart != '['))) { return rect; }
+
+    // Left
+    in >> rect.left;
+    if (!in) { return rect; }
+    in >> ch;
+    if (!in || (ch != ',')) { return rect; }
+
+    // Top
+    in >> rect.top;
+    if (!in) { return rect; }
+    in >> ch;
+    if (!in || (ch != ',')) { return rect; }
+
+    // Right
+    in >> rect.right;
+    if (!in) { return rect; }
+    in >> ch;
+    if (!in || (ch != ',')) { return rect; }
+
+    // Bottom
+    in >> rect.bottom;
+    if (!in) { return rect; }
+
+    // Closing > or ]
+    in >> ch;
+    if (!in) { return rect; }
+    if (((chStart == '<') && (ch != '>'))
+        || ((chStart == '[') && (ch != ']'))) { return rect; }
+
+    // Validate right and bottom are greater than left and top
+    if ((rect.right <= rect.left) || (rect.bottom <= rect.top)) { return rect; }
+
+    // Made It, clear error indicator
+    error = false;
+
+    return rect;
+}
+
+// Parse dimension of form [width, height]
+HwcTestDim hwcTestParseDim(istringstream& in, bool& error)
+{
+    HwcTestDim dim;
+    char chStart, ch;
+    uint32_t val;
+
+    // Defensively specify that an error occurred.  Will clear
+    // error flag if all of parsing succeeds.
+    error = true;
+
+    // First character should be a [ or <
+    in >> chStart;
+    if (!in || ((chStart != '<') && (chStart != '['))) { return dim; }
+
+    // Width
+    in >> val;
+    if (!in) { return dim; }
+    dim.setWidth(val);
+    in >> ch;
+    if (!in || (ch != ',')) { return dim; }
+
+    // Height
+    in >> val;
+    if (!in) { return dim; }
+    dim.setHeight(val);
+
+    // Closing > or ]
+    in >> ch;
+    if (!in) { return dim; }
+    if (((chStart == '<') && (ch != '>'))
+        || ((chStart == '[') && (ch != ']'))) { return dim; }
+
+    // Validate width and height greater than 0
+    if ((dim.width() <= 0) || (dim.height() <= 0)) { return dim; }
+
+    // Made It, clear error indicator
+    error = false;
+    return dim;
+}
+
+// Parse fractional color of form [0.##, 0.##, 0.##]
+// Fractional values can be from 0.0 to 1.0 inclusive.  Note, integer
+// values of 0.0 and 1.0, which are non-fractional, are considered valid.
+// They are an exception, all other valid inputs are fractions.
+ColorFract hwcTestParseColor(istringstream& in, bool& error)
+{
+    ColorFract color;
+    char chStart, ch;
+    float c1, c2, c3;
+
+    // Defensively specify that an error occurred.  Will clear
+    // error flag if all of parsing succeeds.
+    error = true;
+
+    // First character should be a [ or <
+    in >> chStart;
+    if (!in || ((chStart != '<') && (chStart != '['))) { return color; }
+
+    // 1st Component
+    in >> c1;
+    if (!in) { return color; }
+    if ((c1 < 0.0) || (c1 > 1.0)) { return color; }
+    in >> ch;
+    if (!in || (ch != ',')) { return color; }
+
+    // 2nd Component
+    in >> c2;
+    if (!in) { return color; }
+    if ((c2 < 0.0) || (c2 > 1.0)) { return color; }
+    in >> ch;
+    if (!in || (ch != ',')) { return color; }
+
+    // 3rd Component
+    in >> c3;
+    if (!in) { return color; }
+    if ((c3 < 0.0) || (c3 > 1.0)) { return color; }
+
+    // Closing > or ]
+    in >> ch;
+    if (!in) { return color; }
+    if (((chStart == '<') && (ch != '>'))
+        || ((chStart == '[') && (ch != ']'))) { return color; }
+
+    // Are all the components fractional
+    if ((c1 < 0.0) || (c1 > 1.0)
+        || (c2 < 0.0) || (c2 > 1.0)
+        || (c3 < 0.0) || (c3 > 1.0)) { return color; }
+
+    // Made It, clear error indicator
+    error = false;
+
+    return ColorFract(c1, c2, c3);
+}
+
+// Look up and return pointer to structure with the characteristics
+// of the graphic format named by the desc parameter.  Search failure
+// indicated by the return of NULL.
+const struct hwcTestGraphicFormat *hwcTestGraphicFormatLookup(const char *desc)
+{
+    for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) {
+        if (string(desc) == string(hwcTestGraphicFormat[n1].desc)) {
+            return &hwcTestGraphicFormat[n1];
+        }
+    }
+
+    return NULL;
+}
+
+// Given the integer ID of a graphic format, return a pointer to
+// a string that describes the format.
+const char *hwcTestGraphicFormat2str(uint32_t format)
+{
+    const static char *unknown = "unknown";
+
+    for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) {
+        if (format == hwcTestGraphicFormat[n1].format) {
+            return hwcTestGraphicFormat[n1].desc;
+        }
+    }
+
+    return unknown;
+}
+
+/*
+ * hwcTestCreateLayerList
+ * Dynamically creates layer list with numLayers worth
+ * of hwLayers entries.
+ */
+hwc_layer_list_t *hwcTestCreateLayerList(size_t numLayers)
+{
+    hwc_layer_list_t *list;
+
+    size_t size = sizeof(hwc_layer_list) + numLayers * sizeof(hwc_layer_t);
+    if ((list = (hwc_layer_list_t *) calloc(1, size)) == NULL) {
+        return NULL;
+    }
+    list->flags = HWC_GEOMETRY_CHANGED;
+    list->numHwLayers = numLayers;
+
+    return list;
+}
+
+/*
+ * hwcTestFreeLayerList
+ * Frees memory previous allocated via hwcTestCreateLayerList().
+ */
+void hwcTestFreeLayerList(hwc_layer_list_t *list)
+{
+    free(list);
+}
+
+// Display the settings of the layer list pointed to by list
+void hwcTestDisplayList(hwc_layer_list_t *list)
+{
+    testPrintI("  flags: %#x%s", list->flags,
+               (list->flags & HWC_GEOMETRY_CHANGED) ? " GEOMETRY_CHANGED" : "");
+    testPrintI("  numHwLayers: %u", list->numHwLayers);
+
+    for (unsigned int layer = 0; layer < list->numHwLayers; layer++) {
+        testPrintI("    layer %u compositionType: %#x%s%s", layer,
+                   list->hwLayers[layer].compositionType,
+                   (list->hwLayers[layer].compositionType == HWC_FRAMEBUFFER)
+                       ? " FRAMEBUFFER" : "",
+                   (list->hwLayers[layer].compositionType == HWC_OVERLAY)
+                       ? " OVERLAY" : "");
+
+        testPrintI("      hints: %#x",
+                   list->hwLayers[layer].hints,
+                   (list->hwLayers[layer].hints & HWC_HINT_TRIPLE_BUFFER)
+                       ? " TRIPLE_BUFFER" : "",
+                   (list->hwLayers[layer].hints & HWC_HINT_CLEAR_FB)
+                       ? " CLEAR_FB" : "");
+
+        testPrintI("      flags: %#x%s",
+                   list->hwLayers[layer].flags,
+                   (list->hwLayers[layer].flags & HWC_SKIP_LAYER)
+                       ? " SKIP_LAYER" : "");
+
+        testPrintI("      handle: %p",
+                   list->hwLayers[layer].handle);
+
+        // Intentionally skipped display of ROT_180 & ROT_270,
+        // which are formed from combinations of the other flags.
+        testPrintI("      transform: %#x%s%s%s",
+                   list->hwLayers[layer].transform,
+                   (list->hwLayers[layer].transform & HWC_TRANSFORM_FLIP_H)
+                       ? " FLIP_H" : "",
+                   (list->hwLayers[layer].transform & HWC_TRANSFORM_FLIP_V)
+                       ? " FLIP_V" : "",
+                   (list->hwLayers[layer].transform & HWC_TRANSFORM_ROT_90)
+                       ? " ROT_90" : "");
+
+        testPrintI("      blending: %#x%s%s%s",
+                   list->hwLayers[layer].blending,
+                   (list->hwLayers[layer].blending == HWC_BLENDING_NONE)
+                       ? " NONE" : "",
+                   (list->hwLayers[layer].blending == HWC_BLENDING_PREMULT)
+                       ? " PREMULT" : "",
+                   (list->hwLayers[layer].blending == HWC_BLENDING_COVERAGE)
+                       ? " COVERAGE" : "");
+
+        testPrintI("      sourceCrop: %s",
+                   hwcTestRect2str(list->hwLayers[layer].sourceCrop).c_str());
+        testPrintI("      displayFrame: %s",
+                   hwcTestRect2str(list->hwLayers[layer].displayFrame).c_str());
+        testPrintI("      scaleFactor: [%f, %f]",
+                   (float) (list->hwLayers[layer].displayFrame.right
+                            - list->hwLayers[layer].displayFrame.left)
+                       / (float) (list->hwLayers[layer].sourceCrop.right
+                            - list->hwLayers[layer].sourceCrop.left),
+                   (float) (list->hwLayers[layer].displayFrame.bottom
+                            - list->hwLayers[layer].displayFrame.top)
+                       / (float) (list->hwLayers[layer].sourceCrop.bottom
+                            - list->hwLayers[layer].sourceCrop.top));
+    }
+}
+
+/*
+ * Display List Prepare Modifiable
+ *
+ * Displays the portions of a list that are meant to be modified by
+ * a prepare call.
+ */
+void hwcTestDisplayListPrepareModifiable(hwc_layer_list_t *list)
+{
+    for (unsigned int layer = 0; layer < list->numHwLayers; layer++) {
+        testPrintI("    layer %u compositionType: %#x%s%s", layer,
+                   list->hwLayers[layer].compositionType,
+                   (list->hwLayers[layer].compositionType == HWC_FRAMEBUFFER)
+                       ? " FRAMEBUFFER" : "",
+                   (list->hwLayers[layer].compositionType == HWC_OVERLAY)
+                       ? " OVERLAY" : "");
+        testPrintI("      hints: %#x%s%s",
+                   list->hwLayers[layer].hints,
+                   (list->hwLayers[layer].hints & HWC_HINT_TRIPLE_BUFFER)
+                       ? " TRIPLE_BUFFER" : "",
+                   (list->hwLayers[layer].hints & HWC_HINT_CLEAR_FB)
+                       ? " CLEAR_FB" : "");
+    }
+}
+
+/*
+ * Display List Handles
+ *
+ * Displays the handles of all the graphic buffers in the list.
+ */
+void hwcTestDisplayListHandles(hwc_layer_list_t *list)
+{
+    const unsigned int maxLayersPerLine = 6;
+
+    ostringstream str("  layers:");
+    for (unsigned int layer = 0; layer < list->numHwLayers; layer++) {
+        str << ' ' << list->hwLayers[layer].handle;
+        if (((layer % maxLayersPerLine) == (maxLayersPerLine - 1))
+            && (layer != list->numHwLayers - 1)) {
+            testPrintI("%s", str.str().c_str());
+            str.str("    ");
+        }
+    }
+    testPrintI("%s", str.str().c_str());
+}
+
+// Returns a uint32_t that contains a format specific representation of a
+// single pixel of the given color and alpha values.
+uint32_t hwcTestColor2Pixel(uint32_t format, ColorFract color, float alpha)
+{
+    const struct attrib {
+        uint32_t format;
+        bool   hostByteOrder;
+        size_t bytes;
+        size_t c1Offset;
+        size_t c1Size;
+        size_t c2Offset;
+        size_t c2Size;
+        size_t c3Offset;
+        size_t c3Size;
+        size_t aOffset;
+        size_t aSize;
+    } attributes[] = {
+        {HAL_PIXEL_FORMAT_RGBA_8888, false, 4,  0, 8,  8, 8, 16, 8, 24, 8},
+        {HAL_PIXEL_FORMAT_RGBX_8888, false, 4,  0, 8,  8, 8, 16, 8,  0, 0},
+        {HAL_PIXEL_FORMAT_RGB_888,   false, 3,  0, 8,  8, 8, 16, 8,  0, 0},
+        {HAL_PIXEL_FORMAT_RGB_565,   true,  2,  0, 5,  5, 6, 11, 5,  0, 0},
+        {HAL_PIXEL_FORMAT_BGRA_8888, false, 4, 16, 8,  8, 8,  0, 8, 24, 8},
+        {HAL_PIXEL_FORMAT_RGBA_5551, true , 2,  0, 5,  5, 5, 10, 5, 15, 1},
+        {HAL_PIXEL_FORMAT_RGBA_4444, false, 2, 12, 4,  0, 4,  4, 4,  8, 4},
+        {HAL_PIXEL_FORMAT_YV12,      true,  3, 16, 8,  8, 8,  0, 8,  0, 0},  
+    };
+
+    const struct attrib *attrib;
+    for (attrib = attributes; attrib < attributes + NUMA(attributes);
+         attrib++) {
+        if (attrib->format == format) { break; }
+    }
+    if (attrib >= attributes + NUMA(attributes)) {
+        testPrintE("colorFract2Pixel unsupported format of: %u", format);
+        exit(80);
+    }
+
+    uint32_t pixel;
+    pixel = htonl((uint32_t) round((((1 << attrib->c1Size) - 1) * color.c1()))
+         << ((sizeof(pixel) * BITSPERBYTE)
+             - (attrib->c1Offset + attrib->c1Size)));
+    pixel |= htonl((uint32_t) round((((1 << attrib->c2Size) - 1) * color.c2()))
+         << ((sizeof(pixel) * BITSPERBYTE)
+             - (attrib->c2Offset + attrib->c2Size)));
+    pixel |= htonl((uint32_t) round((((1 << attrib->c3Size) - 1) * color.c3()))
+         << ((sizeof(pixel) * BITSPERBYTE)
+             - (attrib->c3Offset + attrib->c3Size)));
+    if (attrib->aSize) {
+        pixel |= htonl((uint32_t) round((((1 << attrib->aSize) - 1) * alpha))
+             << ((sizeof(pixel) * BITSPERBYTE)
+                 - (attrib->aOffset + attrib->aSize)));
+    }
+    if (attrib->hostByteOrder) {
+        pixel = ntohl(pixel);
+        pixel >>= sizeof(pixel) * BITSPERBYTE - attrib->bytes * BITSPERBYTE;
+    }
+
+    return pixel;
+}
+
+// Sets the pixel at the given x and y coordinates to the color and alpha
+// value given by pixel.  The contents of pixel is format specific.  It's
+// value should come from a call to hwcTestColor2Pixel().
+void hwcTestSetPixel(GraphicBuffer *gBuf, unsigned char *buf,
+              uint32_t x, uint32_t y, uint32_t pixel)
+{
+
+    const struct attrib {
+        int format;
+        size_t bytes;
+    } attributes[] = {
+        {HAL_PIXEL_FORMAT_RGBA_8888,  4},
+        {HAL_PIXEL_FORMAT_RGBX_8888,  4},
+        {HAL_PIXEL_FORMAT_RGB_888,    3},
+        {HAL_PIXEL_FORMAT_RGB_565,    2},
+        {HAL_PIXEL_FORMAT_BGRA_8888,  4},
+        {HAL_PIXEL_FORMAT_RGBA_5551,  2},
+        {HAL_PIXEL_FORMAT_RGBA_4444,  2},
+    };
+
+    if (gBuf->getPixelFormat() == HAL_PIXEL_FORMAT_YV12) {
+        uint32_t yPlaneOffset, uPlaneOffset, vPlaneOffset;
+        uint32_t yPlaneStride = gBuf->getStride();
+        uint32_t uPlaneStride = ((gBuf->getStride() / 2) + 0xf) & ~0xf;
+        uint32_t vPlaneStride = uPlaneStride;
+        yPlaneOffset = 0;
+        vPlaneOffset = yPlaneOffset + yPlaneStride * gBuf->getHeight();
+        uPlaneOffset = vPlaneOffset
+                       + vPlaneStride * (gBuf->getHeight() / 2);
+        *(buf + yPlaneOffset + y * yPlaneStride + x) = pixel & 0xff;
+        *(buf + uPlaneOffset + (y / 2) * uPlaneStride + (x / 2))
+            = (pixel & 0xff00) >> 8;
+        *(buf + vPlaneOffset + (y / 2) * vPlaneStride + (x / 2))
+            = (pixel & 0xff0000) >> 16;
+
+        return;
+    }
+
+    const struct attrib *attrib;
+    for (attrib = attributes; attrib < attributes + NUMA(attributes);
+         attrib++) {
+        if (attrib->format == gBuf->getPixelFormat()) { break; }
+    }
+    if (attrib >= attributes + NUMA(attributes)) {
+        testPrintE("setPixel unsupported format of: %u",
+                   gBuf->getPixelFormat());
+        exit(90);
+    }
+
+    memmove(buf + ((gBuf->getStride() * attrib->bytes) * y)
+            + (attrib->bytes * x), &pixel, attrib->bytes);
+}
+
+// Fill a given graphic buffer with a uniform color and alpha
+void hwcTestFillColor(GraphicBuffer *gBuf, ColorFract color, float alpha)
+{
+    unsigned char* buf = NULL;
+    status_t err;
+    uint32_t pixel;
+
+    pixel = hwcTestColor2Pixel(gBuf->getPixelFormat(), color, alpha);
+
+    err = gBuf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf));
+    if (err != 0) {
+        testPrintE("hwcTestFillColor lock failed: %d", err);
+        exit(100);
+    }
+
+    for (unsigned int x = 0; x < gBuf->getStride(); x++) {
+        for (unsigned int y = 0; y < gBuf->getHeight(); y++) {
+            uint32_t val = pixel;
+            hwcTestSetPixel(gBuf, buf, x, y, (x < gBuf->getWidth())
+                            ? pixel : testRand());
+        }
+    }
+
+    err = gBuf->unlock();
+    if (err != 0) {
+        testPrintE("hwcTestFillColor unlock failed: %d", err);
+        exit(101);
+    }
+}
+
+// Fill the given buffer with a horizontal blend of colors, with the left
+// side color given by startColor and the right side color given by
+// endColor.  The startColor and endColor values are specified in the format
+// given by colorFormat, which might be different from the format of the
+// graphic buffer.  When different, a color conversion is done when possible
+// to the graphic format of the graphic buffer.  A color of black is
+// produced for cases where the conversion is impossible (e.g. out of gamut
+// values).
+void hwcTestFillColorHBlend(GraphicBuffer *gBuf, uint32_t colorFormat,
+                            ColorFract startColor, ColorFract endColor)
+{
+    status_t err;
+    unsigned char* buf = NULL;
+    const uint32_t width = gBuf->getWidth();
+    const uint32_t height = gBuf->getHeight();
+    const uint32_t stride = gBuf->getStride();
+
+    err = gBuf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf));
+    if (err != 0) {
+        testPrintE("hwcTestFillColorHBlend lock failed: %d", err);
+        exit(110);
+    }
+
+    for (unsigned int x = 0; x < stride; x++) {
+        uint32_t pixel;
+        if (x < width) {
+            ColorFract color(startColor.c1() + (endColor.c1() - startColor.c1())
+                                 * ((float) x / (float) (width - 1)),
+                             startColor.c2() + (endColor.c2() - startColor.c2())
+                                 * ((float) x / (float) (width - 1)),
+                             startColor.c3() + (endColor.c3() - startColor.c3())
+                                 * ((float) x / (float) (width - 1)));
+
+            // When formats differ, convert colors.
+            // Important to not convert when formats are the same, since
+            // out of gamut colors are always converted to black.
+            if (colorFormat != (uint32_t) gBuf->getPixelFormat()) {
+                hwcTestColorConvert(colorFormat, gBuf->getPixelFormat(), color);
+            }
+            pixel = hwcTestColor2Pixel(gBuf->getPixelFormat(), color, 1.0);
+        } else {
+            // Fill pad with random values
+            pixel = testRand();
+        }
+
+        for (unsigned int y = 0; y <= height; y++) {
+            hwcTestSetPixel(gBuf, buf, x, y, pixel);
+        }
+    }
+
+    err = gBuf->unlock();
+    if (err != 0) {
+        testPrintE("hwcTestFillColorHBlend unlock failed: %d", err);
+        exit(111);
+    }
+}
+
+/*
+ * When possible, converts color specified as a full range value in
+ * the fromFormat, into an equivalent full range color in the toFormat.
+ * When conversion is impossible (e.g. out of gamut color) a color
+ * or black in the full range output format is produced.  The input
+ * color is given as a fractional color in the parameter named color.
+ * The produced color is written over the same parameter used to
+ * provide the input color.
+ *
+ * Each graphic format has 3 color components and each of these
+ * components has both a full and in gamut range.  This function uses
+ * a table that provides the full and in gamut ranges of each of the
+ * supported graphic formats.  The full range is given by members named
+ * c[123]Min to c[123]Max, while the in gamut range is given by members
+ * named c[123]Low to c[123]High.  In most cases the full and in gamut
+ * ranges are equivalent.  This occurs when the c[123]Min == c[123]Low and
+ * c[123]High == c[123]Max.
+ *
+ * The input and produced colors are both specified as a fractional amount
+ * of the full range.  The diagram below provides an overview of the
+ * conversion process.  The main steps are:
+ *
+ *   1. Produce black if the input color is out of gamut.
+ *
+ *   2. Convert the in gamut color into the fraction of the fromFromat
+ *      in gamut range.
+ *
+ *   3. Convert from the fraction of the in gamut from format range to
+ *      the fraction of the in gamut to format range.  Produce black
+ *      if an equivalent color does not exists.
+ *
+ *   4. Covert from the fraction of the in gamut to format to the
+ *      fraction of the full range to format.
+ *
+ *       From Format                 To Format
+ *    max           high            high        max
+ *    ----+                 +-----------+
+ *    high \               /             \      high
+ *    ------\-------------+               +-------->
+ *           \
+ *            \                   +--- black --+
+ *             \                 /              \
+ *              \               /                +-->
+ *    low        \             /                  low
+ *    -------- ---+-- black --+
+ *    min             low           low           min
+ *     ^               ^      ^      ^             ^
+ *     |               |      |      |             |
+ *     |               |      |      |             +-- fraction of full range
+ *     |               |      |      +-- fraction of valid range
+ *     |               |      +-- fromFormat to toFormat color conversion
+ *     |               +-- fraction of valid range
+ *     +-- fraction of full range
+ */
+void hwcTestColorConvert(uint32_t fromFormat, uint32_t toFormat,
+                  ColorFract& color)
+{
+    const struct attrib {
+        uint32_t     format;
+        bool         rgb;
+        bool         yuv;
+        int          c1Min, c1Low, c1High, c1Max;
+        int          c2Min, c2Low, c2High, c2Max;
+        int          c3Min, c3Low, c3High, c3Max;
+    } attributes[] = {
+        {HAL_PIXEL_FORMAT_RGBA_8888, true,  false,
+         0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255},
+        {HAL_PIXEL_FORMAT_RGBX_8888, true,  false,
+         0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255},
+        {HAL_PIXEL_FORMAT_RGB_888,   true,  false,
+         0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255},
+        {HAL_PIXEL_FORMAT_RGB_565,   true,  false,
+         0, 0, 31, 31, 0, 0, 63, 63, 0, 0, 31, 31},
+        {HAL_PIXEL_FORMAT_BGRA_8888, true,  false,
+         0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255},
+        {HAL_PIXEL_FORMAT_RGBA_5551, true,  false,
+         0, 0, 31, 31, 0, 0, 31, 31, 0, 0, 31, 31},
+        {HAL_PIXEL_FORMAT_RGBA_4444, true,  false,
+         0, 0, 15, 15, 0, 0, 15, 15, 0, 0, 15, 15},
+        {HAL_PIXEL_FORMAT_YV12,      false, true,
+         0, 16, 235, 255, 0, 16, 240, 255, 0, 16, 240, 255},
+    };
+
+    const struct attrib *fromAttrib;
+    for (fromAttrib = attributes; fromAttrib < attributes + NUMA(attributes);
+         fromAttrib++) {
+        if (fromAttrib->format == fromFormat) { break; }
+    }
+    if (fromAttrib >= attributes + NUMA(attributes)) {
+        testPrintE("hwcTestColorConvert unsupported from format of: %u",
+                   fromFormat);
+        exit(120);
+    }
+
+    const struct attrib *toAttrib;
+    for (toAttrib = attributes; toAttrib < attributes + NUMA(attributes);
+         toAttrib++) {
+        if (toAttrib->format == toFormat) { break; }
+    }
+    if (toAttrib >= attributes + NUMA(attributes)) {
+        testPrintE("hwcTestColorConvert unsupported to format of: %u",
+                   toFormat);
+        exit(121);
+    }
+
+    // Produce black if any of the from components are outside the
+    // valid color range
+    float c1Val = fromAttrib->c1Min
+        + ((float) (fromAttrib->c1Max - fromAttrib->c1Min) * color.c1());
+    float c2Val = fromAttrib->c2Min
+        + ((float) (fromAttrib->c2Max - fromAttrib->c2Min) * color.c2());
+    float c3Val = fromAttrib->c3Min
+        + ((float) (fromAttrib->c3Max - fromAttrib->c3Min) * color.c3());
+    if ((c1Val < fromAttrib->c1Low) || (c1Val > fromAttrib->c1High)
+        || (c2Val < fromAttrib->c2Low) || (c2Val > fromAttrib->c2High)
+        || (c3Val < fromAttrib->c3Low) || (c3Val > fromAttrib->c3High)) {
+
+        // Return black
+        // Will use representation of black from RGBA8888 graphic format
+        // and recursively convert it to the requested graphic format.
+        color = ColorFract(0.0, 0.0, 0.0);
+        hwcTestColorConvert(HAL_PIXEL_FORMAT_RGBA_8888, toFormat, color);
+        return;
+    }
+
+    // Within from format, convert from fraction of full range
+    // to fraction of valid range
+    color = ColorFract((c1Val - fromAttrib->c1Low)
+                           / (fromAttrib->c1High - fromAttrib->c1Low),
+                       (c2Val - fromAttrib->c2Low)
+                           / (fromAttrib->c2High - fromAttrib->c2Low),
+                       (c3Val - fromAttrib->c3Low)
+                           / (fromAttrib->c3High - fromAttrib->c3Low));
+
+    // If needed perform RGB to YUV conversion
+    float wr = 0.2126, wg = 0.7152, wb = 0.0722; // ITU709 recommended constants
+    if (fromAttrib->rgb && toAttrib->yuv) {
+        float r = color.c1(), g = color.c2(), b = color.c3();
+        float y = wr * r + wg * g + wb * b;
+        float u = 0.5 * ((b - y) / (1.0 - wb)) + 0.5;
+        float v = 0.5 * ((r - y) / (1.0 - wr)) + 0.5;
+
+        // Produce black if color is outside the YUV gamut
+        if ((y < 0.0) || (y > 1.0)
+            || (u < 0.0) || (u > 1.0)
+            || (v < 0.0) || (v > 1.0)) {
+            y = 0.0;
+            u = v = 0.5;
+        }
+
+        color = ColorFract(y, u, v);
+    }
+
+    // If needed perform YUV to RGB conversion
+    // Equations determined from the ITU709 equations for RGB to YUV
+    // conversion, plus the following algebra:
+    //
+    //   u = 0.5 * ((b - y) / (1.0 - wb)) + 0.5
+    //   0.5 * ((b - y) / (1.0 - wb)) = u - 0.5
+    //   (b - y) / (1.0 - wb) = 2 * (u - 0.5)
+    //   b - y = 2 * (u - 0.5) * (1.0 - wb)
+    //   b = 2 * (u - 0.5) * (1.0 - wb) + y
+    //
+    //   v = 0.5 * ((r -y) / (1.0 - wr)) + 0.5
+    //   0.5 * ((r - y) / (1.0 - wr)) = v - 0.5
+    //   (r - y) / (1.0 - wr) = 2 * (v - 0.5)
+    //   r - y = 2 * (v - 0.5) * (1.0 - wr)
+    //   r = 2 * (v - 0.5) * (1.0 - wr) + y
+    //
+    //   y = wr * r + wg * g + wb * b
+    //   wr * r + wg * g + wb * b = y
+    //   wg * g = y - wr * r - wb * b
+    //   g = (y - wr * r - wb * b) / wg
+    if (fromAttrib->yuv && toAttrib->rgb) {
+        float y = color.c1(), u = color.c2(), v = color.c3();
+        float r = 2.0 * (v - 0.5) * (1.0 - wr) + y;
+        float b = 2.0 * (u - 0.5) * (1.0 - wb) + y;
+        float g = (y - wr * r - wb * b) / wg;
+
+        // Produce black if color is outside the RGB gamut
+        if ((r < 0.0) || (r > 1.0)
+            || (g < 0.0) || (g > 1.0)
+            || (b < 0.0) || (b > 1.0)) {
+            r = g = b = 0.0;
+        }
+
+        color = ColorFract(r, g, b);
+    }
+
+    // Within to format, convert from fraction of valid range
+    // to fraction of full range
+    c1Val = (toAttrib->c1Low
+        + (float) (toAttrib->c1High - toAttrib->c1Low) * color.c1());
+    c2Val = (toAttrib->c1Low
+        + (float) (toAttrib->c2High - toAttrib->c2Low) * color.c2());
+    c3Val = (toAttrib->c1Low
+        + (float) (toAttrib->c3High - toAttrib->c3Low) * color.c3());
+    color = ColorFract((float) (c1Val - toAttrib->c1Min)
+                           / (float) (toAttrib->c1Max - toAttrib->c1Min),
+                       (float) (c2Val - toAttrib->c2Min)
+                           / (float) (toAttrib->c2Max - toAttrib->c2Min),
+                       (float) (c3Val - toAttrib->c3Min)
+                           / (float) (toAttrib->c3Max - toAttrib->c3Min));
+}
+
+// TODO: Use PrintGLString, CechckGlError, and PrintEGLConfiguration
+//       from libglTest
+static void printGLString(const char *name, GLenum s)
+{
+    const char *v = (const char *) glGetString(s);
+
+    if (v == NULL) {
+        testPrintI("GL %s unknown", name);
+    } else {
+        testPrintI("GL %s = %s", name, v);
+    }
+}
+
+static void checkEglError(const char* op, EGLBoolean returnVal)
+{
+    if (returnVal != EGL_TRUE) {
+        testPrintE("%s() returned %d", op, returnVal);
+    }
+
+    for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
+            = eglGetError()) {
+        testPrintE("after %s() eglError %s (0x%x)",
+                   op, EGLUtils::strerror(error), error);
+    }
+}
+
+static void checkGlError(const char* op)
+{
+    for (GLint error = glGetError(); error; error
+            = glGetError()) {
+        testPrintE("after %s() glError (0x%x)", op, error);
+    }
+}
+
+static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config)
+{
+
+#define X(VAL) {VAL, #VAL}
+    struct {EGLint attribute; const char* name;} names[] = {
+    X(EGL_BUFFER_SIZE),
+    X(EGL_ALPHA_SIZE),
+    X(EGL_BLUE_SIZE),
+    X(EGL_GREEN_SIZE),
+    X(EGL_RED_SIZE),
+    X(EGL_DEPTH_SIZE),
+    X(EGL_STENCIL_SIZE),
+    X(EGL_CONFIG_CAVEAT),
+    X(EGL_CONFIG_ID),
+    X(EGL_LEVEL),
+    X(EGL_MAX_PBUFFER_HEIGHT),
+    X(EGL_MAX_PBUFFER_PIXELS),
+    X(EGL_MAX_PBUFFER_WIDTH),
+    X(EGL_NATIVE_RENDERABLE),
+    X(EGL_NATIVE_VISUAL_ID),
+    X(EGL_NATIVE_VISUAL_TYPE),
+    X(EGL_SAMPLES),
+    X(EGL_SAMPLE_BUFFERS),
+    X(EGL_SURFACE_TYPE),
+    X(EGL_TRANSPARENT_TYPE),
+    X(EGL_TRANSPARENT_RED_VALUE),
+    X(EGL_TRANSPARENT_GREEN_VALUE),
+    X(EGL_TRANSPARENT_BLUE_VALUE),
+    X(EGL_BIND_TO_TEXTURE_RGB),
+    X(EGL_BIND_TO_TEXTURE_RGBA),
+    X(EGL_MIN_SWAP_INTERVAL),
+    X(EGL_MAX_SWAP_INTERVAL),
+    X(EGL_LUMINANCE_SIZE),
+    X(EGL_ALPHA_MASK_SIZE),
+    X(EGL_COLOR_BUFFER_TYPE),
+    X(EGL_RENDERABLE_TYPE),
+    X(EGL_CONFORMANT),
+   };
+#undef X
+
+    for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
+        EGLint value = -1;
+        EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute,
+                                              &value);
+        EGLint error = eglGetError();
+        if (returnVal && error == EGL_SUCCESS) {
+            testPrintI(" %s: %d (%#x)", names[j].name, value, value);
+        }
+    }
+    testPrintI("");
+}
diff --git a/opengl/tests/hwc/hwcTestLib.h b/opengl/tests/hwc/hwcTestLib.h
new file mode 100644
index 0000000..e19e163
--- /dev/null
+++ b/opengl/tests/hwc/hwcTestLib.h
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ * Hardware Composer Test Library Header
+ */
+
+#include <sstream>
+#include <string>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/EGLUtils.h>
+
+#include <utils/Log.h>
+#include <testUtil.h>
+
+#include <hardware/hwcomposer.h>
+
+// Characteristics of known graphic formats
+const struct hwcTestGraphicFormat {
+    uint32_t format;
+    const char *desc;
+    uint32_t wMod, hMod; // Width/height mod this value must equal zero
+} hwcTestGraphicFormat[] = {
+    {HAL_PIXEL_FORMAT_RGBA_8888, "RGBA8888", 1, 1},
+    {HAL_PIXEL_FORMAT_RGBX_8888, "RGBX8888", 1, 1},
+    {HAL_PIXEL_FORMAT_RGB_888,   "RGB888",   1, 1},
+    {HAL_PIXEL_FORMAT_RGB_565,   "RGB565",   1, 1},
+    {HAL_PIXEL_FORMAT_BGRA_8888, "BGRA8888", 1, 1},
+    {HAL_PIXEL_FORMAT_RGBA_5551, "RGBA5551", 1, 1},
+    {HAL_PIXEL_FORMAT_RGBA_4444, "RGBA4444", 1, 1},
+    {HAL_PIXEL_FORMAT_YV12,      "YV12",     2, 2},
+};
+
+// Represent RGB color as fraction of color components.
+// Each of the color components are expected in the range [0.0, 1.0]
+class ColorFract {
+  public:
+    ColorFract(): _c1(0.0), _c2(0.0), _c3(0.0) {};
+    ColorFract(float c1, float c2, float c3): _c1(c1), _c2(c2), _c3(c3) {};
+    float c1(void) const { return _c1; }
+    float c2(void) const { return _c2; }
+    float c3(void) const { return _c3; }
+
+    operator std::string();
+
+  private:
+    float _c1;
+    float _c2;
+    float _c3;
+};
+
+// Represent RGB color as fraction of color components.
+// Each of the color components are expected in the range [0.0, 1.0]
+class ColorRGB {
+  public:
+    ColorRGB(): _r(0.0), _g(0.0), _b(0.0) {};
+    ColorRGB(float f): _r(f), _g(f), _b(f) {}; // Gray
+    ColorRGB(float r, float g, float b): _r(r), _g(g), _b(b) {};
+    float r(void) const { return _r; }
+    float g(void) const { return _g; }
+    float b(void) const { return _b; }
+
+  private:
+    float _r;
+    float _g;
+    float _b;
+};
+
+// Dimension - width and height of a rectanguler area
+class HwcTestDim {
+  public:
+    HwcTestDim(): _w(0), _h(0) {};
+    HwcTestDim(uint32_t w, uint32_t h) : _w(w), _h(h) {}
+    uint32_t width(void) const { return _w; }
+    uint32_t height(void) const { return _h; }
+    void setWidth(uint32_t w) { _w = w; }
+    void setHeight(uint32_t h) { _h = h; }
+
+    operator std::string();
+
+  private:
+    uint32_t _w;
+    uint32_t _h;
+};
+
+// Function Prototypes
+void hwcTestInitDisplay(bool verbose, EGLDisplay *dpy, EGLSurface *surface,
+    EGLint *width, EGLint *height);
+void hwcTestOpenHwc(hwc_composer_device_t **hwcDevicePtr);
+const struct hwcTestGraphicFormat *hwcTestGraphicFormatLookup(const char *desc);
+const char *hwcTestGraphicFormat2str(uint32_t format);
+std::string hwcTestRect2str(const struct hwc_rect& rect);
+
+hwc_layer_list_t *hwcTestCreateLayerList(size_t numLayers);
+void hwcTestFreeLayerList(hwc_layer_list_t *list);
+void hwcTestDisplayList(hwc_layer_list_t *list);
+void hwcTestDisplayListPrepareModifiable(hwc_layer_list_t *list);
+void hwcTestDisplayListHandles(hwc_layer_list_t *list);
+
+uint32_t hwcTestColor2Pixel(uint32_t format, ColorFract color, float alpha);
+void hwcTestColorConvert(uint32_t fromFormat, uint32_t toFormat,
+                  ColorFract& color);
+void hwcTestSetPixel(android::GraphicBuffer *gBuf, unsigned char *buf,
+                     uint32_t x, uint32_t y, uint32_t pixel);
+void hwcTestFillColor(android::GraphicBuffer *gBuf, ColorFract color,
+                      float alpha);
+void hwcTestFillColorHBlend(android::GraphicBuffer *gBuf,
+                            uint32_t colorFormat,
+                            ColorFract startColor, ColorFract endColor);
+ColorFract hwcTestParseColor(std::istringstream& in, bool& error);
+struct hwc_rect hwcTestParseHwcRect(std::istringstream& in, bool& error);
+HwcTestDim hwcTestParseDim(std::istringstream& in, bool& error);
diff --git a/opengl/tests/hwc/hwc_stress.cpp b/opengl/tests/hwc/hwc_stress.cpp
deleted file mode 100644
index 580eb83..0000000
--- a/opengl/tests/hwc/hwc_stress.cpp
+++ /dev/null
@@ -1,1262 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-/*
- * Hardware Composer stress test
- *
- * Performs a pseudo-random (prandom) sequence of operations to the
- * Hardware Composer (HWC), for a specified number of passes or for
- * a specified period of time.  By default the period of time is FLT_MAX,
- * so that the number of passes will take precedence.
- *
- * The passes are grouped together, where (pass / passesPerGroup) specifies
- * which group a particular pass is in.  This causes every passesPerGroup
- * worth of sequential passes to be within the same group.  Computationally
- * intensive operations are performed just once at the beginning of a group
- * of passes and then used by all the passes in that group.  This is done
- * so as to increase both the average and peak rate of graphic operations,
- * by moving computationally intensive operations to the beginning of a group.
- * In particular, at the start of each group of passes a set of
- * graphic buffers are created, then used by the first and remaining
- * passes of that group of passes.
- *
- * The per-group initialization of the graphic buffers is performed
- * by a function called initFrames.  This function creates an array
- * of smart pointers to the graphic buffers, in the form of a vector
- * of vectors.  The array is accessed in row major order, so each
- * row is a vector of smart pointers.  All the pointers of a single
- * row point to graphic buffers which use the same pixel format and
- * have the same dimension, although it is likely that each one is
- * filled with a different color.  This is done so that after doing
- * the first HWC prepare then set call, subsequent set calls can
- * be made with each of the layer handles changed to a different
- * graphic buffer within the same row.  Since the graphic buffers
- * in a particular row have the same pixel format and dimension,
- * additional HWC set calls can be made, without having to perform
- * an HWC prepare call.
- *
- * This test supports the following command-line options:
- *
- *   -v        Verbose
- *   -s num    Starting pass
- *   -e num    Ending pass
- *   -p num    Execute the single pass specified by num
- *   -n num    Number of set operations to perform after each prepare operation
- *   -t float  Maximum time in seconds to execute the test
- *   -d float  Delay in seconds performed after each set operation
- *   -D float  Delay in seconds performed after the last pass is executed
- *
- * Typically the test is executed for a large range of passes.  By default
- * passes 0 through 99999 (100,000 passes) are executed.  Although this test
- * does not validate the generated image, at times it is useful to reexecute
- * a particular pass and leave the displayed image on the screen for an
- * extended period of time.  This can be done either by setting the -s
- * and -e options to the desired pass, along with a large value for -D.
- * This can also be done via the -p option, again with a large value for
- * the -D options.
- *
- * So far this test only contains code to create graphic buffers with
- * a continuous solid color.  Although this test is unable to validate the
- * image produced, any image that contains other than rectangles of a solid
- * color are incorrect.  Note that the rectangles may use a transparent
- * color and have a blending operation that causes the color in overlapping
- * rectangles to be mixed.  In such cases the overlapping portions may have
- * a different color from the rest of the rectangle.
- */
-
-#include <algorithm>
-#include <assert.h>
-#include <cerrno>
-#include <cmath>
-#include <cstdlib>
-#include <ctime>
-#include <libgen.h>
-#include <sched.h>
-#include <sstream>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <vector>
-
-#include <arpa/inet.h> // For ntohl() and htonl()
-
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-#include <ui/FramebufferNativeWindow.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/EGLUtils.h>
-
-#define LOG_TAG "hwcStressTest"
-#include <utils/Log.h>
-#include <testUtil.h>
-
-#include <hardware/hwcomposer.h>
-
-using namespace std;
-using namespace android;
-
-const float maxSizeRatio = 1.3;  // Graphic buffers can be upto this munch
-                                 // larger than the default screen size
-const unsigned int passesPerGroup = 10; // A group of passes all use the same
-                                        // graphic buffers
-
-// Ratios at which rare and frequent conditions should be produced
-const float rareRatio = 0.1;
-const float freqRatio = 0.9;
-
-// Defaults for command-line options
-const bool defaultVerbose = false;
-const unsigned int defaultStartPass = 0;
-const unsigned int defaultEndPass = 99999;
-const unsigned int defaultPerPassNumSet = 10;
-const float defaultPerSetDelay = 0.0; // Default delay after each set
-                                      // operation.  Default delay of
-                                      // zero used so as to perform the
-                                      // the set operations as quickly
-                                      // as possible.
-const float defaultEndDelay = 2.0; // Default delay between completion of
-                                   // final pass and restart of framework
-const float defaultDuration = FLT_MAX; // A fairly long time, so that
-                                       // range of passes will have
-                                       // precedence
-
-// Command-line option settings
-static bool verbose = defaultVerbose;
-static unsigned int startPass = defaultStartPass;
-static unsigned int endPass = defaultEndPass;
-static unsigned int numSet = defaultPerPassNumSet;
-static float perSetDelay = defaultPerSetDelay;
-static float endDelay = defaultEndDelay;
-static float duration = defaultDuration;
-
-// Command-line mutual exclusion detection flags.
-// Corresponding flag set true once an option is used.
-bool eFlag, sFlag, pFlag;
-
-#define MAXSTR               100
-#define MAXCMD               200
-#define BITSPERBYTE            8 // TODO: Obtain from <values.h>, once
-                                 // it has been added
-
-#define CMD_STOP_FRAMEWORK   "stop 2>&1"
-#define CMD_START_FRAMEWORK  "start 2>&1"
-
-#define NUMA(a) (sizeof(a) / sizeof(a [0]))
-#define MEMCLR(addr, size) do { \
-        memset((addr), 0, (size)); \
-    } while (0)
-
-// Represent RGB color as fraction of color components.
-// Each of the color components are expected in the range [0.0, 1.0]
-class RGBColor {
-  public:
-    RGBColor(): _r(0.0), _g(0.0), _b(0.0) {};
-    RGBColor(float f): _r(f), _g(f), _b(f) {}; // Gray
-    RGBColor(float r, float g, float b): _r(r), _g(g), _b(b) {};
-    float r(void) const { return _r; }
-    float g(void) const { return _g; }
-    float b(void) const { return _b; }
-
-  private:
-    float _r;
-    float _g;
-    float _b;
-};
-
-// Represent YUV color as fraction of color components.
-// Each of the color components are expected in the range [0.0, 1.0]
-class YUVColor {
-  public:
-    YUVColor(): _y(0.0), _u(0.0), _v(0.0) {};
-    YUVColor(float f): _y(f), _u(0.0), _v(0.0) {}; // Gray
-    YUVColor(float y, float u, float v): _y(y), _u(u), _v(v) {};
-    float y(void) const { return _y; }
-    float u(void) const { return _u; }
-    float v(void) const { return _v; }
-
-  private:
-    float _y;
-    float _u;
-    float _v;
-};
-
-// File scope constants
-static const struct graphicFormat {
-    unsigned int format;
-    const char *desc;
-    unsigned int wMod, hMod; // Width/height mod this value must equal zero
-} graphicFormat[] = {
-    {HAL_PIXEL_FORMAT_RGBA_8888, "RGBA8888", 1, 1},
-    {HAL_PIXEL_FORMAT_RGBX_8888, "RGBX8888", 1, 1},
-    {HAL_PIXEL_FORMAT_RGB_888, "RGB888", 1, 1},
-    {HAL_PIXEL_FORMAT_RGB_565, "RGB565", 1, 1},
-    {HAL_PIXEL_FORMAT_BGRA_8888, "BGRA8888", 1, 1},
-    {HAL_PIXEL_FORMAT_RGBA_5551, "RGBA5551", 1, 1},
-    {HAL_PIXEL_FORMAT_RGBA_4444, "RGBA4444", 1, 1},
-    {HAL_PIXEL_FORMAT_YV12, "YV12", 2, 2},
-};
-const unsigned int blendingOps[] = {
-    HWC_BLENDING_NONE,
-    HWC_BLENDING_PREMULT,
-    HWC_BLENDING_COVERAGE,
-};
-const unsigned int layerFlags[] = {
-    HWC_SKIP_LAYER,
-};
-const vector<unsigned int> vecLayerFlags(layerFlags,
-    layerFlags + NUMA(layerFlags));
-
-const unsigned int transformFlags[] = {
-    HWC_TRANSFORM_FLIP_H,
-    HWC_TRANSFORM_FLIP_V,
-    HWC_TRANSFORM_ROT_90,
-    // ROT_180 & ROT_270 intentionally not listed, because they
-    // they are formed from combinations of the flags already listed.
-};
-const vector<unsigned int> vecTransformFlags(transformFlags,
-    transformFlags + NUMA(transformFlags));
-
-// File scope globals
-static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE |
-        GraphicBuffer::USAGE_SW_WRITE_RARELY;
-static hw_module_t const *hwcModule;
-static hwc_composer_device_t *hwcDevice;
-static vector <vector <sp<GraphicBuffer> > > frames;
-static EGLDisplay dpy;
-static EGLContext context;
-static EGLSurface surface;
-static EGLint width, height;
-
-// File scope prototypes
-static void execCmd(const char *cmd);
-static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE);
-static void checkGlError(const char* op);
-static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config);
-static void printGLString(const char *name, GLenum s);
-static hwc_layer_list_t *createLayerList(size_t numLayers);
-static void freeLayerList(hwc_layer_list_t *list);
-static void fillColor(GraphicBuffer *gBuf, RGBColor color, float trans);
-static void fillColor(GraphicBuffer *gBuf, YUVColor color, float trans);
-void init(void);
-void initFrames(unsigned int seed);
-void displayList(hwc_layer_list_t *list);
-void displayListPrepareModifiable(hwc_layer_list_t *list);
-void displayListHandles(hwc_layer_list_t *list);
-const char *graphicFormat2str(unsigned int format);
-template <class T> vector<T> vectorRandSelect(const vector<T>& vec, size_t num);
-template <class T> T vectorOr(const vector<T>& vec);
-
-/*
- * Main
- *
- * Performs the following high-level sequence of operations:
- *
- *   1. Command-line parsing
- *
- *   2. Initialization
- *
- *   3. For each pass:
- *
- *        a. If pass is first pass or in a different group from the
- *           previous pass, initialize the array of graphic buffers.
- *
- *        b. Create a HWC list with room to specify a prandomly
- *           selected number of layers.
- *
- *        c. Select a subset of the rows from the graphic buffer array,
- *           such that there is a unique row to be used for each
- *           of the layers in the HWC list.
- *
- *        d. Prandomly fill in the HWC list with handles
- *           selected from any of the columns of the selected row.
- *
- *        e. Pass the populated list to the HWC prepare call.
- *
- *        f. Pass the populated list to the HWC set call.
- *
- *        g. If additional set calls are to be made, then for each
- *           additional set call, select a new set of handles and
- *           perform the set call.
- */
-int
-main(int argc, char *argv[])
-{
-    int rv, opt;
-    char *chptr;
-    unsigned int pass;
-    char cmd[MAXCMD];
-    struct timeval startTime, currentTime, delta;
-
-    testSetLogCatTag(LOG_TAG);
-
-    // Parse command line arguments
-    while ((opt = getopt(argc, argv, "vp:d:D:n:s:e:t:?h")) != -1) {
-        switch (opt) {
-          case 'd': // Delay after each set operation
-            perSetDelay = strtod(optarg, &chptr);
-            if ((*chptr != '\0') || (perSetDelay < 0.0)) {
-                testPrintE("Invalid command-line specified per pass delay of: "
-                           "%s", optarg);
-                exit(1);
-            }
-            break;
-
-          case 'D': // End of test delay
-                    // Delay between completion of final pass and restart
-                    // of framework
-            endDelay = strtod(optarg, &chptr);
-            if ((*chptr != '\0') || (endDelay < 0.0)) {
-                testPrintE("Invalid command-line specified end of test delay "
-                           "of: %s", optarg);
-                exit(2);
-            }
-            break;
-
-          case 't': // Duration
-            duration = strtod(optarg, &chptr);
-            if ((*chptr != '\0') || (duration < 0.0)) {
-                testPrintE("Invalid command-line specified duration of: %s",
-                           optarg);
-                exit(3);
-            }
-            break;
-
-          case 'n': // Num set operations per pass
-            numSet = strtoul(optarg, &chptr, 10);
-            if (*chptr != '\0') {
-                testPrintE("Invalid command-line specified num set per pass "
-                           "of: %s", optarg);
-                exit(4);
-            }
-            break;
-
-          case 's': // Starting Pass
-            sFlag = true;
-            if (pFlag) {
-                testPrintE("Invalid combination of command-line options.");
-                testPrintE("  The -p option is mutually exclusive from the");
-                testPrintE("  -s and -e options.");
-                exit(5);
-            }
-            startPass = strtoul(optarg, &chptr, 10);
-            if (*chptr != '\0') {
-                testPrintE("Invalid command-line specified starting pass "
-                           "of: %s", optarg);
-                exit(6);
-            }
-            break;
-
-          case 'e': // Ending Pass
-            eFlag = true;
-            if (pFlag) {
-                testPrintE("Invalid combination of command-line options.");
-                testPrintE("  The -p option is mutually exclusive from the");
-                testPrintE("  -s and -e options.");
-                exit(7);
-            }
-            endPass = strtoul(optarg, &chptr, 10);
-            if (*chptr != '\0') {
-                testPrintE("Invalid command-line specified ending pass "
-                           "of: %s", optarg);
-                exit(8);
-            }
-            break;
-
-          case 'p': // Run a single specified pass
-            pFlag = true;
-            if (sFlag || eFlag) {
-                testPrintE("Invalid combination of command-line options.");
-                testPrintE("  The -p option is mutually exclusive from the");
-                testPrintE("  -s and -e options.");
-                exit(9);
-            }
-            startPass = endPass = strtoul(optarg, &chptr, 10);
-            if (*chptr != '\0') {
-                testPrintE("Invalid command-line specified pass of: %s",
-                           optarg);
-                exit(10);
-            }
-            break;
-
-          case 'v': // Verbose
-            verbose = true;
-            break;
-
-          case 'h': // Help
-          case '?':
-          default:
-            testPrintE("  %s [options]", basename(argv[0]));
-            testPrintE("    options:");
-            testPrintE("      -p Execute specified pass");
-            testPrintE("      -s Starting pass");
-            testPrintE("      -e Ending pass");
-            testPrintE("      -t Duration");
-            testPrintE("      -d Delay after each set operation");
-            testPrintE("      -D End of test delay");
-            testPrintE("      -n Num set operations per pass");
-            testPrintE("      -v Verbose");
-            exit(((optopt == 0) || (optopt == '?')) ? 0 : 11);
-        }
-    }
-    if (endPass < startPass) {
-        testPrintE("Unexpected ending pass before starting pass");
-        testPrintE("  startPass: %u endPass: %u", startPass, endPass);
-        exit(12);
-    }
-    if (argc != optind) {
-        testPrintE("Unexpected command-line postional argument");
-        testPrintE("  %s [-s start_pass] [-e end_pass] [-t duration]",
-            basename(argv[0]));
-        exit(13);
-    }
-    testPrintI("duration: %g", duration);
-    testPrintI("startPass: %u", startPass);
-    testPrintI("endPass: %u", endPass);
-    testPrintI("numSet: %u", numSet);
-
-    // Stop framework
-    rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK);
-    if (rv >= (signed) sizeof(cmd) - 1) {
-        testPrintE("Command too long for: %s", CMD_STOP_FRAMEWORK);
-        exit(14);
-    }
-    execCmd(cmd);
-    testDelay(1.0); // TODO - needs means to query whether asyncronous stop
-                    // framework operation has completed.  For now, just wait
-                    // a long time.
-
-    init();
-
-    // For each pass
-    gettimeofday(&startTime, NULL);
-    for (pass = startPass; pass <= endPass; pass++) {
-        // Stop if duration of work has already been performed
-        gettimeofday(&currentTime, NULL);
-        delta = tvDelta(&startTime, &currentTime);
-        if (tv2double(&delta) > duration) { break; }
-
-        // Regenerate a new set of test frames when this pass is
-        // either the first pass or is in a different group then
-        // the previous pass.  A group of passes are passes that
-        // all have the same quotient when their pass number is
-        // divided by passesPerGroup.
-        if ((pass == startPass)
-            || ((pass / passesPerGroup) != ((pass - 1) / passesPerGroup))) {
-            initFrames(pass / passesPerGroup);
-        }
-
-        testPrintI("==== Starting pass: %u", pass);
-
-        // Cause deterministic sequence of prandom numbers to be
-        // generated for this pass.
-        srand48(pass);
-
-        hwc_layer_list_t *list;
-        list = createLayerList(testRandMod(frames.size()) + 1);
-        if (list == NULL) {
-            testPrintE("createLayerList failed");
-            exit(20);
-        }
-
-        // Prandomly select a subset of frames to be used by this pass.
-        vector <vector <sp<GraphicBuffer> > > selectedFrames;
-        selectedFrames = vectorRandSelect(frames, list->numHwLayers);
-
-        // Any transform tends to create a layer that the hardware
-        // composer is unable to support and thus has to leave for
-        // SurfaceFlinger.  Place heavy bias on specifying no transforms.
-        bool noTransform = testRandFract() > rareRatio;
-
-        for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) {
-            unsigned int idx = testRandMod(selectedFrames[n1].size());
-            sp<GraphicBuffer> gBuf = selectedFrames[n1][idx];
-            hwc_layer_t *layer = &list->hwLayers[n1];
-            layer->handle = gBuf->handle;
-
-            layer->blending = blendingOps[testRandMod(NUMA(blendingOps))];
-            layer->flags = (testRandFract() > rareRatio) ? 0
-                : vectorOr(vectorRandSelect(vecLayerFlags,
-                           testRandMod(vecLayerFlags.size() + 1)));
-            layer->transform = (noTransform || testRandFract() > rareRatio) ? 0
-                : vectorOr(vectorRandSelect(vecTransformFlags,
-                           testRandMod(vecTransformFlags.size() + 1)));
-            layer->sourceCrop.left = testRandMod(gBuf->getWidth());
-            layer->sourceCrop.top = testRandMod(gBuf->getHeight());
-            layer->sourceCrop.right = layer->sourceCrop.left
-                + testRandMod(gBuf->getWidth() - layer->sourceCrop.left) + 1;
-            layer->sourceCrop.bottom = layer->sourceCrop.top
-                + testRandMod(gBuf->getHeight() - layer->sourceCrop.top) + 1;
-            layer->displayFrame.left = testRandMod(width);
-            layer->displayFrame.top = testRandMod(height);
-            layer->displayFrame.right = layer->displayFrame.left
-                + testRandMod(width - layer->displayFrame.left) + 1;
-            layer->displayFrame.bottom = layer->displayFrame.top
-                + testRandMod(height - layer->displayFrame.top) + 1;
-
-            // Increase the frequency that a scale factor of 1.0 from
-            // the sourceCrop to displayFrame occurs.  This is the
-            // most common scale factor used by applications and would
-            // be rarely produced by this stress test without this
-            // logic.
-            if (testRandFract() <= freqRatio) {
-                // Only change to scale factor to 1.0 if both the
-                // width and height will fit.
-                int sourceWidth = layer->sourceCrop.right
-                                  - layer->sourceCrop.left;
-                int sourceHeight = layer->sourceCrop.bottom
-                                   - layer->sourceCrop.top;
-                if (((layer->displayFrame.left + sourceWidth) <= width)
-                    && ((layer->displayFrame.top + sourceHeight) <= height)) {
-                    layer->displayFrame.right = layer->displayFrame.left
-                                                + sourceWidth;
-                    layer->displayFrame.bottom = layer->displayFrame.top
-                                                 + sourceHeight;
-                }
-            }
-
-            layer->visibleRegionScreen.numRects = 1;
-            layer->visibleRegionScreen.rects = &layer->displayFrame;
-        }
-
-        // Perform prepare operation
-        if (verbose) { testPrintI("Prepare:"); displayList(list); }
-        hwcDevice->prepare(hwcDevice, list);
-        if (verbose) {
-            testPrintI("Post Prepare:");
-            displayListPrepareModifiable(list);
-        }
-
-        // Turn off the geometry changed flag
-        list->flags &= ~HWC_GEOMETRY_CHANGED;
-
-        // Perform the set operation(s)
-        if (verbose) {testPrintI("Set:"); }
-        for (unsigned int n1 = 0; n1 < numSet; n1++) {
-            if (verbose) {displayListHandles(list); }
-            hwcDevice->set(hwcDevice, dpy, surface, list);
-
-            // Prandomly select a new set of handles
-            for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) {
-                unsigned int idx = testRandMod(selectedFrames[n1].size());
-                sp<GraphicBuffer> gBuf = selectedFrames[n1][idx];
-                hwc_layer_t *layer = &list->hwLayers[n1];
-                layer->handle = (native_handle_t *) gBuf->handle;
-            }
-
-            testDelay(perSetDelay);
-        }
-
-
-        freeLayerList(list);
-        testPrintI("==== Completed pass: %u", pass);
-    }
-
-    testDelay(endDelay);
-
-    // Start framework
-    rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK);
-    if (rv >= (signed) sizeof(cmd) - 1) {
-        testPrintE("Command too long for: %s", CMD_START_FRAMEWORK);
-        exit(21);
-    }
-    execCmd(cmd);
-
-    testPrintI("Successfully completed %u passes", pass - startPass);
-
-    return 0;
-}
-
-/*
- * Execute Command
- *
- * Executes the command pointed to by cmd.  Output from the
- * executed command is captured and sent to LogCat Info.  Once
- * the command has finished execution, it's exit status is captured
- * and checked for an exit status of zero.  Any other exit status
- * causes diagnostic information to be printed and an immediate
- * testcase failure.
- */
-static void execCmd(const char *cmd)
-{
-    FILE *fp;
-    int rv;
-    int status;
-    char str[MAXSTR];
-
-    // Display command to be executed
-    testPrintI("cmd: %s", cmd);
-
-    // Execute the command
-    fflush(stdout);
-    if ((fp = popen(cmd, "r")) == NULL) {
-        testPrintE("execCmd popen failed, errno: %i", errno);
-        exit(30);
-    }
-
-    // Obtain and display each line of output from the executed command
-    while (fgets(str, sizeof(str), fp) != NULL) {
-        if ((strlen(str) > 1) && (str[strlen(str) - 1] == '\n')) {
-            str[strlen(str) - 1] = '\0';
-        }
-        testPrintI(" out: %s", str);
-    }
-
-    // Obtain and check return status of executed command.
-    // Fail on non-zero exit status
-    status = pclose(fp);
-    if (!(WIFEXITED(status) && (WEXITSTATUS(status) == 0))) {
-        testPrintE("Unexpected command failure");
-        testPrintE("  status: %#x", status);
-        if (WIFEXITED(status)) {
-            testPrintE("WEXITSTATUS: %i", WEXITSTATUS(status));
-        }
-        if (WIFSIGNALED(status)) {
-            testPrintE("WTERMSIG: %i", WTERMSIG(status));
-        }
-        exit(31);
-    }
-}
-
-static void checkEglError(const char* op, EGLBoolean returnVal) {
-    if (returnVal != EGL_TRUE) {
-        testPrintE("%s() returned %d", op, returnVal);
-    }
-
-    for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
-            = eglGetError()) {
-        testPrintE("after %s() eglError %s (0x%x)",
-                   op, EGLUtils::strerror(error), error);
-    }
-}
-
-static void checkGlError(const char* op) {
-    for (GLint error = glGetError(); error; error
-            = glGetError()) {
-        testPrintE("after %s() glError (0x%x)", op, error);
-    }
-}
-
-static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
-
-#define X(VAL) {VAL, #VAL}
-    struct {EGLint attribute; const char* name;} names[] = {
-    X(EGL_BUFFER_SIZE),
-    X(EGL_ALPHA_SIZE),
-    X(EGL_BLUE_SIZE),
-    X(EGL_GREEN_SIZE),
-    X(EGL_RED_SIZE),
-    X(EGL_DEPTH_SIZE),
-    X(EGL_STENCIL_SIZE),
-    X(EGL_CONFIG_CAVEAT),
-    X(EGL_CONFIG_ID),
-    X(EGL_LEVEL),
-    X(EGL_MAX_PBUFFER_HEIGHT),
-    X(EGL_MAX_PBUFFER_PIXELS),
-    X(EGL_MAX_PBUFFER_WIDTH),
-    X(EGL_NATIVE_RENDERABLE),
-    X(EGL_NATIVE_VISUAL_ID),
-    X(EGL_NATIVE_VISUAL_TYPE),
-    X(EGL_SAMPLES),
-    X(EGL_SAMPLE_BUFFERS),
-    X(EGL_SURFACE_TYPE),
-    X(EGL_TRANSPARENT_TYPE),
-    X(EGL_TRANSPARENT_RED_VALUE),
-    X(EGL_TRANSPARENT_GREEN_VALUE),
-    X(EGL_TRANSPARENT_BLUE_VALUE),
-    X(EGL_BIND_TO_TEXTURE_RGB),
-    X(EGL_BIND_TO_TEXTURE_RGBA),
-    X(EGL_MIN_SWAP_INTERVAL),
-    X(EGL_MAX_SWAP_INTERVAL),
-    X(EGL_LUMINANCE_SIZE),
-    X(EGL_ALPHA_MASK_SIZE),
-    X(EGL_COLOR_BUFFER_TYPE),
-    X(EGL_RENDERABLE_TYPE),
-    X(EGL_CONFORMANT),
-   };
-#undef X
-
-    for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
-        EGLint value = -1;
-        EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
-        EGLint error = eglGetError();
-        if (returnVal && error == EGL_SUCCESS) {
-            testPrintI(" %s: %d (%#x)", names[j].name, value, value);
-        }
-    }
-    testPrintI("");
-}
-
-static void printGLString(const char *name, GLenum s)
-{
-    const char *v = (const char *) glGetString(s);
-
-    if (v == NULL) {
-        testPrintI("GL %s unknown", name);
-    } else {
-        testPrintI("GL %s = %s", name, v);
-    }
-}
-
-/*
- * createLayerList
- * dynamically creates layer list with numLayers worth
- * of hwLayers entries.
- */
-static hwc_layer_list_t *createLayerList(size_t numLayers)
-{
-    hwc_layer_list_t *list;
-
-    size_t size = sizeof(hwc_layer_list) + numLayers * sizeof(hwc_layer_t);
-    if ((list = (hwc_layer_list_t *) calloc(1, size)) == NULL) {
-        return NULL;
-    }
-    list->flags = HWC_GEOMETRY_CHANGED;
-    list->numHwLayers = numLayers;
-
-    return list;
-}
-
-/*
- * freeLayerList
- * Frees memory previous allocated via createLayerList().
- */
-static void freeLayerList(hwc_layer_list_t *list)
-{
-    free(list);
-}
-
-static void fillColor(GraphicBuffer *gBuf, RGBColor color, float trans)
-{
-    unsigned char* buf = NULL;
-    status_t err;
-    uint32_t pixel;
-
-    // RGB 2 YUV conversion ratios
-    const struct rgb2yuvRatios {
-        int format;
-        float weightRed;
-        float weightBlu;
-        float weightGrn;
-    } rgb2yuvRatios[] = {
-        { HAL_PIXEL_FORMAT_YV12, 0.299, 0.114, 0.587 },
-    };
-
-    const struct rgbAttrib {
-        int format;
-        bool   hostByteOrder;
-        size_t bytes;
-        size_t rOffset;
-        size_t rSize;
-        size_t gOffset;
-        size_t gSize;
-        size_t bOffset;
-        size_t bSize;
-        size_t aOffset;
-        size_t aSize;
-    } rgbAttributes[] = {
-        {HAL_PIXEL_FORMAT_RGBA_8888, false, 4,  0, 8,  8, 8, 16, 8, 24, 8},
-        {HAL_PIXEL_FORMAT_RGBX_8888, false, 4,  0, 8,  8, 8, 16, 8,  0, 0},
-        {HAL_PIXEL_FORMAT_RGB_888,   false, 3,  0, 8,  8, 8, 16, 8,  0, 0},
-        {HAL_PIXEL_FORMAT_RGB_565,   true,  2,  0, 5,  5, 6, 11, 5,  0, 0},
-        {HAL_PIXEL_FORMAT_BGRA_8888, false, 4, 16, 8,  8, 8,  0, 8, 24, 8},
-        {HAL_PIXEL_FORMAT_RGBA_5551, true , 2,  0, 5,  5, 5, 10, 5, 15, 1},
-        {HAL_PIXEL_FORMAT_RGBA_4444, false, 2, 12, 4,  0, 4,  4, 4,  8, 4},
-    };
-
-    // If YUV format, convert color and pass work to YUV color fill
-    for (unsigned int n1 = 0; n1 < NUMA(rgb2yuvRatios); n1++) {
-        if (gBuf->getPixelFormat() == rgb2yuvRatios[n1].format) {
-            float wr = rgb2yuvRatios[n1].weightRed;
-            float wb = rgb2yuvRatios[n1].weightBlu;
-            float wg = rgb2yuvRatios[n1].weightGrn;
-            float y = wr * color.r() + wb * color.b() + wg * color.g();
-            float u = 0.5 * ((color.b() - y) / (1 - wb)) + 0.5;
-            float v = 0.5 * ((color.r() - y) / (1 - wr)) + 0.5;
-            YUVColor yuvColor(y, u, v);
-            fillColor(gBuf, yuvColor, trans);
-            return;
-        }
-    }
-
-    const struct rgbAttrib *attrib;
-    for (attrib = rgbAttributes; attrib < rgbAttributes + NUMA(rgbAttributes);
-         attrib++) {
-        if (attrib->format == gBuf->getPixelFormat()) { break; }
-    }
-    if (attrib >= rgbAttributes + NUMA(rgbAttributes)) {
-        testPrintE("fillColor rgb unsupported format of: %u",
-        gBuf->getPixelFormat());
-        exit(50);
-    }
-
-    pixel = htonl((uint32_t) (((1 << attrib->rSize) - 1) * color.r())
-         << ((sizeof(pixel) * BITSPERBYTE)
-             - (attrib->rOffset + attrib->rSize)));
-    pixel |= htonl((uint32_t) (((1 << attrib->gSize) - 1) * color.g())
-         << ((sizeof(pixel) * BITSPERBYTE)
-             - (attrib->gOffset + attrib->gSize)));
-    pixel |= htonl((uint32_t) (((1 << attrib->bSize) - 1) * color.b())
-         << ((sizeof(pixel) * BITSPERBYTE)
-             - (attrib->bOffset + attrib->bSize)));
-    if (attrib->aSize) {
-        pixel |= htonl((uint32_t) (((1 << attrib->aSize) - 1) * trans)
-             << ((sizeof(pixel) * BITSPERBYTE)
-                 - (attrib->aOffset + attrib->aSize)));
-    }
-    if (attrib->hostByteOrder) {
-        pixel = ntohl(pixel);
-        pixel >>= sizeof(pixel) * BITSPERBYTE - attrib->bytes * BITSPERBYTE;
-    }
-
-    err = gBuf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf));
-    if (err != 0) {
-        testPrintE("fillColor rgb lock failed: %d", err);
-        exit(51);
-    }
-
-    for (unsigned int row = 0; row < gBuf->getHeight(); row++) {
-        for (unsigned int col = 0; col < gBuf->getWidth(); col++) {
-          memmove(buf, &pixel, attrib->bytes);
-          buf += attrib->bytes;
-        }
-        for (unsigned int pad = 0;
-             pad < (gBuf->getStride() - gBuf->getWidth()) * attrib->bytes;
-             pad++) {
-            *buf++ = testRandMod(256);
-        }
-    }
-
-    err = gBuf->unlock();
-    if (err != 0) {
-        testPrintE("fillColor rgb unlock failed: %d", err);
-        exit(52);
-    }
-}
-
-static void fillColor(GraphicBuffer *gBuf, YUVColor color, float trans)
-{
-    unsigned char* buf = NULL;
-    status_t err;
-    unsigned int width = gBuf->getWidth();
-    unsigned int height = gBuf->getHeight();
-
-    const struct yuvAttrib {
-        int format;
-        bool   planar;
-        unsigned int uSubSampX;
-        unsigned int uSubSampY;
-        unsigned int vSubSampX;
-        unsigned int vSubSampY;
-    } yuvAttributes[] = {
-        { HAL_PIXEL_FORMAT_YV12, true, 2, 2, 2, 2},
-    };
-
-    const struct yuvAttrib *attrib;
-    for (attrib = yuvAttributes; attrib < yuvAttributes + NUMA(yuvAttributes);
-         attrib++) {
-        if (attrib->format == gBuf->getPixelFormat()) { break; }
-    }
-    if (attrib >= yuvAttributes + NUMA(yuvAttributes)) {
-        testPrintE("fillColor yuv unsupported format of: %u",
-        gBuf->getPixelFormat());
-        exit(60);
-    }
-
-    assert(attrib->planar == true); // So far, only know how to handle planar
-
-    err = gBuf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf));
-    if (err != 0) {
-        testPrintE("fillColor lock failed: %d", err);
-        exit(61);
-    }
-
-    // Fill in Y component
-    for (unsigned int row = 0; row < height; row++) {
-        for (unsigned int col = 0; col < width; col++) {
-            *buf++ = 255 * color.y();
-        }
-        for (unsigned int pad = 0; pad < gBuf->getStride() - gBuf->getWidth();
-             pad++) {
-             *buf++ = testRandMod(256);
-        }
-    }
-
-    // Fill in U component
-    for (unsigned int row = 0; row < height; row += attrib->uSubSampY) {
-        for (unsigned int col = 0; col < width; col += attrib->uSubSampX) {
-            *buf++ = 255 * color.u();
-        }
-        for (unsigned int pad = 0; pad < gBuf->getStride() - gBuf->getWidth();
-             pad += attrib->uSubSampX) {
-            *buf++ = testRandMod(256);
-        }
-    }
-
-    // Fill in V component
-    for (unsigned int row = 0; row < height; row += attrib->vSubSampY) {
-        for (unsigned int col = 0; col < width; col += attrib->vSubSampX) {
-            *buf++ = 255 * color.v();
-        }
-        for (unsigned int pad = 0; pad < gBuf->getStride() - gBuf->getWidth();
-             pad += attrib->vSubSampX) {
-            *buf++ = testRandMod(256);
-        }
-    }
-
-    err = gBuf->unlock();
-    if (err != 0) {
-        testPrintE("fillColor unlock failed: %d", err);
-        exit(62);
-    }
-}
-
-void init(void)
-{
-    int rv;
-
-    EGLBoolean returnValue;
-    EGLConfig myConfig = {0};
-    EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
-    EGLint sConfigAttribs[] = {
-        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
-        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-        EGL_NONE };
-    EGLint majorVersion, minorVersion;
-
-    checkEglError("<init>");
-    dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    checkEglError("eglGetDisplay");
-    if (dpy == EGL_NO_DISPLAY) {
-        testPrintE("eglGetDisplay returned EGL_NO_DISPLAY");
-        exit(70);
-    }
-
-    returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
-    checkEglError("eglInitialize", returnValue);
-    testPrintI("EGL version %d.%d", majorVersion, minorVersion);
-    if (returnValue != EGL_TRUE) {
-        testPrintE("eglInitialize failed");
-        exit(71);
-    }
-
-    EGLNativeWindowType window = android_createDisplaySurface();
-    if (window == NULL) {
-        testPrintE("android_createDisplaySurface failed");
-        exit(72);
-    }
-    returnValue = EGLUtils::selectConfigForNativeWindow(dpy,
-        sConfigAttribs, window, &myConfig);
-    if (returnValue) {
-        testPrintE("EGLUtils::selectConfigForNativeWindow() returned %d",
-            returnValue);
-        exit(73);
-    }
-    checkEglError("EGLUtils::selectConfigForNativeWindow");
-
-    testPrintI("Chose this configuration:");
-    printEGLConfiguration(dpy, myConfig);
-
-    surface = eglCreateWindowSurface(dpy, myConfig, window, NULL);
-    checkEglError("eglCreateWindowSurface");
-    if (surface == EGL_NO_SURFACE) {
-        testPrintE("gelCreateWindowSurface failed.");
-        exit(74);
-    }
-
-    context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, contextAttribs);
-    checkEglError("eglCreateContext");
-    if (context == EGL_NO_CONTEXT) {
-        testPrintE("eglCreateContext failed");
-        exit(75);
-    }
-    returnValue = eglMakeCurrent(dpy, surface, surface, context);
-    checkEglError("eglMakeCurrent", returnValue);
-    if (returnValue != EGL_TRUE) {
-        testPrintE("eglMakeCurrent failed");
-        exit(76);
-    }
-    eglQuerySurface(dpy, surface, EGL_WIDTH, &width);
-    checkEglError("eglQuerySurface");
-    eglQuerySurface(dpy, surface, EGL_HEIGHT, &height);
-    checkEglError("eglQuerySurface");
-
-    testPrintI("Window dimensions: %d x %d", width, height);
-
-    printGLString("Version", GL_VERSION);
-    printGLString("Vendor", GL_VENDOR);
-    printGLString("Renderer", GL_RENDERER);
-    printGLString("Extensions", GL_EXTENSIONS);
-
-    if ((rv = hw_get_module(HWC_HARDWARE_MODULE_ID, &hwcModule)) != 0) {
-        testPrintE("hw_get_module failed, rv: %i", rv);
-        errno = -rv;
-        perror(NULL);
-        exit(77);
-    }
-    if ((rv = hwc_open(hwcModule, &hwcDevice)) != 0) {
-        testPrintE("hwc_open failed, rv: %i", rv);
-        errno = -rv;
-        perror(NULL);
-        exit(78);
-    }
-
-    testPrintI("");
-}
-
-/*
- * Initialize Frames
- *
- * Creates an array of graphic buffers, within the global variable
- * named frames.  The graphic buffers are contained within a vector of
- * vectors.  All the graphic buffers in a particular row are of the same
- * format and dimension.  Each graphic buffer is uniformly filled with a
- * prandomly selected color.  It is likely that each buffer, even
- * in the same row, will be filled with a unique color.
- */
-void initFrames(unsigned int seed)
-{
-    int rv;
-    const size_t maxRows = 5;
-    const size_t minCols = 2;  // Need at least double buffering
-    const size_t maxCols = 4;  // One more than triple buffering
-
-    if (verbose) { testPrintI("initFrames seed: %u", seed); }
-    srand48(seed);
-    size_t rows = testRandMod(maxRows) + 1;
-
-    frames.clear();
-    frames.resize(rows);
-
-    for (unsigned int row = 0; row < rows; row++) {
-        // All frames within a row have to have the same format and
-        // dimensions.  Width and height need to be >= 1.
-        unsigned int formatIdx = testRandMod(NUMA(graphicFormat));
-        const struct graphicFormat *formatPtr = &graphicFormat[formatIdx];
-        int format = formatPtr->format;
-
-        // Pick width and height, which must be >= 1 and the size
-        // mod the wMod/hMod value must be equal to 0.
-        size_t w = (width * maxSizeRatio) * testRandFract();
-        size_t h = (height * maxSizeRatio) * testRandFract();
-        w = max(1u, w);
-        h = max(1u, h);
-        if ((w % formatPtr->wMod) != 0) {
-            w += formatPtr->wMod - (w % formatPtr->wMod);
-        }
-        if ((h % formatPtr->hMod) != 0) {
-            h += formatPtr->hMod - (h % formatPtr->hMod);
-        }
-        if (verbose) {
-            testPrintI("  frame %u width: %u height: %u format: %u %s",
-                       row, w, h, format, graphicFormat2str(format));
-        }
-
-        size_t cols = testRandMod((maxCols + 1) - minCols) + minCols;
-        frames[row].resize(cols);
-        for (unsigned int col = 0; col < cols; col++) {
-            RGBColor color(testRandFract(), testRandFract(), testRandFract());
-            float transp = testRandFract();
-
-            frames[row][col] = new GraphicBuffer(w, h, format, texUsage);
-            if ((rv = frames[row][col]->initCheck()) != NO_ERROR) {
-                testPrintE("GraphicBuffer initCheck failed, rv: %i", rv);
-                testPrintE("  frame %u width: %u height: %u format: %u %s",
-                           row, w, h, format, graphicFormat2str(format));
-                exit(80);
-            }
-
-            fillColor(frames[row][col].get(), color, transp);
-            if (verbose) {
-                testPrintI("    buf: %p handle: %p color: <%f, %f, %f> "
-                           "transp: %f",
-                           frames[row][col].get(), frames[row][col]->handle,
-                           color.r(), color.g(), color.b(), transp);
-            }
-        }
-    }
-}
-
-void displayList(hwc_layer_list_t *list)
-{
-    testPrintI("  flags: %#x%s", list->flags,
-               (list->flags & HWC_GEOMETRY_CHANGED) ? " GEOMETRY_CHANGED" : "");
-    testPrintI("  numHwLayers: %u", list->numHwLayers);
-
-    for (unsigned int layer = 0; layer < list->numHwLayers; layer++) {
-        testPrintI("    layer %u compositionType: %#x%s%s", layer,
-                   list->hwLayers[layer].compositionType,
-                   (list->hwLayers[layer].compositionType == HWC_FRAMEBUFFER)
-                       ? " FRAMEBUFFER" : "",
-                   (list->hwLayers[layer].compositionType == HWC_OVERLAY)
-                       ? " OVERLAY" : "");
-
-        testPrintI("      hints: %#x",
-                   list->hwLayers[layer].hints,
-                   (list->hwLayers[layer].hints & HWC_HINT_TRIPLE_BUFFER)
-                       ? " TRIPLE_BUFFER" : "",
-                   (list->hwLayers[layer].hints & HWC_HINT_CLEAR_FB)
-                       ? " CLEAR_FB" : "");
-
-        testPrintI("      flags: %#x%s",
-                   list->hwLayers[layer].flags,
-                   (list->hwLayers[layer].flags & HWC_SKIP_LAYER)
-                       ? " SKIP_LAYER" : "");
-
-        testPrintI("      handle: %p",
-                   list->hwLayers[layer].handle);
-
-        // Intentionally skipped display of ROT_180 & ROT_270,
-        // which are formed from combinations of the other flags.
-        testPrintI("      transform: %#x%s%s%s",
-                   list->hwLayers[layer].transform,
-                   (list->hwLayers[layer].transform & HWC_TRANSFORM_FLIP_H)
-                       ? " FLIP_H" : "",
-                   (list->hwLayers[layer].transform & HWC_TRANSFORM_FLIP_V)
-                       ? " FLIP_V" : "",
-                   (list->hwLayers[layer].transform & HWC_TRANSFORM_ROT_90)
-                       ? " ROT_90" : "");
-
-        testPrintI("      blending: %#x",
-                   list->hwLayers[layer].blending,
-                   (list->hwLayers[layer].blending == HWC_BLENDING_NONE)
-                       ? " NONE" : "",
-                   (list->hwLayers[layer].blending == HWC_BLENDING_PREMULT)
-                       ? " PREMULT" : "",
-                   (list->hwLayers[layer].blending == HWC_BLENDING_COVERAGE)
-                       ? " COVERAGE" : "");
-
-        testPrintI("      sourceCrop: [%i, %i, %i, %i]",
-                   list->hwLayers[layer].sourceCrop.left,
-                   list->hwLayers[layer].sourceCrop.top,
-                   list->hwLayers[layer].sourceCrop.right,
-                   list->hwLayers[layer].sourceCrop.bottom);
-
-        testPrintI("      displayFrame: [%i, %i, %i, %i]",
-                   list->hwLayers[layer].displayFrame.left,
-                   list->hwLayers[layer].displayFrame.top,
-                   list->hwLayers[layer].displayFrame.right,
-                   list->hwLayers[layer].displayFrame.bottom);
-        testPrintI("      scaleFactor: [%f %f]",
-                   (float) (list->hwLayers[layer].displayFrame.right
-                            - list->hwLayers[layer].displayFrame.left)
-                       / (float) (list->hwLayers[layer].sourceCrop.right
-                            - list->hwLayers[layer].sourceCrop.left),
-                   (float) (list->hwLayers[layer].displayFrame.bottom
-                            - list->hwLayers[layer].displayFrame.top)
-                       / (float) (list->hwLayers[layer].sourceCrop.bottom
-                            - list->hwLayers[layer].sourceCrop.top));
-    }
-}
-
-/*
- * Display List Prepare Modifiable
- *
- * Displays the portions of a list that are meant to be modified by
- * a prepare call.
- */
-void displayListPrepareModifiable(hwc_layer_list_t *list)
-{
-    for (unsigned int layer = 0; layer < list->numHwLayers; layer++) {
-        testPrintI("    layer %u compositionType: %#x%s%s", layer,
-                   list->hwLayers[layer].compositionType,
-                   (list->hwLayers[layer].compositionType == HWC_FRAMEBUFFER)
-                       ? " FRAMEBUFFER" : "",
-                   (list->hwLayers[layer].compositionType == HWC_OVERLAY)
-                       ? " OVERLAY" : "");
-        testPrintI("      hints: %#x%s%s",
-                   list->hwLayers[layer].hints,
-                   (list->hwLayers[layer].hints & HWC_HINT_TRIPLE_BUFFER)
-                       ? " TRIPLE_BUFFER" : "",
-                   (list->hwLayers[layer].hints & HWC_HINT_CLEAR_FB)
-                       ? " CLEAR_FB" : "");
-    }
-}
-
-/*
- * Display List Handles
- *
- * Displays the handles of all the graphic buffers in the list.
- */
-void displayListHandles(hwc_layer_list_t *list)
-{
-    const unsigned int maxLayersPerLine = 6;
-
-    ostringstream str("  layers:");
-    for (unsigned int layer = 0; layer < list->numHwLayers; layer++) {
-        str << ' ' << list->hwLayers[layer].handle;
-        if (((layer % maxLayersPerLine) == (maxLayersPerLine - 1))
-            && (layer != list->numHwLayers - 1)) {
-            testPrintI("%s", str.str().c_str());
-            str.str("    ");
-        }
-    }
-    testPrintI("%s", str.str().c_str());
-}
-
-const char *graphicFormat2str(unsigned int format)
-{
-    const static char *unknown = "unknown";
-
-    for (unsigned int n1 = 0; n1 < NUMA(graphicFormat); n1++) {
-        if (format == graphicFormat[n1].format) {
-            return graphicFormat[n1].desc;
-        }
-    }
-
-    return unknown;
-}
-
-/*
- * Vector Random Select
- *
- * Prandomly selects and returns num elements from vec.
- */
-template <class T>
-vector<T> vectorRandSelect(const vector<T>& vec, size_t num)
-{
-    vector<T> rv = vec;
-
-    while (rv.size() > num) {
-        rv.erase(rv.begin() + testRandMod(rv.size()));
-    }
-
-    return rv;
-}
-
-/*
- * Vector Or
- *
- * Or's togethen the values of each element of vec and returns the result.
- */
-template <class T>
-T vectorOr(const vector<T>& vec)
-{
-    T rv = 0;
-
-    for (size_t n1 = 0; n1 < vec.size(); n1++) {
-        rv |= vec[n1];
-    }
-
-    return rv;
-}
diff --git a/opengl/tests/include/glTestLib.h b/opengl/tests/include/glTestLib.h
new file mode 100644
index 0000000..06fbf5d
--- /dev/null
+++ b/opengl/tests/include/glTestLib.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ * Graphics Test Library Header
+ */
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+//#include <ui/FramebufferNativeWindow.h>
+//#include <ui/GraphicBuffer.h>
+#include <ui/EGLUtils.h>
+
+void glTestPrintGLString(const char *name, GLenum s);
+void glTestCheckEglError(const char* op, EGLBoolean returnVal = EGL_TRUE);
+void glTestCheckGlError(const char* op);
+void glTestPrintEGLConfiguration(EGLDisplay dpy, EGLConfig config);
diff --git a/opengl/tests/lib/Android.mk b/opengl/tests/lib/Android.mk
new file mode 100644
index 0000000..7542ac4
--- /dev/null
+++ b/opengl/tests/lib/Android.mk
@@ -0,0 +1,32 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE:= libglTest
+LOCAL_SRC_FILES:= glTestLib.cpp
+LOCAL_C_INCLUDES += system/extras/tests/include \
+    bionic \
+    bionic/libstdc++/include \
+    external/stlport/stlport \
+    frameworks/base/opengl/tests/include \
+
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
+LOCAL_SHARED_LIBRARIES += libcutils libutils libstlport
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/opengl/tests/lib/glTestLib.cpp b/opengl/tests/lib/glTestLib.cpp
new file mode 100644
index 0000000..052cbd7
--- /dev/null
+++ b/opengl/tests/lib/glTestLib.cpp
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ * Graphics Test Library
+ */
+
+#include <glTestLib.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <ui/EGLUtils.h>
+
+#include <utils/Log.h>
+#include <testUtil.h>
+
+using namespace std;
+using namespace android;
+
+void glTestPrintGLString(const char *name, GLenum s)
+{
+    const char *v = (const char *) glGetString(s);
+
+    if (v == NULL) {
+        testPrintI("GL %s unknown", name);
+    } else {
+        testPrintI("GL %s = %s", name, v);
+    }
+}
+
+void glTestCheckEglError(const char* op, EGLBoolean returnVal)
+{
+    if (returnVal != EGL_TRUE) {
+        testPrintE("%s() returned %d", op, returnVal);
+    }
+
+    for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
+            = eglGetError()) {
+        testPrintE("after %s() eglError %s (0x%x)",
+                   op, EGLUtils::strerror(error), error);
+    }
+}
+
+void glTestCheckGlError(const char* op)
+{
+    for (GLint error = glGetError(); error; error
+            = glGetError()) {
+        testPrintE("after %s() glError (0x%x)", op, error);
+    }
+}
+
+void glTestPrintEGLConfiguration(EGLDisplay dpy, EGLConfig config)
+{
+
+#define X(VAL) {VAL, #VAL}
+    struct {EGLint attribute; const char* name;} names[] = {
+    X(EGL_BUFFER_SIZE),
+    X(EGL_ALPHA_SIZE),
+    X(EGL_BLUE_SIZE),
+    X(EGL_GREEN_SIZE),
+    X(EGL_RED_SIZE),
+    X(EGL_DEPTH_SIZE),
+    X(EGL_STENCIL_SIZE),
+    X(EGL_CONFIG_CAVEAT),
+    X(EGL_CONFIG_ID),
+    X(EGL_LEVEL),
+    X(EGL_MAX_PBUFFER_HEIGHT),
+    X(EGL_MAX_PBUFFER_PIXELS),
+    X(EGL_MAX_PBUFFER_WIDTH),
+    X(EGL_NATIVE_RENDERABLE),
+    X(EGL_NATIVE_VISUAL_ID),
+    X(EGL_NATIVE_VISUAL_TYPE),
+    X(EGL_SAMPLES),
+    X(EGL_SAMPLE_BUFFERS),
+    X(EGL_SURFACE_TYPE),
+    X(EGL_TRANSPARENT_TYPE),
+    X(EGL_TRANSPARENT_RED_VALUE),
+    X(EGL_TRANSPARENT_GREEN_VALUE),
+    X(EGL_TRANSPARENT_BLUE_VALUE),
+    X(EGL_BIND_TO_TEXTURE_RGB),
+    X(EGL_BIND_TO_TEXTURE_RGBA),
+    X(EGL_MIN_SWAP_INTERVAL),
+    X(EGL_MAX_SWAP_INTERVAL),
+    X(EGL_LUMINANCE_SIZE),
+    X(EGL_ALPHA_MASK_SIZE),
+    X(EGL_COLOR_BUFFER_TYPE),
+    X(EGL_RENDERABLE_TYPE),
+    X(EGL_CONFORMANT),
+   };
+#undef X
+
+    for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
+        EGLint value = -1;
+        EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute,
+                                              &value);
+        EGLint error = eglGetError();
+        if (returnVal && error == EGL_SUCCESS) {
+            testPrintI(" %s: %d (%#x)", names[j].name, value, value);
+        }
+    }
+    testPrintI("");
+}
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
index 7a419f1..7682bba 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
index 690b5f6c7..1534da3 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/packages/SystemUI/res/values-es-rUS-xlarge-land/strings.xml b/packages/SystemUI/res/values-es-rUS-xlarge-land/strings.xml
new file mode 100644
index 0000000..78a4c18
--- /dev/null
+++ b/packages/SystemUI/res/values-es-rUS-xlarge-land/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- XL -->
+    <string name="toast_rotation_locked" msgid="2686639138967158852">"La pantalla está bloqueada en orientación paisaje."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-es-rUS-xlarge-port/strings.xml b/packages/SystemUI/res/values-es-rUS-xlarge-port/strings.xml
new file mode 100644
index 0000000..9daef6a
--- /dev/null
+++ b/packages/SystemUI/res/values-es-rUS-xlarge-port/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- XL -->
+    <string name="toast_rotation_locked" msgid="4297721709987511908">"La pantalla está bloqueada en orientación retrato."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml b/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml
index bf627f4..f29259a 100644
--- a/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml
@@ -1,26 +1,16 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); 
- * you may not use this file except in compliance with the License. 
- * You may obtain a copy of the License at 
- *
- *     http://www.apache.org/licenses/LICENSE-2.0 
- *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
- * limitations under the License.
- */
- -->
-
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
-    <skip />
-    <string name="status_bar_settings_signal_meter_disconnected" msgid="4684094636492991496">"Sin conexión a Int."</string>
-    <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="1456658018593445677">"WiFi conectado"</string>
+    <!-- XL xlarge -->
+    <string name="status_bar_clear_all_button" msgid="4341545325987974494">"Eliminar todos"</string>
+    <!-- XL -->
+    <string name="status_bar_no_notifications_title" msgid="2492933749414725897">"No tienes notificaciones"</string>
+    <!-- XL -->
+    <string name="status_bar_settings_rotation_lock" msgid="9125161825884157545">"Bloquear orient. de pant."</string>
+    <!-- XL -->
+    <string name="recent_tasks_app_label" msgid="5550538721034982973">"Google Apps"</string>
+    <!-- XL xlarge -->
+    <string name="status_bar_settings_signal_meter_disconnected" msgid="4866302415753953027">"Sin conexión a Internet"</string>
+    <!-- XL xlarge -->
+    <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="3832182580451976589">"Wi-Fi conectado"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-port/strings.xml b/packages/SystemUI/res/values-port/strings.xml
index d3ab67b..67364a4 100644
--- a/packages/SystemUI/res/values-port/strings.xml
+++ b/packages/SystemUI/res/values-port/strings.xml
@@ -17,7 +17,4 @@
  */
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- Rotation lock toast text: shown when rotation lock is turned on in portrait orientation.
-         -->
-    <string name="toast_rotation_locked">Screen is now locked in portrait orientation.</string>
 </resources>
diff --git a/packages/SystemUI/res/values-xlarge/config.xml b/packages/SystemUI/res/values-xlarge/config.xml
index e140914..299ab97 100644
--- a/packages/SystemUI/res/values-xlarge/config.xml
+++ b/packages/SystemUI/res/values-xlarge/config.xml
@@ -24,7 +24,7 @@
 
     <!-- Component to be used as the status bar service.  Must implement the IStatusBar
      interface.  This name is in the ComponentName flattened format (package/class)  -->
-    <string name="config_statusBarComponent">com.android.systemui.statusbar.tablet.TabletStatusBar</string>
+    <string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.tablet.TabletStatusBar</string>
 
     <!-- Whether or not we show the number in the bar. -->
     <bool name="config_statusBarShowNumber">false</bool>
diff --git a/packages/SystemUI/res/values-xlarge/strings.xml b/packages/SystemUI/res/values-xlarge/strings.xml
index 279a135..f7b642d 100644
--- a/packages/SystemUI/res/values-xlarge/strings.xml
+++ b/packages/SystemUI/res/values-xlarge/strings.xml
@@ -18,7 +18,7 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- The text for the button in the notification window-shade that clears
-         all of the currently visible notifications. -->
+         all of the currently visible notifications. [CHAR LIMIT=10]-->
     <string name="status_bar_clear_all_button">Clear all</string>
 
     <!-- System panel ("Quick Settings") -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 9737028..df846f1 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -108,11 +108,4 @@
     <!-- Recent apps label. Shown as title on recent apps panel -->
     <string name="recent_tasks_app_label">Apps</string>
 
-    <!-- Rotation lock toast text: shown when rotation lock is turned off (and the screen will
-         auto-rotate based on the accelerometer).  [CHAR LIMIT=NONE]-->
-    <string name="toast_rotation_free">Screen will rotate automatically.</string>
-    
-    <!-- Rotation lock toast text: shown when rotation lock is turned on and the orientation is
-         undefined.  [CHAR LIMIT=NONE] -->
-    <string name="toast_rotation_locked">Screen rotation is now locked.</string>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
index 3ca1e12..7dcf9be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java
@@ -251,14 +251,11 @@
 
         void startAnimation(boolean visible) {
             if (DEBUG) Slog.d(TAG, "startAnimation(visible=" + visible + ")");
-            if (mBgAnim != null && mVisible != visible) {
-                mBgAnim.reverse();
-                mPositionAnim.reverse();
-            } else {
-                createAnimation(visible);
-                mBgAnim.start();
-                mPositionAnim.start();
-            }
+
+            createAnimation(visible);
+            mBgAnim.start();
+            mPositionAnim.start();
+
             mVisible = visible;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index bfc2aa1..9ddb432 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -1149,7 +1149,11 @@
                     }
                 });
         } else {
-            vetoButton.setVisibility(View.INVISIBLE);
+            if ((sbn.notification.flags & Notification.FLAG_ONGOING_EVENT) == 0) {
+                vetoButton.setVisibility(View.INVISIBLE);
+            } else {
+                vetoButton.setVisibility(View.GONE);
+            }
         }
 
         // the large icon
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index a9d42e3..cff9892 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -20,10 +20,7 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
-import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -91,7 +88,6 @@
 
     private AlarmManager mAlarmManager;
     private PendingIntent mIdleIntent;
-    private BluetoothA2dp mBluetoothA2dp;
     private static final int IDLE_REQUEST = 0;
     private boolean mScreenOff;
     private boolean mDeviceIdle;
@@ -943,10 +939,10 @@
                     mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
                 }
                 mPluggedType = pluggedType;
-            } else if (action.equals(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED)) {
-                int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
-                                               BluetoothA2dp.STATE_NOT_PLAYING);
-                mWifiStateMachine.setBluetoothScanMode(state == BluetoothA2dp.STATE_PLAYING);
+            } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
+                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
+                        BluetoothAdapter.STATE_DISCONNECTED);
+                mWifiStateMachine.sendBluetoothAdapterStateChange(state);
             }
         }
 
@@ -1048,7 +1044,7 @@
         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
         intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
         intentFilter.addAction(ACTION_DEVICE_IDLE);
-        intentFilter.addAction(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED);
+        intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
         mContext.registerReceiver(mReceiver, intentFilter);
     }
 
diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
index e7cfe75..99123af 100644
--- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
@@ -37,6 +37,7 @@
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.StatFs;
+import android.os.SystemProperties;
 import android.provider.Telephony;
 import android.provider.Telephony.Sms.Intents;
 import android.provider.Settings;
@@ -156,8 +157,10 @@
     protected boolean mStorageAvailable = true;
     protected boolean mReportMemoryStatusPending = false;
 
-    /* Flag indicating whether the current device allows sms service */
+    /* Flags indicating whether the current device allows sms service */
     protected boolean mSmsCapable = true;
+    protected boolean mSmsReceiveDisabled;
+    protected boolean mSmsSendDisabled;
 
     protected static int getNextConcatenatedRef() {
         sConcatenatedRef += 1;
@@ -255,6 +258,13 @@
 
         mSmsCapable = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_sms_capable);
+        mSmsReceiveDisabled = !SystemProperties.getBoolean(
+                                TelephonyProperties.PROPERTY_SMS_RECEIVE, mSmsCapable);
+        mSmsSendDisabled = !SystemProperties.getBoolean(
+                                TelephonyProperties.PROPERTY_SMS_SEND, mSmsCapable);
+        Log.d(TAG, "SMSDispatcher: ctor mSmsCapable=" + mSmsCapable
+                + " mSmsReceiveDisabled=" + mSmsReceiveDisabled
+                + " mSmsSendDisabled=" + mSmsSendDisabled);
     }
 
     public void dispose() {
@@ -783,13 +793,13 @@
      */
     protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent,
             PendingIntent deliveryIntent) {
-        if (!mSmsCapable) {
+        if (mSmsSendDisabled) {
             if (sentIntent != null) {
                 try {
                     sentIntent.send(RESULT_ERROR_NO_SERVICE);
                 } catch (CanceledException ex) {}
             }
-            Log.d(TAG, "Device does not support sms service.");
+            Log.d(TAG, "Device does not support sending sms.");
             return;
         }
 
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 136d5b1..e6189be 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -147,4 +147,16 @@
      * when there is a radio technology change.
      */
     static final String PROPERTY_RESET_ON_RADIO_TECH_CHANGE = "persist.radio.reset_on_switch";
+
+    /**
+     * Set to false to disable SMS receiving, default is
+     * the value of config_sms_capable
+     */
+    static final String PROPERTY_SMS_RECEIVE = "telephony.sms.receive";
+
+    /**
+     * Set to false to disable SMS sending, default is
+     * the value of config_sms_capable
+     */
+    static final String PROPERTY_SMS_SEND = "telephony.sms.send";
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index 01234b0..6bd2d09 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -107,10 +107,10 @@
             return Activity.RESULT_OK;
         }
 
-        if (!mSmsCapable) {
-            // Device doesn't support SMS service,
+        if (mSmsReceiveDisabled) {
+            // Device doesn't support receiving SMS,
             Log.d(TAG, "Received short message on device which doesn't support "
-                    + "SMS service. Ignored.");
+                    + "receiving SMS. Ignored.");
             return Intents.RESULT_SMS_HANDLED;
         }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index de15408..17cf36d 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -605,7 +605,11 @@
         // mOperatorAlphaLong contains the ERI text
         String plmn = ss.getOperatorAlphaLong();
         if (!TextUtils.equals(plmn, curPlmn)) {
-            boolean showPlmn = !TextUtils.isEmpty(plmn);
+            // Allow A blank plmn, "" to set showPlmn to true. Previously, we
+            // would set showPlmn to true only if plmn was not empty, i.e. was not
+            // null and not blank. But this would cause us to incorrectly display
+            // "No Service". Now showPlmn is set to true for any non null string.
+            boolean showPlmn = plmn != null;
             Log.d(LOG_TAG,
                     String.format("updateSpnDisplay: changed sending intent" +
                             " showPlmn='%b' plmn='%s'", showPlmn, plmn));
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index 497c552..bbe579d 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -110,7 +110,7 @@
             return Intents.RESULT_SMS_HANDLED;
         }
 
-        if (!mSmsCapable) {
+        if (mSmsReceiveDisabled) {
             // Device doesn't support SMS service,
             Log.d(TAG, "Received short message on device which doesn't support "
                     + "SMS service. Ignored.");
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 61bf33b..0c78952 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -418,7 +418,7 @@
             assert false;
             Bridge.getLog().fidelityWarning(null,
                     "android.graphics.Canvas#setMatrix(android.graphics.Matrix) only " +
-                    "supports affine transformations in the Layout Preview.", null);
+                    "supports affine transformations.", null);
         }
     }
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
index 94beef3..22c216d 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -17,6 +17,7 @@
 package android.graphics;
 
 
+import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.impl.DelegateManager;
 
 import android.graphics.Matrix.ScaleToFit;
@@ -599,7 +600,10 @@
     /*package*/ static boolean native_setPolyToPoly(int native_object, float[] src, int srcIndex,
             float[] dst, int dstIndex, int pointCount) {
         // FIXME
-        throw new UnsupportedOperationException("Native delegate needed: Matrix_Delegate.native_setPolyToPoly");
+        Bridge.getLog().fidelityWarning(null,
+                "Matrix.setPolyToPoly is not supported.",
+                null);
+        return false;
     }
 
     /*package*/ static boolean native_invert(int native_object, int inverse) {
@@ -639,9 +643,7 @@
         if (isPts) {
             d.mapPoints(dst, dstIndex, src, srcIndex, ptCount);
         } else {
-            // src is vectors
-            // FIXME
-            throw new UnsupportedOperationException("Native delegate needed: Matrix_Delegate.native_mapPoints");
+            d.mapVectors(dst, dstIndex, src, srcIndex, ptCount);
         }
     }
 
@@ -655,8 +657,18 @@
     }
 
     /*package*/ static float native_mapRadius(int native_object, float radius) {
-        // FIXME
-        throw new UnsupportedOperationException("Native delegate needed: Matrix_Delegate.native_mapRadius");
+        Matrix_Delegate d = sManager.getDelegate(native_object);
+        if (d == null) {
+            return 0.f;
+        }
+
+        float[] src = new float[] { radius, 0.f, 0.f, radius };
+        d.mapVectors(src, 0, src, 0, 2);
+
+        float l1 = getPointLength(src, 0);
+        float l2 = getPointLength(src, 2);
+
+        return (float) Math.sqrt(l1 * l2);
     }
 
     /*package*/ static void native_getValues(int native_object, float[] values) {
@@ -842,15 +854,15 @@
 
      private void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex,
                            int pointCount) {
-         //checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
+         final int count = pointCount * 2;
 
          float[] tmpDest = dst;
          boolean inPlace = dst == src;
          if (inPlace) {
-             tmpDest = new float[dstIndex + pointCount * 2];
+             tmpDest = new float[dstIndex + count];
          }
 
-         for (int i = 0 ; i < pointCount * 2 ; i += 2) {
+         for (int i = 0 ; i < count ; i += 2) {
              // just in case we are doing in place, we better put this in temp vars
              float x = mValues[0] * src[i + srcIndex] +
                        mValues[1] * src[i + srcIndex + 1] +
@@ -864,7 +876,7 @@
          }
 
          if (inPlace) {
-             System.arraycopy(tmpDest, dstIndex, dst, dstIndex, pointCount * 2);
+             System.arraycopy(tmpDest, dstIndex, dst, dstIndex, count);
          }
      }
 
@@ -879,6 +891,37 @@
          mapPoints(pts, 0, pts, 0, pts.length >> 1);
      }
 
+     private void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex, int ptCount) {
+         if (hasPerspective()) {
+             // transform the (0,0) point
+             float[] origin = new float[] { 0.f, 0.f};
+             mapPoints(origin);
+
+             // translate the vector data as points
+             mapPoints(dst, dstIndex, src, srcIndex, ptCount);
+
+             // then substract the transformed origin.
+             final int count = ptCount * 2;
+             for (int i = 0 ; i < count ; i += 2) {
+                 dst[dstIndex + i] = dst[dstIndex + i] - origin[0];
+                 dst[dstIndex + i + 1] = dst[dstIndex + i + 1] - origin[1];
+             }
+         } else {
+             // make a copy of the matrix
+             Matrix_Delegate copy = new Matrix_Delegate(mValues);
+
+             // remove the translation
+             setTranslate(copy.mValues, 0, 0);
+
+             // map the content as points.
+             copy.mapPoints(dst, dstIndex, src, srcIndex, ptCount);
+         }
+     }
+
+     private static float getPointLength(float[] src, int index) {
+         return (float) Math.sqrt(src[index] * src[index] + src[index + 1] * src[index + 1]);
+     }
+
     /**
      * multiply two matrices and store them in a 3rd.
      * <p/>This in effect does dest = a*b
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index 66ab29c..03a1815 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -703,7 +703,7 @@
             assert false;
             Bridge.getLog().fidelityWarning(null,
                     "android.graphics.Path#transform() only " +
-                    "supports affine transformations in the Layout Preview.", null);
+                    "supports affine transformations.", null);
         }
 
         GeneralPath newPath = new GeneralPath();
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index f03a9e5..10faeda 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -62,11 +62,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.app.backup.IBackupManager;
-import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothProfile;
 import android.content.BroadcastReceiver;
 import android.content.Intent;
 import android.content.Context;
@@ -120,6 +116,8 @@
     private int mReconnectCount = 0;
     private boolean mIsScanMode = false;
 
+    private boolean mBluetoothConnectionActive = false;
+
     /**
      * Interval in milliseconds between polling for RSSI
      * and linkspeed information
@@ -138,16 +136,6 @@
 
     private int mSupplicantRestartCount = 0;
 
-    /**
-     * Instance of the bluetooth headset helper. This needs to be created
-     * early because there is a delay before it actually 'connects', as
-     * noted by its javadoc. If we check before it is connected, it will be
-     * in an error state and we will not disable coexistence.
-     */
-    private BluetoothHeadset mBluetoothHeadset;
-
-    private BluetoothA2dp mBluetoothA2dp;
-
     private LinkProperties mLinkProperties;
 
     // Wakelock held during wifi start/stop and driver load/unload
@@ -186,10 +174,6 @@
     static final int CMD_UNLOAD_DRIVER_SUCCESS            = 5;
     /* Indicates driver unload failed */
     static final int CMD_UNLOAD_DRIVER_FAILURE            = 6;
-    /* Set bluetooth headset proxy */
-    static final int CMD_SET_BLUETOOTH_HEADSET_PROXY      = 7;
-    /* Set bluetooth A2dp proxy */
-    static final int CMD_SET_BLUETOOTH_A2DP_PROXY         = 8;
 
     /* Start the supplicant */
     static final int CMD_START_SUPPLICANT                 = 11;
@@ -209,6 +193,7 @@
     /* Stop the soft access point */
     static final int CMD_STOP_AP                          = 22;
 
+    static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE   = 23;
 
     /* Supplicant events */
     /* Connection to supplicant established */
@@ -277,17 +262,6 @@
      * - DTIM wake up settings
      */
     static final int CMD_SET_HIGH_PERF_MODE               = 77;
-    /* Set bluetooth co-existence
-     * BLUETOOTH_COEXISTENCE_MODE_ENABLED
-     * BLUETOOTH_COEXISTENCE_MODE_DISABLED
-     * BLUETOOTH_COEXISTENCE_MODE_SENSE
-     */
-    static final int CMD_SET_BLUETOOTH_COEXISTENCE        = 78;
-    /* Enable/disable bluetooth scan mode
-     * true(1)
-     * false(0)
-     */
-    static final int CMD_SET_BLUETOOTH_SCAN_MODE          = 79;
     /* Set the country code */
     static final int CMD_SET_COUNTRY_CODE                 = 80;
     /* Request connectivity manager wake lock before driver stop */
@@ -476,15 +450,7 @@
         mInterfaceName = SystemProperties.get("wifi.interface", "tiwlan0");
         mSupplicantStateTracker = new SupplicantStateTracker(context, this, getHandler());
         mWpsStateMachine = new WpsStateMachine(context, this, getHandler());
-
         mLinkProperties = new LinkProperties();
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        if (adapter != null) {
-            adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
-                                    BluetoothProfile.A2DP);
-            adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
-                                    BluetoothProfile.HEADSET);
-        }
 
         mNetworkInfo.setIsAvailable(false);
         mLinkProperties.clear();
@@ -914,26 +880,10 @@
     }
 
     /**
-     * Set bluetooth coex mode:
-     *
-     * @param mode
-     *  BLUETOOTH_COEXISTENCE_MODE_ENABLED
-     *  BLUETOOTH_COEXISTENCE_MODE_DISABLED
-     *  BLUETOOTH_COEXISTENCE_MODE_SENSE
+     * Send a message indicating bluetooth adapter connection state changed
      */
-    public void setBluetoothCoexistenceMode(int mode) {
-        sendMessage(obtainMessage(CMD_SET_BLUETOOTH_COEXISTENCE, mode, 0));
-    }
-
-    /**
-     * Enable or disable Bluetooth coexistence scan mode. When this mode is on,
-     * some of the low-level scan parameters used by the driver are changed to
-     * reduce interference with A2DP streaming.
-     *
-     * @param isBluetoothPlaying whether to enable or disable this mode
-     */
-    public void setBluetoothScanMode(boolean isBluetoothPlaying) {
-        sendMessage(obtainMessage(CMD_SET_BLUETOOTH_SCAN_MODE, isBluetoothPlaying ? 1 : 0, 0));
+    public void sendBluetoothAdapterStateChange(int state) {
+        sendMessage(obtainMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0));
     }
 
     /**
@@ -1312,54 +1262,6 @@
                                       DEFAULT_MAX_DHCP_RETRIES);
     }
 
-    /**
-     * Whether to disable coexistence mode while obtaining IP address. We
-     * disable coexistence if the headset indicates that there are no
-     * connected devices. If we have not got an indication of the service
-     * connection yet, we go ahead with disabling coexistence mode.
-     *
-     * @return Whether to disable coexistence mode.
-     */
-    private boolean shouldDisableCoexistenceMode() {
-        if (mBluetoothHeadset == null) return true;
-        List<BluetoothDevice> devices = mBluetoothHeadset.getConnectedDevices();
-        return (devices.size() != 0 ? false : true);
-    }
-
-    private void checkIsBluetoothPlaying() {
-        boolean isBluetoothPlaying = false;
-        if (mBluetoothA2dp != null) {
-            List<BluetoothDevice> connected = mBluetoothA2dp.getConnectedDevices();
-
-            for (BluetoothDevice device : connected) {
-                if (mBluetoothA2dp.isA2dpPlaying(device)) {
-                    isBluetoothPlaying = true;
-                    break;
-                }
-            }
-        }
-        setBluetoothScanMode(isBluetoothPlaying);
-    }
-
-    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
-        new BluetoothProfile.ServiceListener() {
-        public void onServiceConnected(int profile, BluetoothProfile proxy) {
-                if (profile == BluetoothProfile.HEADSET) {
-                    sendMessage(CMD_SET_BLUETOOTH_HEADSET_PROXY, proxy);
-                } else if (profile == BluetoothProfile.A2DP) {
-                    sendMessage(CMD_SET_BLUETOOTH_A2DP_PROXY, proxy);
-                }
-        }
-
-        public void onServiceDisconnected(int profile) {
-                if (profile == BluetoothProfile.HEADSET) {
-                    sendMessage(CMD_SET_BLUETOOTH_HEADSET_PROXY, null);
-                } else if (profile == BluetoothProfile.A2DP) {
-                    sendMessage(CMD_SET_BLUETOOTH_A2DP_PROXY, null);
-                }
-        }
-    };
-
     private void sendScanResultsAvailableBroadcast() {
         Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -1562,11 +1464,9 @@
         public boolean processMessage(Message message) {
             if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
             switch (message.what) {
-                case CMD_SET_BLUETOOTH_HEADSET_PROXY:
-                    mBluetoothHeadset = (BluetoothHeadset) message.obj;
-                    break;
-                case CMD_SET_BLUETOOTH_A2DP_PROXY:
-                    mBluetoothA2dp = (BluetoothA2dp) message.obj;
+                case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
+                    mBluetoothConnectionActive = (message.arg1 !=
+                            BluetoothAdapter.STATE_DISCONNECTED);
                     break;
                     /* Synchronous call returns */
                 case CMD_PING_SUPPLICANT:
@@ -1610,8 +1510,6 @@
                 case CMD_SET_SCAN_MODE:
                 case CMD_SET_SCAN_TYPE:
                 case CMD_SET_HIGH_PERF_MODE:
-                case CMD_SET_BLUETOOTH_COEXISTENCE:
-                case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_REQUEST_CM_WAKELOCK:
@@ -1722,8 +1620,6 @@
                 case CMD_SET_SCAN_MODE:
                 case CMD_SET_SCAN_TYPE:
                 case CMD_SET_HIGH_PERF_MODE:
-                case CMD_SET_BLUETOOTH_COEXISTENCE:
-                case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -1850,8 +1746,6 @@
                 case CMD_SET_SCAN_MODE:
                 case CMD_SET_SCAN_TYPE:
                 case CMD_SET_HIGH_PERF_MODE:
-                case CMD_SET_BLUETOOTH_COEXISTENCE:
-                case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -1930,8 +1824,6 @@
                     //TODO: initialize and fix multicast filtering
                     //mWM.initializeMulticastFiltering();
 
-                    checkIsBluetoothPlaying();
-
                     sendSupplicantConnectionChangedBroadcast(true);
                     transitionTo(mDriverStartedState);
                     break;
@@ -1960,8 +1852,6 @@
                 case CMD_SET_SCAN_MODE:
                 case CMD_SET_SCAN_TYPE:
                 case CMD_SET_HIGH_PERF_MODE:
-                case CMD_SET_BLUETOOTH_COEXISTENCE:
-                case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2116,8 +2006,6 @@
                 case CMD_SET_SCAN_MODE:
                 case CMD_SET_SCAN_TYPE:
                 case CMD_SET_HIGH_PERF_MODE:
-                case CMD_SET_BLUETOOTH_COEXISTENCE:
-                case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2154,8 +2042,6 @@
                 case PASSWORD_MAY_BE_INCORRECT_EVENT:
                 case CMD_SET_SCAN_TYPE:
                 case CMD_SET_HIGH_PERF_MODE:
-                case CMD_SET_BLUETOOTH_COEXISTENCE:
-                case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2183,6 +2069,12 @@
             mIsRunning = true;
             updateBatteryWorkSource(null);
 
+            /**
+             * Enable bluetooth coexistence scan mode when bluetooth connection is active.
+             * When this mode is on, some of the low-level scan parameters used by the
+             * driver are changed to reduce interference with bluetooth
+             */
+            WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive);
             /* set country code */
             setCountryCode();
             /* set frequency band of operation */
@@ -2219,12 +2111,6 @@
                 case CMD_SET_HIGH_PERF_MODE:
                     setHighPerfModeEnabledNative(message.arg1 == 1);
                     break;
-                case CMD_SET_BLUETOOTH_COEXISTENCE:
-                    WifiNative.setBluetoothCoexistenceModeCommand(message.arg1);
-                    break;
-                case CMD_SET_BLUETOOTH_SCAN_MODE:
-                    WifiNative.setBluetoothCoexistenceScanModeCommand(message.arg1 == 1);
-                    break;
                 case CMD_SET_COUNTRY_CODE:
                     String country = (String) message.obj;
                     Log.d(TAG, "set country code " + country);
@@ -2243,6 +2129,11 @@
                         Log.e(TAG, "Failed to set frequency band " + band);
                     }
                     break;
+                case CMD_BLUETOOTH_ADAPTER_STATE_CHANGE:
+                    mBluetoothConnectionActive = (message.arg1 !=
+                            BluetoothAdapter.STATE_DISCONNECTED);
+                    WifiNative.setBluetoothCoexistenceScanModeCommand(mBluetoothConnectionActive);
+                    break;
                 case CMD_STOP_DRIVER:
                     mWakeLock.acquire();
                     WifiNative.stopDriverCommand();
@@ -2290,8 +2181,6 @@
                 case CMD_STOP_DRIVER:
                 case CMD_SET_SCAN_TYPE:
                 case CMD_SET_HIGH_PERF_MODE:
-                case CMD_SET_BLUETOOTH_COEXISTENCE:
-                case CMD_SET_BLUETOOTH_SCAN_MODE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2490,7 +2379,7 @@
                 mModifiedBluetoothCoexistenceMode = false;
                 mPowerMode = POWER_MODE_AUTO;
 
-                if (shouldDisableCoexistenceMode()) {
+                if (!mBluetoothConnectionActive) {
                     /*
                      * There are problems setting the Wi-Fi driver's power
                      * mode to active when bluetooth coexistence mode is