Merge "Add implementations for saveLayerAlpha() and textured rects."
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 5c24058..aafd3ff 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -278,30 +278,34 @@
@Override
public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
- // TODO: Implement
- return 0;
+ return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags);
}
@Override
public int saveLayer(float left, float top, float right, float bottom, Paint paint,
int saveFlags) {
- // TODO: Implement
- return 0;
+ int nativePaint = paint == null ? 0 : paint.mNativePaint;
+ return nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
}
+ private native int nSaveLayer(int renderer, float left, float top, float right, float bottom,
+ int paint, int saveFlags);
+
@Override
public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
- // TODO: Implement
- return 0;
+ return saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom,
+ alpha, saveFlags);
}
@Override
public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
int saveFlags) {
- // TODO: Implement
- return 0;
+ return nSaveLayerAlpha(mRenderer, left, top, right, bottom, alpha, saveFlags);
}
+ private native int nSaveLayerAlpha(int renderer, float left, float top, float right,
+ float bottom, int alpha, int saveFlags);
+
@Override
public void restore() {
nRestore(mRenderer);
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index d3b6558..fd9ce44 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -92,6 +92,22 @@
}
// ----------------------------------------------------------------------------
+// Layers
+// ----------------------------------------------------------------------------
+
+static jint android_view_GLES20Renderer_saveLayer(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
+ SkPaint* paint, jint saveFlags) {
+ return renderer->saveLayer(left, top, right, bottom, paint, saveFlags);
+}
+
+static jint android_view_GLES20Renderer_saveLayerAlpha(JNIEnv* env, jobject canvas,
+ OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
+ jint alpha, jint saveFlags) {
+ return renderer->saveLayerAlpha(left, top, right, bottom, alpha, saveFlags);
+}
+
+// ----------------------------------------------------------------------------
// Clipping
// ----------------------------------------------------------------------------
@@ -178,30 +194,33 @@
const char* const kClassPathName = "android/view/GLES20Canvas";
static JNINativeMethod gMethods[] = {
- { "nCreateRenderer", "()I", (void*) android_view_GLES20Renderer_createRenderer },
- { "nDestroyRenderer", "(I)V", (void*) android_view_GLES20Renderer_destroyRenderer },
- { "nSetViewport", "(III)V", (void*) android_view_GLES20Renderer_setViewport },
- { "nPrepare", "(I)V", (void*) android_view_GLES20Renderer_prepare },
+ { "nCreateRenderer", "()I", (void*) android_view_GLES20Renderer_createRenderer },
+ { "nDestroyRenderer", "(I)V", (void*) android_view_GLES20Renderer_destroyRenderer },
+ { "nSetViewport", "(III)V", (void*) android_view_GLES20Renderer_setViewport },
+ { "nPrepare", "(I)V", (void*) android_view_GLES20Renderer_prepare },
- { "nSave", "(II)I", (void*) android_view_GLES20Renderer_save },
- { "nRestore", "(I)V", (void*) android_view_GLES20Renderer_restore },
- { "nRestoreToCount", "(II)V", (void*) android_view_GLES20Renderer_restoreToCount },
- { "nGetSaveCount", "(I)I", (void*) android_view_GLES20Renderer_getSaveCount },
+ { "nSave", "(II)I", (void*) android_view_GLES20Renderer_save },
+ { "nRestore", "(I)V", (void*) android_view_GLES20Renderer_restore },
+ { "nRestoreToCount", "(II)V", (void*) android_view_GLES20Renderer_restoreToCount },
+ { "nGetSaveCount", "(I)I", (void*) android_view_GLES20Renderer_getSaveCount },
- { "nQuickReject", "(IFFFFI)Z", (void*) android_view_GLES20Renderer_quickReject },
- { "nClipRect", "(IFFFF)Z", (void*) android_view_GLES20Renderer_clipRectF },
- { "nClipRect", "(IIIII)Z", (void*) android_view_GLES20Renderer_clipRect },
+ { "nSaveLayer", "(IFFFFII)I", (void*) android_view_GLES20Renderer_saveLayer },
+ { "nSaveLayerAlpha", "(IFFFFII)I", (void*) android_view_GLES20Renderer_saveLayerAlpha },
- { "nTranslate", "(IFF)V", (void*) android_view_GLES20Renderer_translate },
- { "nRotate", "(IF)V", (void*) android_view_GLES20Renderer_rotate },
- { "nScale", "(IFF)V", (void*) android_view_GLES20Renderer_scale },
+ { "nQuickReject", "(IFFFFI)Z", (void*) android_view_GLES20Renderer_quickReject },
+ { "nClipRect", "(IFFFF)Z", (void*) android_view_GLES20Renderer_clipRectF },
+ { "nClipRect", "(IIIII)Z", (void*) android_view_GLES20Renderer_clipRect },
- { "nSetMatrix", "(II)V", (void*) android_view_GLES20Renderer_setMatrix },
- { "nGetMatrix", "(II)V", (void*) android_view_GLES20Renderer_getMatrix },
- { "nConcatMatrix", "(II)V", (void*) android_view_GLES20Renderer_concatMatrix },
+ { "nTranslate", "(IFF)V", (void*) android_view_GLES20Renderer_translate },
+ { "nRotate", "(IF)V", (void*) android_view_GLES20Renderer_rotate },
+ { "nScale", "(IFF)V", (void*) android_view_GLES20Renderer_scale },
- { "nDrawColor", "(III)V", (void*) android_view_GLES20Renderer_drawColor },
- { "nDrawRect", "(IFFFFI)V", (void*) android_view_GLES20Renderer_drawRect },
+ { "nSetMatrix", "(II)V", (void*) android_view_GLES20Renderer_setMatrix },
+ { "nGetMatrix", "(II)V", (void*) android_view_GLES20Renderer_getMatrix },
+ { "nConcatMatrix", "(II)V", (void*) android_view_GLES20Renderer_concatMatrix },
+
+ { "nDrawColor", "(III)V", (void*) android_view_GLES20Renderer_drawColor },
+ { "nDrawRect", "(IFFFFI)V", (void*) android_view_GLES20Renderer_drawRect },
{ "nGetClipBounds", "(ILandroid/graphics/Rect;)Z",
(void*) android_view_GLES20Renderer_getClipBounds },
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index c772f00..e9c7791 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -97,6 +97,14 @@
memcpy(v, data, sizeof(data));
}
+float Matrix4::getTranslateX() {
+ return data[12];
+}
+
+float Matrix4::getTranslateY() {
+ return data[13];
+}
+
void Matrix4::loadTranslate(float x, float y, float z) {
loadIdentity();
data[12] = x;
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index fa9638b..40c80fa 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -90,6 +90,9 @@
void mapRect(Rect& r) const;
+ float getTranslateX();
+ float getTranslateY();
+
void dump() const;
private:
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 830e0c3..786b927 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -27,6 +27,7 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+#include <SkCanvas.h>
#include <SkPaint.h>
#include <SkXfermode.h>
@@ -40,21 +41,31 @@
// Defines
///////////////////////////////////////////////////////////////////////////////
-#define V(x, y) { { x, y } }
+#define SV(x, y) { { x, y } }
+#define FV(x, y, u, v) { { x, y }, { u, v } }
///////////////////////////////////////////////////////////////////////////////
// Globals
///////////////////////////////////////////////////////////////////////////////
const SimpleVertex gDrawColorVertices[] = {
- V(0.0f, 0.0f),
- V(1.0f, 0.0f),
- V(0.0f, 1.0f),
- V(1.0f, 1.0f)
+ SV(0.0f, 0.0f),
+ SV(1.0f, 0.0f),
+ SV(0.0f, 1.0f),
+ SV(1.0f, 1.0f)
};
const GLsizei gDrawColorVertexStride = sizeof(SimpleVertex);
const GLsizei gDrawColorVertexCount = 4;
+const TextureVertex gDrawTextureVertices[] = {
+ FV(0.0f, 0.0f, 0.0f, 1.0f),
+ FV(1.0f, 0.0f, 1.0f, 1.0f),
+ FV(0.0f, 1.0f, 0.0f, 0.0f),
+ FV(1.0f, 1.0f, 1.0f, 0.0f)
+};
+const GLsizei gDrawTextureVertexStride = sizeof(TextureVertex);
+const GLsizei gDrawTextureVertexCount = 4;
+
///////////////////////////////////////////////////////////////////////////////
// Shaders
///////////////////////////////////////////////////////////////////////////////
@@ -64,6 +75,9 @@
#include "shaders/drawColor.vert"
#include "shaders/drawColor.frag"
+#include "shaders/drawTexture.vert"
+#include "shaders/drawTexture.frag"
+
Program::Program(const char* vertex, const char* fragment) {
vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
@@ -139,6 +153,15 @@
DrawColorProgram::DrawColorProgram():
Program(gDrawColorVertexShader, gDrawColorFragmentShader) {
+ getAttribsAndUniforms();
+}
+
+DrawColorProgram::DrawColorProgram(const char* vertex, const char* fragment):
+ Program(vertex, fragment) {
+ getAttribsAndUniforms();
+}
+
+void DrawColorProgram::getAttribsAndUniforms() {
position = addAttrib("position");
color = addAttrib("color");
projection = addUniform("projection");
@@ -154,6 +177,12 @@
glUniformMatrix4fv(transform, 1, GL_FALSE, transformMatrix);
}
+DrawTextureProgram::DrawTextureProgram():
+ DrawColorProgram(gDrawTextureVertexShader, gDrawTextureFragmentShader) {
+ texCoords = addAttrib("texCoords");
+ sampler = addUniform("sampler");
+}
+
///////////////////////////////////////////////////////////////////////////////
// Support
///////////////////////////////////////////////////////////////////////////////
@@ -175,6 +204,7 @@
LOGD("Create OpenGLRenderer");
mDrawColorShader = new DrawColorProgram;
+ mDrawTextureShader = new DrawTextureProgram;
}
OpenGLRenderer::~OpenGLRenderer() {
@@ -252,17 +282,90 @@
bool OpenGLRenderer::restoreSnapshot() {
bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet;
+ bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer;
+ sp<Snapshot> current = mSnapshot;
+ sp<Snapshot> previous = mSnapshot->previous;
+
+ if (restoreLayer) {
+ // Unbind current FBO and restore previous one
+ // Most of the time, previous->fbo will be 0 to bind the default buffer
+ glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
+
+ const Rect& layer = current->layer;
+ clipRect(layer.left, layer.top, layer.right, layer.bottom);
+ mSnapshot->transform.loadIdentity();
+
+ drawTextureRect(0.0f, 0.0f, mWidth, mHeight, current->texture, current->alpha);
+
+ glDeleteFramebuffers(1, ¤t->fbo);
+ glDeleteTextures(1, ¤t->texture);
+ }
+
+ mSnapshot = previous;
mSaveCount--;
- // Do not merge these two lines!
- sp<Snapshot> previous = mSnapshot->previous;
- mSnapshot = previous;
-
return restoreClip;
}
///////////////////////////////////////////////////////////////////////////////
+// Layers
+///////////////////////////////////////////////////////////////////////////////
+
+int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
+ const SkPaint* p, int flags) {
+ // TODO Implement
+ return saveSnapshot();
+}
+
+int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
+ int alpha, int flags) {
+ int count = saveSnapshot();
+
+ mSnapshot->flags |= Snapshot::kFlagIsLayer;
+ mSnapshot->alpha = alpha / 255.0f;
+ mSnapshot->layer.set(left, top, right, bottom);
+
+ // Generate the FBO and attach the texture
+ glGenFramebuffers(1, &mSnapshot->fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, mSnapshot->fbo);
+
+ // Generate the texture in which the FBO will draw
+ glGenTextures(1, &mSnapshot->texture);
+ glBindTexture(GL_TEXTURE_2D, mSnapshot->texture);
+
+ // The FBO will not be scaled, so we can use lower quality filtering
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ // TODO ***** IMPORTANT *****
+ // Creating a texture-backed FBO works only if the texture is the same size
+ // as the original rendering buffer (in this case, mWidth and mHeight.)
+ // This is expensive and wasteful and must be fixed.
+
+ const GLsizei width = mWidth; //right - left;
+ const GLsizei height = mHeight; //bottom - right;
+
+ const GLint format = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) ? GL_RGBA : GL_RGB;
+ glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ // Bind texture to FBO
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ mSnapshot->texture, 0);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ LOGD("Framebuffer incomplete %d", status);
+
+ glDeleteFramebuffers(1, &mSnapshot->fbo);
+ glDeleteTextures(1, &mSnapshot->texture);
+ }
+
+ return count;
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Transforms
///////////////////////////////////////////////////////////////////////////////
@@ -346,10 +449,10 @@
drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color);
}
-void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* paint) {
+void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) {
// TODO Support more than just color
// TODO: Set the transfer mode
- drawColorRect(left, top, right, bottom, paint->getColor());
+ drawColorRect(left, top, right, bottom, p->getColor());
}
void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, int color) {
@@ -375,5 +478,43 @@
glDisableVertexAttribArray(mDrawColorShader->position);
}
+void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
+ GLuint texture, float alpha) {
+ mModelView.loadTranslate(left, top, 0.0f);
+ mModelView.scale(right - left, bottom - top, 1.0f);
+
+ mDrawTextureShader->use(&mOrthoMatrix[0], &mModelView.data[0], &mSnapshot->transform.data[0]);
+
+ // TODO Correctly set the blend function
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+
+ glBindTexture(GL_TEXTURE_2D, texture);
+
+ glActiveTexture(GL_TEXTURE0);
+ glUniform1i(mDrawTextureShader->sampler, 0);
+
+ const GLvoid* p = &gDrawTextureVertices[0].position[0];
+ const GLvoid* t = &gDrawTextureVertices[0].texture[0];
+
+ glEnableVertexAttribArray(mDrawTextureShader->position);
+ glVertexAttribPointer(mDrawTextureShader->position, 2, GL_FLOAT, GL_FALSE,
+ gDrawTextureVertexStride, p);
+
+ glEnableVertexAttribArray(mDrawTextureShader->texCoords);
+ glVertexAttribPointer(mDrawTextureShader->texCoords, 2, GL_FLOAT, GL_FALSE,
+ gDrawTextureVertexStride, t);
+
+ glVertexAttrib4f(mDrawTextureShader->color, 1.0f, 1.0f, 1.0f, alpha);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawTextureVertexCount);
+
+ glDisableVertexAttribArray(mDrawTextureShader->position);
+ glDisableVertexAttribArray(mDrawTextureShader->texCoords);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDisable(GL_BLEND);
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 6f6b997..527bf3e 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -45,12 +45,17 @@
transform(s->transform),
clipRect(s->clipRect),
flags(kFlagDirtyTransform),
- previous(s) {
+ previous(s),
+ layer(0.0f, 0.0f, 0.0f, 0.0f),
+ texture(0),
+ fbo(0),
+ alpha(255) {
}
enum Flags {
kFlagClipSet = 0x1,
kFlagDirtyTransform = 0x2,
+ kFlagIsLayer = 0x4,
};
const Rect& getMappedClip();
@@ -67,6 +72,12 @@
// Previous snapshot in the frames stack
sp<Snapshot> previous;
+ // Layer, only set if kFlagIsLayer is set
+ Rect layer;
+ GLuint texture;
+ GLuint fbo;
+ float alpha;
+
private:
// Clipping rectangle mapped with the transform
Rect mappedClip;
@@ -76,7 +87,10 @@
float position[2];
}; // struct SimpleVertex
-typedef char* shader;
+struct TextureVertex {
+ float position[2];
+ float texture[2];
+}; // struct TextureVertex
class Program: public LightRefBase<Program> {
public:
@@ -110,6 +124,7 @@
class DrawColorProgram: public Program {
public:
DrawColorProgram();
+ DrawColorProgram(const char* vertex, const char* fragment);
void use(const GLfloat* projectionMatrix, const GLfloat* modelViewMatrix,
const GLfloat* transformMatrix);
@@ -120,6 +135,17 @@
int projection;
int modelView;
int transform;
+
+protected:
+ void getAttribsAndUniforms();
+};
+
+class DrawTextureProgram: public DrawColorProgram {
+public:
+ DrawTextureProgram();
+
+ int sampler;
+ int texCoords;
};
///////////////////////////////////////////////////////////////////////////////
@@ -139,6 +165,9 @@
void restore();
void restoreToCount(int saveCount);
+ int saveLayer(float left, float top, float right, float bottom, const SkPaint* p, int flags);
+ int saveLayerAlpha(float left, float top, float right, float bottom, int alpha, int flags);
+
void translate(float dx, float dy);
void rotate(float degrees);
void scale(float sx, float sy);
@@ -152,7 +181,7 @@
bool clipRect(float left, float top, float right, float bottom);
void drawColor(int color, SkXfermode::Mode mode);
- void drawRect(float left, float top, float right, float bottom, SkPaint* paint);
+ void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
private:
int saveSnapshot();
@@ -161,6 +190,8 @@
void setScissorFromClip();
void drawColorRect(float left, float top, float right, float bottom, int color);
+ void drawTextureRect(float left, float top, float right, float bottom, GLuint texture,
+ float alpha);
// Dimensions of the drawing surface
int mWidth, mHeight;
@@ -180,6 +211,7 @@
// Shaders
sp<DrawColorProgram> mDrawColorShader;
+ sp<DrawTextureProgram> mDrawTextureShader;
}; // class OpenGLRenderer
}; // namespace uirenderer
diff --git a/libs/hwui/shaders/drawColor.frag b/libs/hwui/shaders/drawColor.frag
index f753abb..e84c47b 100644
--- a/libs/hwui/shaders/drawColor.frag
+++ b/libs/hwui/shaders/drawColor.frag
@@ -1,8 +1,6 @@
SHADER_SOURCE(gDrawColorFragmentShader,
-precision mediump float;
-
-varying vec4 outColor;
+varying lowp vec4 outColor;
void main(void) {
gl_FragColor = outColor;
diff --git a/libs/hwui/shaders/drawTexture.frag b/libs/hwui/shaders/drawTexture.frag
new file mode 100644
index 0000000..5bd420e
--- /dev/null
+++ b/libs/hwui/shaders/drawTexture.frag
@@ -0,0 +1,12 @@
+SHADER_SOURCE(gDrawTextureFragmentShader,
+
+varying lowp vec4 outColor;
+varying mediump vec2 outTexCoords;
+
+uniform sampler2D sampler;
+
+void main(void) {
+ gl_FragColor = texture2D(sampler, outTexCoords) * outColor;
+}
+
+);
diff --git a/libs/hwui/shaders/drawTexture.vert b/libs/hwui/shaders/drawTexture.vert
new file mode 100644
index 0000000..310a812
--- /dev/null
+++ b/libs/hwui/shaders/drawTexture.vert
@@ -0,0 +1,20 @@
+SHADER_SOURCE(gDrawTextureVertexShader,
+
+attribute vec4 position;
+attribute vec2 texCoords;
+attribute vec4 color;
+
+uniform mat4 projection;
+uniform mat4 modelView;
+uniform mat4 transform;
+
+varying vec4 outColor;
+varying vec2 outTexCoords;
+
+void main(void) {
+ outColor = color;
+ outTexCoords = texCoords;
+ gl_Position = projection * transform * modelView * position;
+}
+
+);
diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/HwUiActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/HwUiActivity.java
index 14154a8..85e3997 100644
--- a/tests/HwAccelerationTest/src/com/google/android/test/hwui/HwUiActivity.java
+++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/HwUiActivity.java
@@ -22,7 +22,11 @@
import android.graphics.Paint;
import android.os.Bundle;
import android.util.Log;
+import android.view.Gravity;
import android.view.View;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.widget.FrameLayout;
@SuppressWarnings({"UnusedDeclaration"})
public class HwUiActivity extends Activity {
@@ -32,7 +36,19 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(new DirtyBitmapView(this));
+ DirtyBitmapView container = new DirtyBitmapView(this);
+
+ ColorView color = new ColorView(this);
+ container.addView(color, new DirtyBitmapView.LayoutParams(
+ dipToPx(this, 100), dipToPx(this, 100), Gravity.CENTER));
+
+ AlphaAnimation a = new AlphaAnimation(1.0f, 0.0f);
+ a.setDuration(2000);
+ a.setRepeatCount(Animation.INFINITE);
+ a.setRepeatMode(Animation.REVERSE);
+ color.startAnimation(a);
+
+ setContentView(container);
}
@SuppressWarnings({"UnusedDeclaration"})
@@ -40,7 +56,19 @@
return (int) (c.getResources().getDisplayMetrics().density * dip + 0.5f);
}
- static class DirtyBitmapView extends View {
+ static class ColorView extends View {
+ ColorView(Context c) {
+ super(c);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawRGB(0, 255, 0);
+ }
+ }
+
+ static class DirtyBitmapView extends FrameLayout {
private final Paint mPaint;
DirtyBitmapView(Context c) {
@@ -49,9 +77,7 @@
}
@Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
+ public void dispatchDraw(Canvas canvas) {
canvas.drawRGB(255, 255, 255);
mPaint.setColor(0xffff0000);
@@ -86,6 +112,7 @@
Canvas.EdgeType.BW));
canvas.restore();
+ canvas.save();
canvas.scale(2.0f, 2.0f);
canvas.clipRect(20.0f, 0.0f, 40.0f, 20.0f);
@@ -94,6 +121,21 @@
mPaint.setColor(0xff0000ff);
canvas.drawRect(20.0f, 0.0f, 40.0f, 20.0f, mPaint);
+
+ canvas.restore();
+
+ final int restoreTo = canvas.save();
+ canvas.saveLayerAlpha(0.0f, 100.0f, getWidth(), 150.0f, 127,
+ Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
+ mPaint.setColor(0xff0000ff);
+ canvas.drawRect(0.0f, 100.0f, 40.0f, 150.0f, mPaint);
+ mPaint.setColor(0xff00ffff);
+ canvas.drawRect(40.0f, 100.0f, 140.0f, 150.0f, mPaint);
+ mPaint.setColor(0xffff00ff);
+ canvas.drawRect(140.0f, 100.0f, 240.0f, 150.0f, mPaint);
+ canvas.restoreToCount(restoreTo);
+
+ super.dispatchDraw(canvas);
}
}
}