1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.O; 4 import static org.junit.Assert.assertEquals; 5 import static org.junit.Assert.assertTrue; 6 7 import android.graphics.Bitmap; 8 import android.graphics.Canvas; 9 import android.graphics.Color; 10 import android.graphics.DiscretePathEffect; 11 import android.graphics.Paint; 12 import android.graphics.Paint.Style; 13 import android.graphics.Path; 14 import android.graphics.PorterDuff.Mode; 15 import android.graphics.PorterDuffXfermode; 16 import androidx.test.ext.junit.runners.AndroidJUnit4; 17 import org.junit.Test; 18 import org.junit.runner.RunWith; 19 import org.robolectric.annotation.Config; 20 21 @RunWith(AndroidJUnit4.class) 22 @Config(minSdk = O) 23 public class ShadowNativeDiscretePathEffectTest { 24 private static final int BITMAP_WIDTH = 200; 25 private static final int BITMAP_HEIGHT = 100; 26 private static final int START_X = 10; 27 private static final int END_X = BITMAP_WIDTH - START_X; 28 private static final int COORD_Y = BITMAP_HEIGHT / 2; 29 private static final int SEGMENT_LENGTH = 10; // must be < BITMAP_WIDTH 30 private static final int DEVIATION = 10; // must be < BITMAP_HEIGHT 31 32 @Test testDiscretePathEffect()33 public void testDiscretePathEffect() { 34 DiscretePathEffect effect = new DiscretePathEffect(SEGMENT_LENGTH, DEVIATION); 35 36 Paint paint = new Paint(); 37 paint.setColor(Color.GREEN); 38 paint.setStyle(Style.STROKE); 39 paint.setStrokeWidth(0); 40 paint.setPathEffect(effect); 41 paint.setAntiAlias(false); 42 43 Path path = new Path(); 44 path.moveTo(START_X, COORD_Y); 45 path.lineTo(END_X, COORD_Y); 46 47 Bitmap bitmap = Bitmap.createBitmap(BITMAP_WIDTH, BITMAP_HEIGHT, Bitmap.Config.ARGB_8888); 48 bitmap.eraseColor(Color.TRANSPARENT); 49 50 Canvas canvas = new Canvas(bitmap); 51 canvas.drawPath(path, paint); 52 53 // draw guide line into red channel (each segment should cross this once) 54 paint = new Paint(); 55 paint.setColor(Color.RED); 56 paint.setStyle(Style.STROKE); 57 paint.setStrokeWidth(0); 58 paint.setXfermode(new PorterDuffXfermode(Mode.SCREEN)); 59 canvas.drawPath(path, paint); 60 61 // draw guide rectangle into blue channel (each segment must be completely inside this) 62 paint.setColor(Color.BLUE); 63 paint.setStrokeWidth(1 + 2 * DEVIATION); 64 canvas.drawPath(path, paint); 65 66 int intersect = 0; 67 int numGreenPixels = 0; 68 int minY = BITMAP_HEIGHT; 69 int maxY = 0; 70 for (int y = 0; y < BITMAP_HEIGHT; y++) { 71 for (int x = 0; x < BITMAP_WIDTH; x++) { 72 int pixel = bitmap.getPixel(x, y); 73 if (Color.green(pixel) > 0) { 74 numGreenPixels += 1; 75 minY = Math.min(minY, y); 76 maxY = Math.max(maxY, y); 77 assertEquals(0xFF, Color.blue(pixel)); 78 if (Color.red(pixel) > 0) { 79 intersect += 1; 80 } 81 } 82 } 83 } 84 int lineLength = END_X - START_X; 85 // the number of pixels in all segments must be at least the same as the line length 86 assertTrue(numGreenPixels >= lineLength); 87 // green line must vary in y direction 88 assertTrue(maxY - minY > 0); 89 // ... but not too much 90 assertTrue(maxY - minY <= 1 + 2 * DEVIATION); 91 // intersecting pixels must be less than line length, otherwise deviation doesn't work 92 assertTrue(intersect < lineLength); 93 // there must be at least as many intersecting pixels as there are full segments 94 assertTrue(intersect >= lineLength / SEGMENT_LENGTH); 95 } 96 } 97