Merge "Add optional metadata to initiliaze the render threat."
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3f61e6b..eefebd5 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -23,6 +23,7 @@
 import android.content.ComponentCallbacks;
 import android.content.ComponentCallbacks2;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
@@ -82,7 +83,6 @@
 
 import java.io.IOException;
 import java.io.OutputStream;
-import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
@@ -140,6 +140,10 @@
     static final ArrayList<ComponentCallbacks> sConfigCallbacks
             = new ArrayList<ComponentCallbacks>();
 
+    private static boolean sUseRenderThread = false;
+    private static boolean sRenderThreadQueried = false;
+    private static final Object[] sRenderThreadQueryLock = new Object[0];
+
     long mLastTrackballTime = 0;
     final TrackballAxis mTrackballAxisX = new TrackballAxis();
     final TrackballAxis mTrackballAxisY = new TrackballAxis();
@@ -381,6 +385,31 @@
         mChoreographer = Choreographer.getInstance();
     }
 
+    /**
+     * @return True if the application requests the use of a separate render thread,
+     *         false otherwise
+     */
+    private static boolean isRenderThreadRequested(Context context) {
+        synchronized (sRenderThreadQueryLock) {
+            if (!sRenderThreadQueried) {
+                final PackageManager packageManager = context.getPackageManager();
+                final String packageName = context.getApplicationInfo().packageName;
+                try {
+                    ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName,
+                            PackageManager.GET_META_DATA);
+                    if (applicationInfo.metaData != null) {
+                        sUseRenderThread = applicationInfo.metaData.getBoolean(
+                                "android.graphics.renderThread", false);
+                    }
+                } catch (PackageManager.NameNotFoundException e) {
+                } finally {
+                    sRenderThreadQueried = true;
+                }
+            }
+            return sUseRenderThread;
+        }
+    }
+
     public static void addFirstDrawHandler(Runnable callback) {
         synchronized (sFirstDrawHandlers) {
             if (!sFirstDrawComplete) {
@@ -451,7 +480,7 @@
 
                 // If the application owns the surface, don't enable hardware acceleration
                 if (mSurfaceHolder == null) {
-                    enableHardwareAcceleration(attrs);
+                    enableHardwareAcceleration(mView.getContext(), attrs);
                 }
 
                 boolean restore = false;
@@ -611,7 +640,7 @@
         }
     }
 
-    private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
+    private void enableHardwareAcceleration(Context context, WindowManager.LayoutParams attrs) {
         mAttachInfo.mHardwareAccelerated = false;
         mAttachInfo.mHardwareAccelerationRequested = false;
 
@@ -644,20 +673,27 @@
             if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
                     && forceHwAccelerated)) {
                 // Don't enable hardware acceleration when we're not on the main thread
-                if (!HardwareRenderer.sSystemRendererDisabled
-                        && Looper.getMainLooper() != Looper.myLooper()) {
-                    Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
+                if (!HardwareRenderer.sSystemRendererDisabled &&
+                        Looper.getMainLooper() != Looper.myLooper()) {
+                    Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware " 
                             + "acceleration outside of the main thread, aborting");
                     return;
                 }
 
-                final boolean translucent = attrs.format != PixelFormat.OPAQUE;
+                boolean renderThread = isRenderThreadRequested(context);
+                if (renderThread) {
+                    Log.i(HardwareRenderer.LOG_TAG, "Render threat initiated");
+                }
+
                 if (mAttachInfo.mHardwareRenderer != null) {
                     mAttachInfo.mHardwareRenderer.destroy(true);
-                }                
+                }
+
+                final boolean translucent = attrs.format != PixelFormat.OPAQUE;
                 mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
                 mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested
                         = mAttachInfo.mHardwareRenderer != null;
+
             } else if (fakeHwAccelerated) {
                 // The window had wanted to use hardware acceleration, but this
                 // is not allowed in its process.  By setting this flag, it can
@@ -3444,11 +3480,11 @@
         if (args.localChanges != 0) {
             if (mAttachInfo != null) {
                 mAttachInfo.mSystemUiVisibility =
-                        (mAttachInfo.mSystemUiVisibility&~args.localChanges)
-                        | (args.localValue&args.localChanges);
+                        (mAttachInfo.mSystemUiVisibility & ~args.localChanges) |
+                                (args.localValue & args.localChanges);
+                mAttachInfo.mRecomputeGlobalAttributes = true;
             }
             mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
-            mAttachInfo.mRecomputeGlobalAttributes = true;
             scheduleTraversals();            
         }
         mView.dispatchSystemUiVisibilityChanged(args.globalVisibility);
@@ -3602,7 +3638,7 @@
         mView.debug();
     }
     
