Integrate unsubmitted cupcake change 131127:
	CTS: add test cases for graphics.ComposeShader, CornerPathEffect, DashPathEffect, DiscretePathEffect, EmbossMaskFilter and LightingColorFilter
diff --git a/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java b/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java
new file mode 100644
index 0000000..a52ede1
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.graphics.cts;
+
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ComposeShader;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.PixelXorXfermode;
+import android.graphics.PorterDuff;
+import android.graphics.Shader;
+import android.graphics.Xfermode;
+import android.graphics.Bitmap.Config;
+import android.graphics.Shader.TileMode;
+import android.util.Log;
+
+import junit.framework.TestCase;
+
+@TestTargetClass(ComposeShader.class)
+public class ComposeShaderTest extends TestCase {
+
+    private static final int SIZE = 255;
+    private static final int TOLERANCE = 5;
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "ComposeShader",
+        args = {Shader.class, Shader.class, PorterDuff.Mode.class}
+    )
+    public void testPorterDuff() {
+        LinearGradient blueGradient = new LinearGradient(0, 0, SIZE, 0,
+                Color.GREEN, Color.BLUE, Shader.TileMode.CLAMP);
+        LinearGradient redGradient = new LinearGradient(0, 0, 0, SIZE,
+                Color.GREEN, Color.RED, Shader.TileMode.CLAMP);
+        ComposeShader shader = new ComposeShader(blueGradient, redGradient, PorterDuff.Mode.SCREEN);
+
+        Bitmap bitmap = Bitmap.createBitmap(SIZE, SIZE, Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+        Paint paint = new Paint();
+        paint.setShader(shader);
+        canvas.drawPaint(paint);
+
+        for (int y = 0; y < SIZE; y++) {
+            for (int x = 0; x < SIZE; x++) {
+                float greenX = 1f - (x / 255f);
+                float greenY = 1f - (y / 255f);
+                int green = (int)((greenX + greenY - greenX * greenY) * 255);
+                int pixel = bitmap.getPixel(x, y);
+                try {
+                    assertEquals(0xFF, Color.alpha(pixel), TOLERANCE);
+                    assertEquals(y, Color.red(pixel), TOLERANCE);
+                    assertEquals(green, Color.green(pixel), TOLERANCE);
+                    assertEquals(x, Color.blue(pixel), TOLERANCE);
+                } catch (Error e) {
+                    Log.w(getClass().getName(), "Failed at (" + x + "," + y + ")");
+                    throw e;
+                }
+            }
+        }
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "ComposeShader",
+        args = {Shader.class, Shader.class, Xfermode.class}
+    )
+    public void testXfermode() {
+        Bitmap greenBitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
+        greenBitmap.eraseColor(Color.GREEN);
+        Bitmap cyanBitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
+        cyanBitmap.eraseColor(Color.CYAN);
+
+        BitmapShader blueShader = new BitmapShader(greenBitmap, TileMode.CLAMP, TileMode.CLAMP);
+        BitmapShader redShader = new BitmapShader(cyanBitmap, TileMode.CLAMP, TileMode.CLAMP);
+
+        PixelXorXfermode xferMode = new PixelXorXfermode(Color.WHITE);
+
+        ComposeShader shader = new ComposeShader(blueShader, redShader, xferMode);
+
+        Bitmap bitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+        Paint paint = new Paint();
+        paint.setShader(shader);
+        canvas.drawPaint(paint);
+
+        // white ^ green ^ cyan = yellow
+        assertEquals(Color.YELLOW, bitmap.getPixel(0, 0));
+    }
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/CornerPathEffectTest.java b/tests/tests/graphics/src/android/graphics/cts/CornerPathEffectTest.java
new file mode 100644
index 0000000..eceb290
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/CornerPathEffectTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.graphics.cts;
+
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.ToBeFixed;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.CornerPathEffect;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PathEffect;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.RectF;
+import android.graphics.Bitmap.Config;
+import android.graphics.Paint.Style;
+import android.graphics.PorterDuff.Mode;
+
+import junit.framework.TestCase;
+
+@TestTargetClass(CornerPathEffect.class)
+public class CornerPathEffectTest extends TestCase {
+    private static final int BITMAP_WIDTH = 100;
+    private static final int BITMAP_HEIGHT = 100;
+    private static final int PADDING = 10;
+    private static final int RADIUS = 20;
+    private static final int TOLERANCE = 5;
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "CornerPathEffect",
+        args = {float.class}
+    )
+    @ToBeFixed(bug = "2037365", explanation = "CornerPathEffect ends the path prematurely it " +
+            "is not closed.")
+    public void testCornerPathEffect() {
+        Path path = new Path();
+        path.moveTo(0, PADDING);
+        path.lineTo(BITMAP_WIDTH - PADDING, PADDING);
+        path.lineTo(BITMAP_WIDTH - PADDING, BITMAP_HEIGHT);
+
+        PathEffect effect = new CornerPathEffect(RADIUS);
+
+        Paint pathPaint = new Paint();
+        pathPaint.setColor(Color.GREEN);
+        pathPaint.setStyle(Style.STROKE);
+        pathPaint.setStrokeWidth(0);
+        pathPaint.setPathEffect(effect);
+
+        Bitmap bitmap = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+
+        // draw the path using the corner path effect
+        canvas.drawPath(path, pathPaint);
+
+        // create a path that describes the expected shape after the corner is rounded
+        Path expectedPath = new Path();
+        RectF oval = new RectF(BITMAP_WIDTH - PADDING - 2 * RADIUS, PADDING,
+                BITMAP_WIDTH - PADDING, PADDING + 2 * RADIUS);
+        expectedPath.moveTo(0, PADDING);
+        expectedPath.arcTo(oval, 270, 90);
+        expectedPath.lineTo(BITMAP_WIDTH - PADDING, BITMAP_HEIGHT);
+
+        // A paint that draws the expected path with a tolerance width into the red channel
+        Paint expectedPaint = new Paint();
+        expectedPaint.setColor(Color.RED);
+        expectedPaint.setStyle(Style.STROKE);
+        expectedPaint.setStrokeWidth(TOLERANCE);
+        expectedPaint.setXfermode(new PorterDuffXfermode(Mode.SCREEN));
+
+        canvas.drawPath(expectedPath, expectedPaint);
+
+        int numPixels = 0;
+        for (int y = 0; y < BITMAP_HEIGHT; y++) {
+            for (int x = 0; x < BITMAP_WIDTH; x++) {
+                int pixel = bitmap.getPixel(x, y);
+                if (Color.green(pixel) > 0) {
+                    numPixels += 1;
+                    // green path must overlap with red guide line
+                    assertEquals(Color.YELLOW, pixel);
+                }
+            }
+        }
+        // number of pixels that should be on a straight line
+        int straightLines = BITMAP_WIDTH - PADDING - RADIUS + BITMAP_HEIGHT - PADDING - RADIUS;
+        // number of pixels forming the corner
+        int cornerPixels = numPixels - straightLines;
+        // rounded corner must have less pixels than a sharp corner
+        assertTrue(cornerPixels < 2 * RADIUS);
+        // ... but not as few as a diagonal
+        // ToBeFixed: The following should be assertTrue (see bug 2037365)
+        assertFalse(cornerPixels > RADIUS);
+    }
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/DashPathEffectTest.java b/tests/tests/graphics/src/android/graphics/cts/DashPathEffectTest.java
new file mode 100644
index 0000000..1e3aa17
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/DashPathEffectTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.graphics.cts;
+
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.ToBeFixed;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.DashPathEffect;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PathEffect;
+import android.graphics.Bitmap.Config;
+import android.graphics.Paint.Style;
+import android.util.Log;
+
+import junit.framework.TestCase;
+
+@TestTargetClass(DashPathEffect.class)
+public class DashPathEffectTest extends TestCase {
+    private static final int BITMAP_WIDTH = 200;
+    private static final int BITMAP_HEIGHT = 20;
+    private static final int START_X = 10;
+    private static final int END_X = BITMAP_WIDTH - START_X;
+    private static final int COORD_Y = BITMAP_HEIGHT / 2;
+    private static final float[] PATTERN = new float[] { 15, 5, 10, 5 };
+    private static final int OFFSET = 5;
+    private static final int BACKGROUND = Color.TRANSPARENT;
+    private static final int FOREGROUND = Color.GREEN;
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "DashPathEffect",
+        args = {float[].class, float.class}
+    )
+    @ToBeFixed(bug = "2039296", explanation = "Javadoc for phase parameter is wrong. The phase" +
+        " determines the start offset within the pattern and not an initial gap")
+    public void testDashPathEffect() {
+        PathEffect effect = new DashPathEffect(PATTERN, OFFSET);
+        Bitmap bitmap = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Config.ARGB_8888);
+        bitmap.eraseColor(BACKGROUND);
+
+        Path path = new Path();
+        path.moveTo(START_X, COORD_Y);
+        path.lineTo(END_X, COORD_Y);
+
+        Paint paint = new Paint();
+        paint.setStyle(Style.STROKE);
+        paint.setStrokeWidth(0);
+        paint.setColor(FOREGROUND);
+        paint.setPathEffect(effect);
+
+        Canvas canvas = new Canvas(bitmap);
+        canvas.drawPath(path, paint);
+
+        PatternIterator iterator = new PatternIterator(PATTERN, OFFSET);
+        for (int y = 0; y < BITMAP_HEIGHT; y++) {
+            for (int x = 0; x < BITMAP_WIDTH; x++) {
+                try {
+                    if (y == COORD_Y && x >= START_X && x < END_X) {
+                        if (iterator.next()) {
+                            assertEquals(FOREGROUND, bitmap.getPixel(x, y));
+                        } else {
+                            assertEquals(BACKGROUND, bitmap.getPixel(x, y));
+                        }
+                    } else {
+                        assertEquals(BACKGROUND, bitmap.getPixel(x, y));
+                    }
+                } catch (Error e) {
+                    Log.w(getClass().getName(), "Failed at (" + x + "," + y + ")");
+                    throw e;
+                }
+            }
+        }
+    }
+
+    private static class PatternIterator {
+        private int mPatternOffset;
+        private int mLength;
+        private final float[] mPattern;
+
+        /**
+         * Create an instance that iterates through the given pattern starting at the given offset.
+         */
+        PatternIterator(final float[] pattern, int offset) {
+            mPattern = pattern;
+            while (offset-- > 0) {
+                next();
+            }
+        }
+
+        /**
+         * Determine whether to draw the current pixel and move on to the next.
+         */
+        boolean next() {
+            int oldPatternOffset = mPatternOffset;
+            mLength += 1;
+            if (mLength == mPattern[mPatternOffset]) {
+                mLength = 0;
+                mPatternOffset += 1;
+                mPatternOffset %= mPattern.length;
+            }
+            // even offsets are 'on'
+            return (oldPatternOffset & 1) == 0;
+        }
+    }
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/DiscretePathEffectTest.java b/tests/tests/graphics/src/android/graphics/cts/DiscretePathEffectTest.java
new file mode 100644
index 0000000..d54dc83
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/DiscretePathEffectTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.cts;
+
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.DiscretePathEffect;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Bitmap.Config;
+import android.graphics.Paint.Style;
+import android.graphics.PorterDuff.Mode;
+
+import junit.framework.TestCase;
+
+@TestTargetClass(DiscretePathEffect.class)
+public class DiscretePathEffectTest extends TestCase {
+    private static final int BITMAP_WIDTH = 200;
+    private static final int BITMAP_HEIGHT = 100;
+    private static final int START_X = 10;
+    private static final int END_X = BITMAP_WIDTH - START_X;
+    private static final int COORD_Y = BITMAP_HEIGHT / 2;
+    private static final int SEGMENT_LENGTH = 10; // must be < BITMAP_WIDTH
+    private static final int DEVIATION = 10; // must be < BITMAP_HEIGHT
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "DiscretePathEffect",
+        args = {float.class, float.class}
+    )
+    public void testDiscretePathEffect() {
+        DiscretePathEffect effect = new DiscretePathEffect(SEGMENT_LENGTH, DEVIATION);
+
+        Paint paint = new Paint();
+        paint.setColor(Color.GREEN);
+        paint.setStyle(Style.STROKE);
+        paint.setStrokeWidth(0);
+        paint.setPathEffect(effect);
+
+        Path path = new Path();
+        path.moveTo(START_X, COORD_Y);
+        path.lineTo(END_X, COORD_Y);
+
+        Bitmap bitmap = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Config.ARGB_8888);
+        bitmap.eraseColor(Color.TRANSPARENT);
+
+        Canvas canvas = new Canvas(bitmap);
+        canvas.drawPath(path, paint);
+
+        // draw guide line into red channel (each segment should cross this once)
+        paint = new Paint();
+        paint.setColor(Color.RED);
+        paint.setStyle(Style.STROKE);
+        paint.setStrokeWidth(0);
+        paint.setXfermode(new PorterDuffXfermode(Mode.SCREEN));
+        canvas.drawPath(path, paint);
+
+        // draw guide rectangle into blue channel (each segment must be completely inside this)
+        paint.setColor(Color.BLUE);
+        paint.setStrokeWidth(1 + 2 * DEVIATION);
+        canvas.drawPath(path, paint);
+
+        int intersect = 0;
+        int numGreenPixels = 0;
+        int minY = BITMAP_HEIGHT;
+        int maxY = 0;
+        for (int y = 0; y < BITMAP_HEIGHT; y++) {
+            for (int x = 0; x < BITMAP_WIDTH; x++) {
+                int pixel = bitmap.getPixel(x, y);
+                if (Color.green(pixel) > 0) {
+                    numGreenPixels += 1;
+                    minY = Math.min(minY, y);
+                    maxY = Math.max(maxY, y);
+                    assertEquals(0xFF, Color.blue(pixel));
+                    if (Color.red(pixel) > 0) {
+                        intersect += 1;
+                    }
+                }
+            }
+        }
+        int lineLength = END_X - START_X;
+        // the number of pixels in all segments must be at least the same as the line length
+        assertTrue(numGreenPixels >= lineLength);
+        // green line must vary in y direction
+        assertTrue(maxY - minY > 0);
+        // ... but not too much
+        assertTrue(maxY - minY <= 1 + 2 * DEVIATION);
+        // intersecting pixels must be less than line length, otherwise deviation doesn't work
+        assertTrue(intersect < lineLength);
+        // there must be at least as many intersecting pixels as there are full segments
+        assertTrue(intersect >= lineLength / SEGMENT_LENGTH);
+    }
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/EmbossMaskFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/EmbossMaskFilterTest.java
new file mode 100644
index 0000000..10bfbad
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/EmbossMaskFilterTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.cts;
+
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.EmbossMaskFilter;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.graphics.Bitmap.Config;
+
+import junit.framework.TestCase;
+
+@TestTargetClass(EmbossMaskFilter.class)
+public class EmbossMaskFilterTest extends TestCase {
+    private static final int BITMAP_WIDTH = 100;
+    private static final int BITMAP_HEIGHT = 100;
+    private static final int START_X = 10;
+    private static final int END_X = BITMAP_WIDTH - START_X;
+    private static final int CENTER_X = (START_X + END_X) / 2;
+    private static final int CENTER_Y = BITMAP_HEIGHT / 2;
+    private static final int STROKE_WIDTH = 10;
+
+    @TestTargetNew(
+        level = TestLevel.SUFFICIENT,
+        notes = "Javadoc is incomplete, cannot test all parameters",
+        method = "EmbossMaskFilter",
+        args = {float[].class, float.class, float.class, float.class}
+    )
+    public void testEmbossMaskFilter() {
+        EmbossMaskFilter filter = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.5f, 8, 3);
+
+        Paint paint = new Paint();
+        paint.setMaskFilter(filter);
+        paint.setStyle(Paint.Style.STROKE);
+        paint.setStrokeWidth(STROKE_WIDTH);
+        paint.setColor(Color.GRAY);
+
+        Path path = new Path();
+        path.moveTo(START_X, CENTER_Y);
+        path.lineTo(END_X, CENTER_Y);
+
+        Bitmap bitmap = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Config.ARGB_8888);
+        bitmap.eraseColor(Color.BLACK);
+
+        Canvas c = new Canvas(bitmap);
+        c.drawPath(path, paint);
+
+        Rect top = new Rect(0, 0, BITMAP_WIDTH, CENTER_Y);
+        Rect bottom = new Rect(0, CENTER_Y, BITMAP_WIDTH, BITMAP_HEIGHT);
+        Rect left = new Rect(0, 0, CENTER_X, BITMAP_HEIGHT);
+        Rect right = new Rect(CENTER_X, 0, BITMAP_WIDTH, BITMAP_HEIGHT);
+
+        assertTrue(brightness(bitmap, top) > brightness(bitmap, bottom));
+        assertTrue(brightness(bitmap, left) > brightness(bitmap, right));
+
+        // emboss must not change anything outside the drawn shape
+        top.bottom = CENTER_Y - STROKE_WIDTH / 2;
+        assertEquals(0, brightness(bitmap, top));
+        bottom.top = CENTER_Y + STROKE_WIDTH / 2;
+        assertEquals(0, brightness(bitmap, bottom));
+        left.right = START_X;
+        assertEquals(0, brightness(bitmap, left));
+        right.left = END_X;
+        assertEquals(0, brightness(bitmap, right));
+    }
+
+    /**
+     * Calculate the cumulative brightness of all pixels in the given rectangle.
+     * Ignores alpha channel. Maximum returned value depends on the size of the rectangle.
+     */
+    private long brightness(Bitmap b, Rect rect) {
+        long color = 0;
+        for (int y = rect.top; y < rect.bottom; y++) {
+            for (int x = rect.left; x < rect.right; x++) {
+                int pixel = b.getPixel(x, y);
+                color += Color.red(pixel) + Color.green(pixel) + Color.blue(pixel);
+            }
+        }
+        return color;
+    }
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java
new file mode 100644
index 0000000..0bb2027
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.cts;
+
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LightingColorFilter;
+import android.graphics.Paint;
+import android.graphics.Bitmap.Config;
+
+import junit.framework.TestCase;
+
+@TestTargetClass(LightingColorFilter.class)
+public class LightingColorFilterTest extends TestCase {
+
+    private static final int TOLERANCE = 2;
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "LightingColorFilter",
+        args = {int.class, int.class}
+    )
+    public void testLightingColorFilter() {
+        Bitmap bitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+
+        Paint paint = new Paint();
+
+        paint.setColor(Color.MAGENTA);
+        paint.setColorFilter(new LightingColorFilter(Color.WHITE, Color.BLACK));
+        canvas.drawPaint(paint);
+        assertColor(Color.MAGENTA, bitmap.getPixel(0, 0));
+
+        paint.setColor(Color.MAGENTA);
+        paint.setColorFilter(new LightingColorFilter(Color.CYAN, Color.BLACK));
+        canvas.drawPaint(paint);
+        assertColor(Color.BLUE, bitmap.getPixel(0, 0));
+
+        paint.setColor(Color.MAGENTA);
+        paint.setColorFilter(new LightingColorFilter(Color.BLUE, Color.GREEN));
+        canvas.drawPaint(paint);
+        assertColor(Color.CYAN, bitmap.getPixel(0, 0));
+
+        // alpha is ignored
+        bitmap.eraseColor(Color.TRANSPARENT);
+        paint.setColor(Color.MAGENTA);
+        paint.setColorFilter(new LightingColorFilter(Color.TRANSPARENT, Color.argb(0, 0, 0xFF, 0)));
+        canvas.drawPaint(paint);
+        assertColor(Color.GREEN, bitmap.getPixel(0, 0));
+
+        // channels get clipped (no overflow into green or alpha)
+        paint.setColor(Color.MAGENTA);
+        paint.setColorFilter(new LightingColorFilter(Color.WHITE, Color.MAGENTA));
+        canvas.drawPaint(paint);
+        assertColor(Color.MAGENTA, bitmap.getPixel(0, 0));
+
+        // multiply before add
+        paint.setColor(Color.argb(255, 60, 20, 40));
+        paint.setColorFilter(
+                new LightingColorFilter(Color.rgb(0x80, 0xFF, 0x80), Color.rgb(0, 10, 10)));
+        canvas.drawPaint(paint);
+        assertColor(Color.argb(255, 30, 30, 30), bitmap.getPixel(0, 0));
+
+        // source alpha remains unchanged
+        bitmap.eraseColor(Color.TRANSPARENT);
+        paint.setColor(Color.argb(0x80, 60, 20, 40));
+        paint.setColorFilter(
+                new LightingColorFilter(Color.rgb(0x80, 0xFF, 0x80), Color.rgb(0, 10, 10)));
+        canvas.drawPaint(paint);
+        assertColor(Color.argb(0x80, 30, 30, 30), bitmap.getPixel(0, 0));
+    }
+
+    private void assertColor(int expected, int actual) {
+        assertEquals(Color.alpha(expected), Color.alpha(actual), TOLERANCE);
+        assertEquals(Color.red(expected), Color.red(actual), TOLERANCE);
+        assertEquals(Color.green(expected), Color.green(actual), TOLERANCE);
+        assertEquals(Color.blue(expected), Color.blue(actual), TOLERANCE);
+    }
+}