Fix INVALID_OPERATION error with layers rendering.

This change is a workaround for a driver bug that causes an INVALID_OPERATION
to be thrown on every glCopyTexSubImage() call. This change also adds a new
test for gradients local matrices.

Change-Id: I41b7437481026702d0a3a9677f099b4557c0a84e
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 595bac8..00324a85 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -17,7 +17,6 @@
 package android.view;
 
 import android.content.ClipData;
-import android.content.ClipDescription;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -55,7 +54,6 @@
 import android.util.Pools;
 import android.util.SparseArray;
 import android.view.ContextMenu.ContextMenuInfo;
-import android.view.DragEvent;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityEventSource;
 import android.view.accessibility.AccessibilityManager;
@@ -2038,7 +2036,6 @@
      *
      */
     boolean mCanAcceptDrop;
-    private boolean mIsCurrentDropTarget;
     private int mThumbnailWidth;
     private int mThumbnailHeight;
 
@@ -9800,11 +9797,14 @@
                     + " surface=" + surface);
             if (token != null) {
                 Canvas canvas = surface.lockCanvas(null);
-                onDrawDragThumbnail(canvas);
-                surface.unlockCanvasAndPost(canvas);
+                try {
+                    onDrawDragThumbnail(canvas);
+                } finally {
+                    surface.unlockCanvasAndPost(canvas);
+                }
 
                 okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, token,
-                        touchX, touchY, thumbnailTouchX, thumbnailTouchX, data);
+                        touchX, touchY, thumbnailTouchX, thumbnailTouchY, data);
                 if (DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay);
             }
         } catch (Exception e) {
@@ -9837,8 +9837,8 @@
      * The View must call this method from onMeasureDragThumbnail() in order to
      * specify the dimensions of the drag thumbnail image.
      *
-     * @param width
-     * @param height
+     * @param width The desired thumbnail width.
+     * @param height The desired thumbnail height.
      */
     protected final void setDragThumbnailDimension(int width, int height) {
         mPrivateFlags |= MEASURED_DIMENSION_SET;
@@ -9973,30 +9973,6 @@
                 ViewConfiguration.getLongPressTimeout() - delayOffset);
     }
 
-    private static int[] stateSetUnion(final int[] stateSet1, final int[] stateSet2) {
-        final int stateSet1Length = stateSet1.length;
-        final int stateSet2Length = stateSet2.length;
-        final int[] newSet = new int[stateSet1Length + stateSet2Length];
-        int k = 0;
-        int i = 0;
-        int j = 0;
-        // This is a merge of the two input state sets and assumes that the
-        // input sets are sorted by the order imposed by ViewDrawableStates.
-        for (int viewState : R.styleable.ViewDrawableStates) {
-            if (i < stateSet1Length && stateSet1[i] == viewState) {
-                newSet[k++] = viewState;
-                i++;
-            } else if (j < stateSet2Length && stateSet2[j] == viewState) {
-                newSet[k++] = viewState;
-                j++;
-            }
-            if (k > 1) {
-                assert(newSet[k - 1] > newSet[k - 2]);
-            }
-        }
-        return newSet;
-    }
-
     /**
      * Inflate a view from an XML resource.  This convenience method wraps the {@link
      * LayoutInflater} class, which provides a full range of options for view inflation.
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 60523db..a0cc5d6 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -44,7 +44,7 @@
     uint32_t id;
 
     bool operator<(const LayerSize& rhs) const {
-        if (id != 0 && rhs.id != 0) {
+        if (id != 0 && rhs.id != 0 && id != rhs.id) {
             return id < rhs.id;
         }
         if (width == rhs.width) {
@@ -54,7 +54,7 @@
     }
 
     bool operator==(const LayerSize& rhs) const {
-        return width == rhs.width && height == rhs.height;
+        return id == rhs.id && width == rhs.width && height == rhs.height;
     }
 }; // struct LayerSize
 
@@ -83,7 +83,7 @@
      */
     bool blend;
     /**
-     * Indicates that this layer has never been used before.
+     * Indicates whether this layer has been used already.
      */
     bool empty;
 }; // struct Layer
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 2770868..8c70cf9 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -114,6 +114,8 @@
         glGenTextures(1, &layer->texture);
         glBindTexture(GL_TEXTURE_2D, layer->texture);
 
+        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 23de3a5..0810fb8 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -366,6 +366,8 @@
         return false;
     }
 
+    glActiveTexture(GL_TEXTURE0);
+
     LayerSize size(bounds.getWidth(), bounds.getHeight());
     Layer* layer = mCaches.layerCache.get(size);
     if (!layer) {
@@ -383,17 +385,22 @@
     // Copy the framebuffer into the layer
     glBindTexture(GL_TEXTURE_2D, layer->texture);
 
-    if (layer->empty) {
-        glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left, mHeight - bounds.bottom,
-                bounds.getWidth(), bounds.getHeight(), 0);
-        layer->empty = false;
-    } else {
-        glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left, mHeight - bounds.bottom,
-                bounds.getWidth(), bounds.getHeight());
-    }
+    // TODO: Workaround for b/3054204
+    glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left, mHeight - bounds.bottom,
+            bounds.getWidth(), bounds.getHeight(), 0);
 
