Merge "Unhide MotionEvent#actionToString."
diff --git a/api/current.txt b/api/current.txt
index 23da130..b7c1bbd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -21551,6 +21551,7 @@
 
   public final class SynthesisRequest {
     ctor public SynthesisRequest(java.lang.String, android.os.Bundle);
+    method public int getCallerUid();
     method public java.lang.String getCountry();
     method public java.lang.String getLanguage();
     method public android.os.Bundle getParams();
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 3a355f9..f104d71 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -109,7 +109,7 @@
                     break;
                 }
                 case HANDLE_PROVIDERS_CHANGED: {
-                    onProvidersChanged(msg.arg1);
+                    onProvidersChanged();
                     break;
                 }
                 case HANDLE_VIEW_DATA_CHANGED: {
@@ -396,14 +396,6 @@
      * are added, updated or removed, or widget components are enabled or disabled.)
      */
     protected void onProvidersChanged() {
-        onProvidersChanged(mContext.getUserId());
-    }
-
-    /**
-     * Private method containing a userId
-     * @hide
-     */
-    protected void onProvidersChanged(int userId) {
         // Does nothing
     }
 
diff --git a/core/java/android/speech/tts/SynthesisRequest.java b/core/java/android/speech/tts/SynthesisRequest.java
index 6398d3d..917a109 100644
--- a/core/java/android/speech/tts/SynthesisRequest.java
+++ b/core/java/android/speech/tts/SynthesisRequest.java
@@ -41,6 +41,7 @@
     private String mVariant;
     private int mSpeechRate;
     private int mPitch;
+    private int mCallerUid;
 
     public SynthesisRequest(String text, Bundle params) {
         mText = text;
@@ -98,6 +99,13 @@
     }
 
     /**
+     * Gets the request caller Uid.
+     */
+    public int getCallerUid() {
+        return mCallerUid;
+    }
+
+    /**
      * Sets the locale for the request.
      */
     void setLanguage(String language, String country, String variant) {
@@ -119,4 +127,11 @@
     void setPitch(int pitch) {
         mPitch = pitch;
     }
+
+    /**
+     * Sets Caller Uid
+     */
+    void setCallerUid(int uid) {
+        mCallerUid = uid;
+    }
 }
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 703dcff..575855c 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -557,11 +557,13 @@
         // guarded by 'this'.
         private AbstractSynthesisCallback mSynthesisCallback;
         private final EventLogger mEventLogger;