-    public void dumpGfxInfo(PrintWriter pw, int[] info) {
+    public void dumpGfxInfo(int[] info) {
         if (mView != null) {
             getGfxInfo(mView, info);
         } else {
@@ -3714,7 +3750,7 @@
      * Represents a pending input event that is waiting in a queue.
      *
      * Input events are processed in serial order by the timestamp specified by
-     * {@link InputEvent#getEventTime()}.  In general, the input dispatcher delivers
+     * {@link InputEvent#getEventTimeNano()}.  In general, the input dispatcher delivers
      * one input event to the application at a time and waits for the application
      * to finish handling it before delivering the next one.
      *
@@ -3723,7 +3759,7 @@
      * needing a queue on the application's side.
      */
     private static final class QueuedInputEvent {
-        public static final int FLAG_DELIVER_POST_IME = 1 << 0;
+        public static final int FLAG_DELIVER_POST_IME = 1;
 
         public QueuedInputEvent mNext;
 
@@ -4842,7 +4878,7 @@
             mPool.release(args);
             List<AccessibilityNodeInfo> infos = null;
             try {
-                View target = null;
+                View target;
                 if (accessibilityViewId != View.NO_ID) {
                     target = findViewByAccessibilityId(accessibilityViewId);
                 } else {
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index d7113374..6bdc4e8 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -490,7 +490,7 @@
 
                     for (int i = 0; i < count; i++) {
                         ViewRootImpl root = mRoots[i];
-                        root.dumpGfxInfo(pw, info);
+                        root.dumpGfxInfo(info);
 
                         String name = root.getClass().getName() + '@' +
                                 Integer.toHexString(hashCode());                        
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index bd213d5..afae70f 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -754,7 +754,7 @@
 
     // TODO: See LayerRenderer.cpp::generateMesh() for important
     //       information about this implementation
-    if (!layer->region.isEmpty()) {
+    if (CC_LIKELY(!layer->region.isEmpty())) {
         size_t count;
         const android::Rect* rects = layer->region.getArray(&count);
 
@@ -1398,7 +1398,7 @@
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
-    if (bitmap->getConfig() == SkBitmap::kA8_Config) {
+    if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
         drawAlphaBitmap(texture, left, top, paint);
     } else {
         drawTextureRect(left, top, right, bottom, texture, paint);
@@ -1454,9 +1454,9 @@
     float bottom = FLT_MIN;
 
 #if RENDER_LAYERS_AS_REGIONS
-    bool hasActiveLayer = hasLayer();
+    const bool hasActiveLayer = hasLayer();
 #else
-    bool hasActiveLayer = false;
+    const bool hasActiveLayer = false;
 #endif
 
     // TODO: Support the colors array
@@ -1541,7 +1541,7 @@
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
 
-    if (mSnapshot->transform->isPureTranslate()) {
+    if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
         const float x = (int) floorf(dstLeft + mSnapshot->transform->getTranslateX() + 0.5f);
         const float y = (int) floorf(dstTop + mSnapshot->transform->getTranslateY() + 0.5f);
 
@@ -1587,7 +1587,7 @@
     const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(),
             right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors);
 
-    if (mesh && mesh->verticesCount > 0) {
+    if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
         const bool pureTranslate = mSnapshot->transform->isPureTranslate();
 #if RENDER_LAYERS_AS_REGIONS
         // Mark the current layer dirty where we are going to draw the patch
@@ -1597,7 +1597,7 @@
             const size_t count = mesh->quads.size();
             for (size_t i = 0; i < count; i++) {
                 const Rect& bounds = mesh->quads.itemAt(i);
-                if (pureTranslate) {
+                if (CC_LIKELY(pureTranslate)) {
                     const float x = (int) floorf(bounds.left + offsetX + 0.5f);
                     const float y = (int) floorf(bounds.top + offsetY + 0.5f);
                     dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
@@ -1609,7 +1609,7 @@
         }
 #endif
 
-        if (pureTranslate) {
+        if (CC_LIKELY(pureTranslate)) {
             const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f);
             const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f);
 
@@ -1637,7 +1637,7 @@
     float inverseScaleX = 1.0f;
     float inverseScaleY = 1.0f;
     // The quad that we use needs to account for scaling.
-    if (!mSnapshot->transform->isPureTranslate()) {
+    if (CC_UNLIKELY(!mSnapshot->transform->isPureTranslate())) {
         Matrix4 *mat = mSnapshot->transform;
         float m00 = mat->data[Matrix4::kScaleX];
         float m01 = mat->data[Matrix4::kSkewY];
@@ -1743,7 +1743,7 @@
         // The quad that we use for AA and hairlines needs to account for scaling. For hairlines
         // the line on the screen should always be one pixel wide regardless of scale. For
         // AA lines, we only want one pixel of translucent boundary around the quad.
-        if (!mSnapshot->transform->isPureTranslate()) {
+        if (CC_UNLIKELY(!mSnapshot->transform->isPureTranslate())) {
             Matrix4 *mat = mSnapshot->transform;
             float m00 = mat->data[Matrix4::kScaleX];
             float m01 = mat->data[Matrix4::kSkewY];
@@ -1751,8 +1751,8 @@
             float m10 = mat->data[Matrix4::kSkewX];
             float m11 = mat->data[Matrix4::kScaleX];
             float m12 = mat->data[6];
-            float scaleX = sqrt(m00*m00 + m01*m01);
-            float scaleY = sqrt(m10*m10 + m11*m11);
+            float scaleX = sqrtf(m00 * m00 + m01 * m01);
+            float scaleY = sqrtf(m10 * m10 + m11 * m11);
             inverseScaleX = (scaleX != 0) ? (inverseScaleX / scaleX) : 0;
             inverseScaleY = (scaleY != 0) ? (inverseScaleY / scaleY) : 0;
             if (inverseScaleX != 1.0f || inverseScaleY != 1.0f) {
@@ -1770,11 +1770,7 @@
     setupDrawColor(paint->getColor(), alpha);
     setupDrawColorFilter();
     setupDrawShader();
-    if (isAA) {
-        setupDrawBlending(true, mode);
-    } else {
-        setupDrawBlending(mode);
-    }
+    setupDrawBlending(isAA, mode);
     setupDrawProgram();
     setupDrawModelViewIdentity(true);
     setupDrawColorUniforms();
@@ -1792,7 +1788,7 @@
     Vertex* vertices = &lines[0];
     AAVertex wLines[verticesCount];
     AAVertex* aaVertices = &wLines[0];
-    if (!isAA) {
+    if (CC_UNLIKELY(!isAA)) {
         setupDrawVertices(vertices);
     } else {
         void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset;
@@ -2152,9 +2148,9 @@
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
 #if RENDER_LAYERS_AS_REGIONS
-    bool hasActiveLayer = hasLayer();
+    const bool hasActiveLayer = hasLayer();
 #else
-    bool hasActiveLayer = false;
+    const bool hasActiveLayer = false;
 #endif
 
     if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
@@ -2201,7 +2197,7 @@
     const float oldX = x;
     const float oldY = y;
     const bool pureTranslate = mSnapshot->transform->isPureTranslate();
-    if (pureTranslate) {
+    if (CC_LIKELY(pureTranslate)) {
         x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
         y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
     }
@@ -2218,7 +2214,7 @@
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
-    if (mHasShadow) {
+    if (CC_UNLIKELY(mHasShadow)) {
         mCaches.activeTexture(0);
 
         mCaches.dropShadowCache.setFontRenderer(fontRenderer);
@@ -2277,9 +2273,9 @@
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
 #if RENDER_LAYERS_AS_REGIONS
-    bool hasActiveLayer = hasLayer();
+    const bool hasActiveLayer = hasLayer();
 #else
-    bool hasActiveLayer = false;
+    const bool hasActiveLayer = false;
 #endif
 
     if (fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y,
@@ -2326,7 +2322,7 @@
     layer->setAlpha(alpha, mode);
 
 #if RENDER_LAYERS_AS_REGIONS
-    if (!layer->region.isEmpty()) {
+    if (CC_LIKELY(!layer->region.isEmpty())) {
         if (layer->region.isRect()) {
             composeLayerRect(layer, layer->regionRect);
         } else if (layer->mesh) {
@@ -2342,7 +2338,7 @@
             setupDrawPureColorUniforms();
             setupDrawColorFilterUniforms();
             setupDrawTexture(layer->getTexture());
-            if (mSnapshot->transform->isPureTranslate()) {
+            if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
                 x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
                 y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
 
@@ -2502,7 +2498,7 @@
                 break;
         }
 
-        if (underlineWidth > 0.0f) {
+        if (CC_LIKELY(underlineWidth > 0.0f)) {
             const float textSize = paintCopy.getTextSize();
             const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
 
@@ -2571,7 +2567,7 @@
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
 
-    if (mSnapshot->transform->isPureTranslate()) {
+    if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
         const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f);
         const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f);
 
@@ -2631,8 +2627,8 @@
         // the blending, turn blending off here
         // If the blend mode cannot be implemented using shaders, fall
         // back to the default SrcOver blend mode instead
-        if (mode > SkXfermode::kScreen_Mode) {
-            if (mCaches.extensions.hasFramebufferFetch()) {
+        if CC_UNLIKELY((mode > SkXfermode::kScreen_Mode)) {
+            if (CC_UNLIKELY(mCaches.extensions.hasFramebufferFetch())) {
                 description.framebufferMode = mode;
                 description.swapSrcDst = swapSrcDst;
 
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 5bbcce3..643cb8d 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -30,6 +30,8 @@
         android:label="HwUi"
         android:hardwareAccelerated="true">
 
+        <meta-data android:name="android.graphics.renderThread" android:value="true" />
+
         <activity
                 android:name="PaintDrawFilterActivity"
                 android:label="_DrawFilter">