-    if (flags & SkCanvas::kClipToLayer_SaveFlag) {
-        if (mSnapshot->clipTransformed(bounds)) setScissorFromClip();
+    // TODO: Waiting for b/3054204 to be fixed
+//    if (layer->empty) {
+//        glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left, mHeight - bounds.bottom,
+//                bounds.getWidth(), bounds.getHeight(), 0);
+//        layer->empty = false;
+//    } else {
+//        glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left, mHeight - bounds.bottom,
+//                bounds.getWidth(), bounds.getHeight());
+//    }
+
+    if (flags & SkCanvas::kClipToLayer_SaveFlag && mSnapshot->clipTransformed(bounds)) {
+        setScissorFromClip();
     }
 
     // Enqueue the buffer coordinates to clear the corresponding region later
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index af71a0f..4be41b9 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -164,6 +164,15 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+        
+        <activity
+                android:name="GradientsActivity"
+                android:label="_Gradients">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
 
         <activity
                 android:name="ShadersActivity"
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java
new file mode 100644
index 0000000..b70f3a9
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.LinearGradient;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Shader;
+import android.os.Bundle;
+import android.view.View;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class GradientsActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(new ShadersView(this));
+    }
+
+    static class ShadersView extends View {
+        private final Paint mPaint;
+        private final float mDrawWidth;
+        private final float mDrawHeight;
+        private final LinearGradient mGradient;
+        private final Matrix mMatrix;
+
+        ShadersView(Context c) {
+            super(c);
+
+            mDrawWidth = 200;
+            mDrawHeight = 200;
+
+            mGradient = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP);
+            mMatrix = new Matrix();
+
+            mPaint = new Paint();
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+            canvas.drawRGB(255, 255, 255);
+
+            // Gradients
+            canvas.save();
+            float top = 40.0f;
+            float right = 40.0f + mDrawWidth;
+            float left = 40.0f;
+            float bottom = 40.0f + mDrawHeight;
+
+            mPaint.setShader(mGradient);
+
+            mMatrix.setScale(1, mDrawWidth);
+            mMatrix.postRotate(90);
+            mMatrix.postTranslate(right, top);
+            mGradient.setLocalMatrix(mMatrix);
+            canvas.drawRect(right - mDrawWidth, top, right, top + mDrawHeight, mPaint);
+
+            top += 40.0f + mDrawHeight;
+            bottom += 40.0f + mDrawHeight;
+            
+            mMatrix.setScale(1, mDrawHeight);
+            mMatrix.postTranslate(left, top);
+            mGradient.setLocalMatrix(mMatrix);
+            canvas.drawRect(left, top, right, top + mDrawHeight, mPaint);
+            
+            left += 40.0f + mDrawWidth;
+            right += 40.0f + mDrawWidth;
+            top -= 40.0f + mDrawHeight;
+            bottom -= 40.0f + mDrawHeight;
+
+            mMatrix.setScale(1, mDrawHeight);
+            mMatrix.postRotate(180);
+            mMatrix.postTranslate(left, bottom);
+            mGradient.setLocalMatrix(mMatrix);
+            canvas.drawRect(left, bottom - mDrawHeight, right, bottom, mPaint);
+
+            top += 40.0f + mDrawHeight;
+            bottom += 40.0f + mDrawHeight;
+            
+            mMatrix.setScale(1, mDrawWidth);
+            mMatrix.postRotate(-90);
+            mMatrix.postTranslate(left, top);
+            mGradient.setLocalMatrix(mMatrix);
+            canvas.drawRect(left, top, left + mDrawWidth, bottom, mPaint);
+           
+            canvas.restore();
+        }
+    }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java
index 9c8e7ec..2db1071 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ShadersActivity.java
@@ -77,8 +77,13 @@
             m2.setScale(0.5f, 0.5f);
             mScaledShader.setLocalMatrix(m2);
 
-            mHorGradient = new LinearGradient(0.0f, 0.0f, mDrawWidth, 0.0f,
+            mHorGradient = new LinearGradient(0.0f, 0.0f, 1.0f, 0.0f,
                     Color.RED, Color.GREEN, Shader.TileMode.CLAMP);
+            Matrix m3 = new Matrix();
+            m3.setScale(mDrawHeight, 1.0f);
+            m3.postRotate(-90.0f);
+            m3.postTranslate(0.0f, mDrawHeight);
+            mHorGradient.setLocalMatrix(m3);
             
             mDiagGradient = new LinearGradient(0.0f, 0.0f, mDrawWidth / 1.5f, mDrawHeight,
                     Color.BLUE, Color.MAGENTA, Shader.TileMode.CLAMP);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TransparentListActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TransparentListActivity.java
index f47b00f..763169a 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TransparentListActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TransparentListActivity.java
@@ -87,6 +87,7 @@
         ListView list = (ListView) findViewById(R.id.list);
         list.setAdapter(adapter);
         list.setCacheColorHint(0);
+        list.setVerticalFadingEdgeEnabled(true);
 
         registerForContextMenu(list);
     }