+        private final int mCallerUid;
 
         public SynthesisSpeechItem(Object callerIdentity, int callerUid, int callerPid,
                 Bundle params, String text) {
             super(callerIdentity, callerUid, callerPid, params);
             mText = text;
+            mCallerUid = callerUid;
             mSynthesisRequest = new SynthesisRequest(mText, mParams);
             mDefaultLocale = getSettingsLocale();
             setRequestParams(mSynthesisRequest);
@@ -611,7 +613,7 @@
         private void setRequestParams(SynthesisRequest request) {
             request.setLanguage(getLanguage(), getCountry(), getVariant());
             request.setSpeechRate(getSpeechRate());
-
+            request.setCallerUid(mCallerUid);
             request.setPitch(getPitch());
         }
 
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index ff0579c..55cfd27 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -595,12 +595,13 @@
                     final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
                             (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
 
+                    // Calling overScrollBy will call onOverScrolled, which
+                    // calls onScrollChanged if applicable.
                     if (overScrollBy(deltaX, 0, mScrollX, 0, range, 0,
                             mOverscrollDistance, 0, true)) {
                         // Break our velocity if we hit a scroll barrier.
                         mVelocityTracker.clear();
                     }
-                    onScrollChanged(mScrollX, mScrollY, oldX, oldY);
 
                     if (canOverscroll) {
                         final int pulledToX = oldX + deltaX;
@@ -732,9 +733,12 @@
             boolean clampedX, boolean clampedY) {
         // Treat animating scrolls differently; see #computeScroll() for why.
         if (!mScroller.isFinished()) {
+            final int oldX = mScrollX;
+            final int oldY = mScrollY;
             mScrollX = scrollX;
             mScrollY = scrollY;
             invalidateParentIfNeeded();
+            onScrollChanged(mScrollX, mScrollY, oldX, oldY);
             if (clampedX) {
                 mScroller.springBack(mScrollX, mScrollY, 0, getScrollRange(), 0, 0);
             }
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index bc41931..0545d24 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -631,12 +631,13 @@
                     final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
                             (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
 
+                    // Calling overScrollBy will call onOverScrolled, which
+                    // calls onScrollChanged if applicable.
                     if (overScrollBy(0, deltaY, 0, mScrollY,
                             0, range, 0, mOverscrollDistance, true)) {
                         // Break our velocity if we hit a scroll barrier.
                         mVelocityTracker.clear();
                     }
-                    onScrollChanged(mScrollX, mScrollY, oldX, oldY);
 
                     if (canOverscroll) {
                         final int pulledToY = oldY + deltaY;
@@ -753,9 +754,12 @@
             boolean clampedX, boolean clampedY) {
         // Treat animating scrolls differently; see #computeScroll() for why.
         if (!mScroller.isFinished()) {
+            final int oldX = mScrollX;
+            final int oldY = mScrollY;
             mScrollX = scrollX;
             mScrollY = scrollY;
             invalidateParentIfNeeded();
+            onScrollChanged(mScrollX, mScrollY, oldX, oldY);
             if (clampedY) {
                 mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, getScrollRange());
             }
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 771ac45..5a30472 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -41,6 +41,7 @@
 		SkiaShader.cpp \
 		Snapshot.cpp \
 		Stencil.cpp \
+		Texture.cpp \
 		TextureCache.cpp \
 		TextDropShadowCache.cpp
 
diff --git a/libs/hwui/AssetAtlas.cpp b/libs/hwui/AssetAtlas.cpp
index 8511e7c..782c052 100644
--- a/libs/hwui/AssetAtlas.cpp
+++ b/libs/hwui/AssetAtlas.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "AssetAtlas.h"
+#include "Caches.h"
 
 #include <GLES2/gl2ext.h>
 
@@ -33,12 +34,14 @@
     mImage = new Image(buffer);
 
     if (mImage->getTexture()) {
-        mTexture = new Texture();
+        Caches& caches = Caches::getInstance();
+
+        mTexture = new Texture(caches);
         mTexture->id = mImage->getTexture();
         mTexture->width = buffer->getWidth();
         mTexture->height = buffer->getHeight();
 
-        createEntries(map, count);
+        createEntries(caches, map, count);
     } else {
         ALOGW("Could not create atlas image");
 
@@ -82,7 +85,7 @@
  * instead of applying the changes to the virtual textures.
  */
 struct DelegateTexture: public Texture {
-    DelegateTexture(Texture* delegate): Texture(), mDelegate(delegate) { }
+    DelegateTexture(Caches& caches, Texture* delegate): Texture(caches), mDelegate(delegate) { }
 
     virtual void setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture = false,
             bool force = false, GLenum renderTarget = GL_TEXTURE_2D) {
@@ -100,7 +103,7 @@
 /**
  * TODO: This method does not take the rotation flag into account
  */
-void AssetAtlas::createEntries(int* map, int count) {
+void AssetAtlas::createEntries(Caches& caches, int* map, int count) {
     const float width = float(mTexture->width);
     const float height = float(mTexture->height);
 
@@ -117,7 +120,7 @@
                 x / width, (x + bitmap->width()) / width,
                 y / height, (y + bitmap->height()) / height);
 
-        Texture* texture = new DelegateTexture(mTexture);
+        Texture* texture = new DelegateTexture(caches, mTexture);
         Entry* entry = new Entry(bitmap, x, y, rotated, texture, mapper, *this);
 
         texture->id = mTexture->id;
diff --git a/libs/hwui/AssetAtlas.h b/libs/hwui/AssetAtlas.h
index 793e300..2624907 100644
--- a/libs/hwui/AssetAtlas.h
+++ b/libs/hwui/AssetAtlas.h
@@ -34,6 +34,8 @@
 namespace android {
 namespace uirenderer {
 
+class Caches;
+
 /**
  * An asset atlas holds a collection of framework bitmaps in a single OpenGL
  * texture. Each bitmap is associated with a location, defined in pixels,
@@ -157,7 +159,7 @@
     Texture* getEntryTexture(SkBitmap* const bitmap) const;
 
 private:
-    void createEntries(int* map, int count);
+    void createEntries(Caches& caches, int* map, int count);
 
     Texture* mTexture;
     Image* mImage;
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 9d5a854..23b5d76 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -47,7 +47,8 @@
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-Caches::Caches(): Singleton<Caches>(), mExtensions(Extensions::getInstance()), mInitialized(false) {
+Caches::Caches(): Singleton<Caches>(),
+        mExtensions(Extensions::getInstance()), mInitialized(false) {
     init();
     initFont();
     initConstraints();
@@ -100,6 +101,8 @@
 
     mInitialized = true;
 
+    resetBoundTextures();
+
     return true;
 }
 
@@ -491,6 +494,24 @@
     }
 }
 
+void Caches::bindTexture(GLuint texture) {
+    if (mBoundTextures[mTextureUnit] != texture) {
+        glBindTexture(GL_TEXTURE_2D, texture);
+        mBoundTextures[mTextureUnit] = texture;
+    }
+}
+
+void Caches::bindTexture(GLenum target, GLuint texture) {
+    if (mBoundTextures[mTextureUnit] != texture) {
+        glBindTexture(target, texture);
+        mBoundTextures[mTextureUnit] = texture;
+    }
+}
+
+void Caches::resetBoundTextures() {
+    memset(mBoundTextures, 0, REQUIRED_TEXTURE_UNITS_COUNT * sizeof(GLuint));
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Scissor
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 54e4138..bd31ec3 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -55,6 +55,7 @@
 // Globals
 ///////////////////////////////////////////////////////////////////////////////
 
+// GL ES 2.0 defines that at least 16 texture units must be supported
 #define REQUIRED_TEXTURE_UNITS_COUNT 3
 
 #define REGION_MESH_QUAD_COUNT 512
@@ -79,6 +80,7 @@
 static const GLsizei gVertexAALengthOffset = 3 * sizeof(float);
 static const GLsizei gMeshCount = 4;
 
+// Must define as many texture units as specified by REQUIRED_TEXTURE_UNITS_COUNT
 static const GLenum gTextureUnits[] = {
     GL_TEXTURE0,
     GL_TEXTURE1,
@@ -223,6 +225,22 @@
     void activeTexture(GLuint textureUnit);
 
     /**
+     * Binds the specified texture as a GL_TEXTURE_2D texture.
+     */
+    void bindTexture(GLuint texture);
+
+    /**
+     * Binds the specified texture..
+     */
+    void bindTexture(GLenum target, GLuint texture);
+
+    /**
+     * Signals that the cache of bound textures should be cleared.
+     * Other users of the context may have altered which textures are bound.
+     */
+    void resetBoundTextures();
+
+    /**
      * Sets the scissor for the current surface.
      */
     bool setScissor(GLint x, GLint y, GLint width, GLint height);
@@ -363,6 +381,8 @@
     bool mInitialized;
 
     uint32_t mFunctorsCount;
+
+    GLuint mBoundTextures[REQUIRED_TEXTURE_UNITS_COUNT];
 }; // class Caches
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp
index 19b3849..4dc85e0 100644
--- a/libs/hwui/Dither.cpp
+++ b/libs/hwui/Dither.cpp
@@ -24,12 +24,15 @@
 // Lifecycle
 ///////////////////////////////////////////////////////////////////////////////
 
+Dither::Dither(): mCaches(NULL), mInitialized(false), mDitherTexture(0) {
+}
+
 void Dither::bindDitherTexture() {
     if (!mInitialized) {
         bool useFloatTexture = Extensions::getInstance().getMajorGlVersion() >= 3;
 
         glGenTextures(1, &mDitherTexture);
-        glBindTexture(GL_TEXTURE_2D, mDitherTexture);
+        mCaches->bindTexture(mDitherTexture);
 
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -68,7 +71,7 @@
 
         mInitialized = true;
     } else {
-        glBindTexture(GL_TEXTURE_2D, mDitherTexture);
+        mCaches->bindTexture(mDitherTexture);
     }
 }
 
@@ -84,8 +87,10 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void Dither::setupProgram(Program* program, GLuint* textureUnit) {
+    if (!mCaches) mCaches = &Caches::getInstance();
+
     GLuint textureSlot = (*textureUnit)++;
-    Caches::getInstance().activeTexture(textureSlot);
+    mCaches->activeTexture(textureSlot);
 
     bindDitherTexture();
 
diff --git a/libs/hwui/Dither.h b/libs/hwui/Dither.h
index 4d1f921..546236be 100644
--- a/libs/hwui/Dither.h
+++ b/libs/hwui/Dither.h
@@ -24,9 +24,7 @@
 namespace android {
 namespace uirenderer {
 
-///////////////////////////////////////////////////////////////////////////////
-// Defines
-///////////////////////////////////////////////////////////////////////////////
+class Caches;
 
 // Must be a power of two
 #define DITHER_KERNEL_SIZE 4
@@ -39,7 +37,7 @@
  */
 class Dither {
 public:
-    Dither(): mInitialized(false), mDitherTexture(0) { }
+    Dither();
 
     void clear();
     void setupProgram(Program* program, GLuint* textureUnit);
@@ -47,6 +45,7 @@
 private:
     void bindDitherTexture();
 
+    Caches* mCaches;
     bool mInitialized;
     GLuint mDitherTexture;
 };
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index a9bf13e..3e3d882 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -376,7 +376,7 @@
             if (cacheTexture->getTextureId() != lastTextureId) {
                 lastTextureId = cacheTexture->getTextureId();
                 caches.activeTexture(0);
-                glBindTexture(GL_TEXTURE_2D, lastTextureId);
+                caches.bindTexture(lastTextureId);
             }
 
             if (cacheTexture->upload()) {
@@ -429,7 +429,7 @@
                 first = false;
             }
 
-            glBindTexture(GL_TEXTURE_2D, texture->getTextureId());
+            caches.bindTexture(texture->getTextureId());
             texture->setLinearFiltering(mLinearFiltering, false);
 
             TextureVertex* mesh = texture->mesh();
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 507ed95..1ed04fa 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -173,7 +173,7 @@
     GradientInfo info;
     getGradientInfo(colors, count, info);
 
-    Texture* texture = new Texture;
+    Texture* texture = new Texture();
     texture->width = info.width;
     texture->height = 2;
     texture->blend = info.hasAlpha;
@@ -286,7 +286,7 @@
     memcpy(pixels + rowBytes, pixels, rowBytes);
 
     glGenTextures(1, &texture->id);
-    glBindTexture(GL_TEXTURE_2D, texture->id);
+    Caches::getInstance().bindTexture(texture->id);
     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
 
     if (mUseFloatTexture) {
diff --git a/libs/hwui/Image.cpp b/libs/hwui/Image.cpp
index 35ca40d..77c2300 100644
--- a/libs/hwui/Image.cpp
+++ b/libs/hwui/Image.cpp
@@ -18,6 +18,7 @@
 
 #include <utils/Log.h>
 
+#include "Caches.h"
 #include "Image.h"
 
 namespace android {
@@ -38,7 +39,7 @@
     } else {
         // Create a 2D texture to sample from the EGLImage
         glGenTextures(1, &mTexture);
-        glBindTexture(GL_TEXTURE_2D, mTexture);
+        Caches::getInstance().bindTexture(mTexture);
         glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, mImage);
 
         GLenum status = GL_NO_ERROR;
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 4adad05..60c38ba 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -28,7 +28,8 @@
 namespace android {
 namespace uirenderer {
 
-Layer::Layer(const uint32_t layerWidth, const uint32_t layerHeight) {
+Layer::Layer(const uint32_t layerWidth, const uint32_t layerHeight):
+        caches(Caches::getInstance()), texture(caches) {
     mesh = NULL;
     meshIndices = NULL;
     meshElementCount = 0;
@@ -47,11 +48,11 @@
     debugDrawUpdate = false;
     hasDrawnSinceUpdate = false;
     deferredList = NULL;
-    Caches::getInstance().resourceCache.incrementRefcount(this);
+    caches.resourceCache.incrementRefcount(this);
 }
 
 Layer::~Layer() {
-    if (colorFilter) Caches::getInstance().resourceCache.decrementRefcount(colorFilter);
+    if (colorFilter) caches.resourceCache.decrementRefcount(colorFilter);
     removeFbo();
     deleteTexture();
 
@@ -76,7 +77,7 @@
         return true;
     }
 
-    const uint32_t maxTextureSize = Caches::getInstance().maxTextureSize;
+    const uint32_t maxTextureSize = caches.maxTextureSize;
     if (desiredWidth > maxTextureSize || desiredHeight > maxTextureSize) {
         ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)",
                 desiredWidth, desiredHeight, maxTextureSize, maxTextureSize);
@@ -89,7 +90,7 @@
     setSize(desiredWidth, desiredHeight);
 
     if (fbo) {
-        Caches::getInstance().activeTexture(0);
+        caches.activeTexture(0);
         bindTexture();
         allocateTexture();
 
@@ -120,14 +121,14 @@
         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
         if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
 
-        Caches::getInstance().renderBufferCache.put(stencil);
+        caches.renderBufferCache.put(stencil);
         stencil = NULL;
     }
 
     if (fbo) {
         if (flush) LayerRenderer::flushLayer(this);
         // If put fails the cache will delete the FBO
-        Caches::getInstance().fboCache.put(fbo);
+        caches.fboCache.put(fbo);
         fbo = 0;
     }
 }
@@ -138,11 +139,51 @@
 
 void Layer::setColorFilter(SkiaColorFilter* filter) {
     if (colorFilter) {
-        Caches::getInstance().resourceCache.decrementRefcount(colorFilter);
+        caches.resourceCache.decrementRefcount(colorFilter);
     }
     colorFilter = filter;
     if (colorFilter) {
-        Caches::getInstance().resourceCache.incrementRefcount(colorFilter);
+        caches.resourceCache.incrementRefcount(colorFilter);
+    }
+}
+
+void Layer::bindTexture() const {
+    if (texture.id) {
+        caches.bindTexture(renderTarget, texture.id);
+    }
+}
+
+void Layer::bindStencilRenderBuffer() const {
+    if (stencil) {
+        stencil->bind();
+    }
+}
+
+void Layer::generateTexture() {
+    if (!texture.id) {
+        glGenTextures(1, &texture.id);
+    }
+}
+
+void Layer::deleteTexture() {
+    if (texture.id) {
+        glDeleteTextures(1, &texture.id);
+        texture.id = 0;
+    }
+}
+
+void Layer::clearTexture() {
+    texture.id = 0;
+}
+
+void Layer::allocateTexture() {
+#if DEBUG_LAYERS
+    ALOGD("  Allocate layer: %dx%d", getWidth(), getHeight());
+#endif
+    if (texture.id) {
+        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+        glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, NULL);
     }
 }
 
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 7186603..326b25a 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -40,6 +40,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 // Forward declarations
+class Caches;
 class OpenGLRenderer;
 class DisplayList;
 class DeferredDisplayList;
@@ -221,50 +222,19 @@
 
     ANDROID_API void setColorFilter(SkiaColorFilter* filter);
 
-    inline void bindTexture() const {
-        if (texture.id) {
-            glBindTexture(renderTarget, texture.id);
-        }
-    }
+    void bindStencilRenderBuffer() const;
 
-    inline void bindStencilRenderBuffer() const {
-        if (stencil) {
-            stencil->bind();
-        }
-    }
-
-    inline void generateTexture() {
-        if (!texture.id) {
-            glGenTextures(1, &texture.id);
-        }
-    }
-
-    inline void deleteTexture() {
-        if (texture.id) {
-            glDeleteTextures(1, &texture.id);
-            texture.id = 0;
-        }
-    }
+    void bindTexture() const;
+    void generateTexture();
+    void allocateTexture();
+    void deleteTexture();
 
     /**
      * When the caller frees the texture itself, the caller
      * must call this method to tell this layer that it lost
      * the texture.
      */
-    void clearTexture() {
-        texture.id = 0;
-    }
-
-    inline void allocateTexture() {
-#if DEBUG_LAYERS
-        ALOGD("  Allocate layer: %dx%d", getWidth(), getHeight());
-#endif
-        if (texture.id) {
-            glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
-            glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0,
-                    GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-        }
-    }
+    ANDROID_API void clearTexture();
 
     inline mat4& getTexTransform() {
         return texTransform;
@@ -320,6 +290,8 @@
     bool hasDrawnSinceUpdate;
 
 private:
+    Caches& caches;
+
     /**
      * Name of the FBO used to render the layer. If the name is 0
      * this layer is not backed by an FBO, but a simple texture.
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 3e55fff..987daae 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -436,7 +436,7 @@
         if ((error = glGetError()) != GL_NO_ERROR) goto error;
 
         caches.activeTexture(0);
-        glBindTexture(GL_TEXTURE_2D, texture);
+        caches.bindTexture(texture);
 
         glPixelStorei(GL_PACK_ALIGNMENT, bitmap->bytesPerPixel());
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index f12119a..f5343b1 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -371,6 +371,7 @@
     dirtyClip();
 
     mCaches.activeTexture(0);
+    mCaches.resetBoundTextures();
 
     mCaches.blend = true;
     glEnable(GL_BLEND);
@@ -3109,7 +3110,7 @@
 void OpenGLRenderer::setupShader(SkiaShader* shader) {
     mDrawModifiers.mShader = shader;
     if (mDrawModifiers.mShader) {
-        mDrawModifiers.mShader->set(&mCaches.textureCache, &mCaches.gradientCache);
+        mDrawModifiers.mShader->setCaches(mCaches);
     }
 }
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 6286e94..e9ea2f32 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -888,7 +888,7 @@
      * prior to calling this method.
      */
     inline void bindTexture(GLuint texture) {
-        glBindTexture(GL_TEXTURE_2D, texture);
+        mCaches.bindTexture(texture);
     }
 
     /**
@@ -896,7 +896,7 @@
      * prior to calling this method.
      */
     inline void bindExternalTexture(GLuint texture) {
-        glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
+        mCaches.bindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
     }
 
     /**
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index fdb10e2..3f6485c 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -139,7 +139,7 @@
 
 static PathTexture* createTexture(float left, float top, float offset,
         uint32_t width, uint32_t height, uint32_t id) {
-    PathTexture* texture = new PathTexture();
+    PathTexture* texture = new PathTexture(Caches::getInstance());
     texture->left = left;
     texture->top = top;
     texture->offset = offset;
@@ -300,7 +300,7 @@
 
     glGenTextures(1, &texture->id);
 
-    glBindTexture(GL_TEXTURE_2D, texture->id);
+    Caches::getInstance().bindTexture(texture->id);
     // Textures are Alpha8
     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index dd1f996..a191f0e 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -58,7 +58,7 @@
  * Alpha texture used to represent a path.
  */
 struct PathTexture: public Texture {
-    PathTexture(): Texture() {
+    PathTexture(Caches& caches): Texture(caches) {
     }
 
     ~PathTexture() {
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index c38eedb..797ed10 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -69,9 +69,13 @@
     mGenerationId = shader.mGenerationId;
 }
 
+SkiaShader::SkiaShader(): mCaches(NULL) {
+}
+
 SkiaShader::SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
         SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
-        mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend) {
+        mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend),
+        mCaches(NULL) {
     setMatrix(matrix);
     mGenerationId = 0;
 }
@@ -87,7 +91,7 @@
 }
 
 void SkiaShader::bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT) {
-    glBindTexture(GL_TEXTURE_2D, texture->id);
+    mCaches->bindTexture(texture->id);
     texture->setWrapST(wrapS, wrapT);
 }
 
@@ -114,7 +118,7 @@
 }
 
 void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) {
-    Texture* texture = mTextureCache->get(mBitmap);
+    Texture* texture = mCaches->textureCache.get(mBitmap);
     if (!texture) return;
     mTexture = texture;
 
@@ -229,7 +233,7 @@
         GLuint textureSlot = (*textureUnit)++;
         Caches::getInstance().activeTexture(textureSlot);
 
-        Texture* texture = mGradientCache->get(mColors, mPositions, mCount);
+        Texture* texture = mCaches->gradientCache.get(mColors, mPositions, mCount);
 
         // Uniforms
         bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
@@ -349,7 +353,7 @@
         GLuint textureSlot = (*textureUnit)++;
         Caches::getInstance().activeTexture(textureSlot);
 
-        Texture* texture = mGradientCache->get(mColors, mPositions, mCount);
+        Texture* texture = mCaches->gradientCache.get(mColors, mPositions, mCount);
 
         // Uniforms
         bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
@@ -359,7 +363,7 @@
        bindUniformColor(program->getUniform("endColor"), mColors[1]);
     }
 
-    Caches::getInstance().dither.setupProgram(program, textureUnit);
+    mCaches->dither.setupProgram(program, textureUnit);
 
     mat4 screenSpace;
     computeScreenSpaceMatrix(screenSpace, modelView);
@@ -394,12 +398,6 @@
     return copy;
 }
 
-void SkiaComposeShader::set(TextureCache* textureCache, GradientCache* gradientCache) {
-    SkiaShader::set(textureCache, gradientCache);
-    mFirst->set(textureCache, gradientCache);
-    mSecond->set(textureCache, gradientCache);
-}
-
 void SkiaComposeShader::describe(ProgramDescription& description, const Extensions& extensions) {
     mFirst->describe(description, extensions);
     mSecond->describe(description, extensions);
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index bc12b0d..a63431c 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -33,6 +33,8 @@
 namespace android {
 namespace uirenderer {
 
+class Caches;
+
 ///////////////////////////////////////////////////////////////////////////////
 // Base shader
 ///////////////////////////////////////////////////////////////////////////////
@@ -77,9 +79,8 @@
         return mType;
     }
 
-    virtual void set(TextureCache* textureCache, GradientCache* gradientCache) {
-        mTextureCache = textureCache;
-        mGradientCache = gradientCache;
+    virtual void setCaches(Caches& caches) {
+        mCaches = &caches;
     }
 
     uint32_t getGenerationId() {
@@ -103,8 +104,7 @@
     void computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView);
 
 protected:
-    SkiaShader() {
-    }
+    SkiaShader();
 
     /**
      * The appropriate texture unit must have been activated prior to invoking
@@ -118,8 +118,7 @@
     SkShader::TileMode mTileY;
     bool mBlend;
 
-    TextureCache* mTextureCache;
-    GradientCache* mGradientCache;
+    Caches* mCaches;
 
     mat4 mUnitMatrix;
     mat4 mShaderMatrix;
@@ -229,7 +228,11 @@
     ~SkiaComposeShader();
     SkiaShader* copy();
 
-    void set(TextureCache* textureCache, GradientCache* gradientCache);
+    void setCaches(Caches& caches) {
+        SkiaShader::setCaches(caches);
+        mFirst->setCaches(caches);
+        mSecond->setCaches(caches);
+    }
 
     void describe(ProgramDescription& description, const Extensions& extensions);
     void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp
index 6976eaa..3b6cb91 100644
--- a/libs/hwui/TextDropShadowCache.cpp
+++ b/libs/hwui/TextDropShadowCache.cpp
@@ -18,6 +18,7 @@
 
 #include <utils/JenkinsHash.h>
 
+#include "Caches.h"
 #include "Debug.h"
 #include "TextDropShadowCache.h"
 #include "Properties.h"
@@ -182,7 +183,9 @@
             return NULL;
         }
 
-        texture = new ShadowTexture;
+        Caches& caches = Caches::getInstance();
+
+        texture = new ShadowTexture(caches);
         texture->left = shadow.penX;
         texture->top = shadow.penY;
         texture->width = shadow.width;
@@ -202,7 +205,7 @@
 
         glGenTextures(1, &texture->id);
 
-        glBindTexture(GL_TEXTURE_2D, texture->id);
+        caches.bindTexture(texture->id);
         // Textures are Alpha8
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h
index 0bed72b6..04d7357 100644
--- a/libs/hwui/TextDropShadowCache.h
+++ b/libs/hwui/TextDropShadowCache.h
@@ -30,6 +30,8 @@
 namespace android {
 namespace uirenderer {
 
+class Caches;
+
 struct ShadowText {
     ShadowText(): len(0), radius(0.0f), textSize(0.0f), typeface(NULL),
             flags(0), italicStyle(0.0f), scaleX(0), text(NULL), positions(NULL) {
@@ -114,7 +116,7 @@
  * Alpha texture used to represent a shadow.
  */
 struct ShadowTexture: public Texture {
-    ShadowTexture(): Texture() {
+    ShadowTexture(Caches& caches): Texture(caches) {
     }
 
     float left;
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
new file mode 100644
index 0000000..e06227c
--- /dev/null
+++ b/libs/hwui/Texture.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <utils/Log.h>
+
+#include "Caches.h"
+#include "Texture.h"
+
+namespace android {
+namespace uirenderer {
+
+Texture::Texture(): id(0), generation(0), blend(false), width(0), height(0),
+        cleanup(false), bitmapSize(0), mipMap(false), uvMapper(NULL),
+        mWrapS(GL_CLAMP_TO_EDGE), mWrapT(GL_CLAMP_TO_EDGE),
+        mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST),
+        mFirstFilter(true), mFirstWrap(true), mCaches(Caches::getInstance()) {
+}
+
+Texture::Texture(Caches& caches): id(0), generation(0), blend(false), width(0), height(0),
+        cleanup(false), bitmapSize(0), mipMap(false), uvMapper(NULL),
+        mWrapS(GL_CLAMP_TO_EDGE), mWrapT(GL_CLAMP_TO_EDGE),
+        mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST),
+        mFirstFilter(true), mFirstWrap(true), mCaches(caches) {
+}
+
+void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force,
+        GLenum renderTarget) {
+
+    if (mFirstWrap || force || wrapS != mWrapS || wrapT != mWrapT) {
+        mFirstWrap = false;
+
+        mWrapS = wrapS;
+        mWrapT = wrapT;
+
+        if (bindTexture) {
+            mCaches.bindTexture(renderTarget, id);
+        }
+
+        glTexParameteri(renderTarget, GL_TEXTURE_WRAP_S, wrapS);
+        glTexParameteri(renderTarget, GL_TEXTURE_WRAP_T, wrapT);
+    }
+}
+
+void Texture::setFilterMinMag(GLenum min, GLenum mag, bool bindTexture, bool force,
+        GLenum renderTarget) {
+
+    if (mFirstFilter || force || min != mMinFilter || mag != mMagFilter) {
+        mFirstFilter = false;
+
+        mMinFilter = min;
+        mMagFilter = mag;
+
+        if (bindTexture) {
+            mCaches.bindTexture(renderTarget, id);
+        }
+
+        if (mipMap && min == GL_LINEAR) min = GL_LINEAR_MIPMAP_LINEAR;
+
+        glTexParameteri(renderTarget, GL_TEXTURE_MIN_FILTER, min);
+        glTexParameteri(renderTarget, GL_TEXTURE_MAG_FILTER, mag);
+    }
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index f84cd67..d249741 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -22,81 +22,34 @@
 namespace android {
 namespace uirenderer {
 
+class Caches;
 class UvMapper;
 
 /**
  * Represents an OpenGL texture.
  */
-struct Texture {
-    Texture() {
-        cleanup = false;
-        bitmapSize = 0;
-
-        wrapS = GL_CLAMP_TO_EDGE;
-        wrapT = GL_CLAMP_TO_EDGE;
-
-        minFilter = GL_NEAREST;
-        magFilter = GL_NEAREST;
-
-        mipMap = false;
-
-        firstFilter = true;
-        firstWrap = true;
-
-        id = 0;
-
-        uvMapper = NULL;
-    }
+class Texture {
+public:
+    Texture();
+    Texture(Caches& caches);
 
     virtual ~Texture() { }
 
-    void setWrap(GLenum wrap, bool bindTexture = false, bool force = false,
+    inline void setWrap(GLenum wrap, bool bindTexture = false, bool force = false,
                 GLenum renderTarget = GL_TEXTURE_2D) {
         setWrapST(wrap, wrap, bindTexture, force, renderTarget);
     }
 
     virtual void setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture = false,
-            bool force = false, GLenum renderTarget = GL_TEXTURE_2D) {
+            bool force = false, GLenum renderTarget = GL_TEXTURE_2D);
 
-        if (firstWrap || force || wrapS != this->wrapS || wrapT != this->wrapT) {
-            firstWrap = false;
-
-            this->wrapS = wrapS;
-            this->wrapT = wrapT;
-
-            if (bindTexture) {
-                glBindTexture(renderTarget, id);
-            }
-
-            glTexParameteri(renderTarget, GL_TEXTURE_WRAP_S, wrapS);
-            glTexParameteri(renderTarget, GL_TEXTURE_WRAP_T, wrapT);
-        }
-    }
-
-    void setFilter(GLenum filter, bool bindTexture = false, bool force = false,
+    inline void setFilter(GLenum filter, bool bindTexture = false, bool force = false,
                 GLenum renderTarget = GL_TEXTURE_2D) {
         setFilterMinMag(filter, filter, bindTexture, force, renderTarget);
     }
 
     virtual void setFilterMinMag(GLenum min, GLenum mag, bool bindTexture = false,
-            bool force = false, GLenum renderTarget = GL_TEXTURE_2D) {
-
-        if (firstFilter || force || min != minFilter || mag != magFilter) {
-            firstFilter = false;
-
-            minFilter = min;
-            magFilter = mag;
-
-            if (bindTexture) {
-                glBindTexture(renderTarget, id);
-            }
-
-            if (mipMap && min == GL_LINEAR) min = GL_LINEAR_MIPMAP_LINEAR;
-
-            glTexParameteri(renderTarget, GL_TEXTURE_MIN_FILTER, min);
-            glTexParameteri(renderTarget, GL_TEXTURE_MAG_FILTER, mag);
-        }
-    }
+            bool force = false, GLenum renderTarget = GL_TEXTURE_2D);
 
     /**
      * Name of the texture.
@@ -140,17 +93,19 @@
     /**
      * Last wrap modes set on this texture. Defaults to GL_CLAMP_TO_EDGE.
      */
-    GLenum wrapS;
-    GLenum wrapT;
+    GLenum mWrapS;
+    GLenum mWrapT;
 
     /**
      * Last filters set on this texture. Defaults to GL_NEAREST.
      */
-    GLenum minFilter;
-    GLenum magFilter;
+    GLenum mMinFilter;
+    GLenum mMagFilter;
 
-    bool firstFilter;
-    bool firstWrap;
+    bool mFirstFilter;
+    bool mFirstWrap;
+
+    Caches& mCaches;
 }; // struct Texture
 
 class AutoTexture {
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 2378eb5..7f5b80f 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -139,7 +139,7 @@
             }
         }
 
-        texture = new Texture;
+        texture = new Texture();
         texture->bitmapSize = size;
         generateTexture(bitmap, texture, false);
 
@@ -162,7 +162,7 @@
 }
 
 Texture* TextureCache::getTransient(SkBitmap* bitmap) {
-    Texture* texture = new Texture;
+    Texture* texture = new Texture();
     texture->bitmapSize = bitmap->rowBytes() * bitmap->height();
     texture->cleanup = true;
 
@@ -235,7 +235,7 @@
     texture->width = bitmap->width();
     texture->height = bitmap->height();
 
-    glBindTexture(GL_TEXTURE_2D, texture->id);
+    Caches::getInstance().bindTexture(texture->id);
 
     switch (bitmap->getConfig()) {
     case SkBitmap::kA8_Config:
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index 6c5267d..2d58338 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -17,6 +17,7 @@
 #include <SkGlyph.h>
 
 #include "CacheTexture.h"
+#include "../Caches.h"
 #include "../Debug.h"
 #include "../Extensions.h"
 #include "../PixelBuffer.h"
@@ -110,7 +111,8 @@
 CacheTexture::CacheTexture(uint16_t width, uint16_t height, uint32_t maxQuadCount) :
             mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height),
             mLinearFiltering(false), mDirty(false), mNumGlyphs(0),
-            mMesh(NULL), mCurrentQuad(0), mMaxQuadCount(maxQuadCount) {
+            mMesh(NULL), mCurrentQuad(0), mMaxQuadCount(maxQuadCount),
+            mCaches(Caches::getInstance()) {
     mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
             mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
 
@@ -166,7 +168,7 @@
        mLinearFiltering = linearFiltering;
 
        const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
-       if (bind) glBindTexture(GL_TEXTURE_2D, getTextureId());
+       if (bind) mCaches.bindTexture(getTextureId());
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
    }
@@ -186,7 +188,7 @@
     if (!mTextureId) {
         glGenTextures(1, &mTextureId);
 
-        glBindTexture(GL_TEXTURE_2D, mTextureId);
+        mCaches.bindTexture(mTextureId);
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
         // Initialize texture dimensions
         glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mWidth, mHeight, 0,
diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h
index ddcc836..8c3ea0b 100644
--- a/libs/hwui/font/CacheTexture.h
+++ b/libs/hwui/font/CacheTexture.h
@@ -30,6 +30,7 @@
 namespace android {
 namespace uirenderer {
 
+class Caches;
 class PixelBuffer;
 
 /**
@@ -178,9 +179,10 @@
     TextureVertex* mMesh;
     uint32_t mCurrentQuad;
     uint32_t mMaxQuadCount;
+    Caches& mCaches;
     CacheBlock* mCacheBlocks;
-    Rect mDirtyRect;
     bool mHasES3;
+    Rect mDirtyRect;
 };
 
 }; // namespace uirenderer