1 package com.xtremelabs.robolectric.shadows; 2 3 import android.graphics.*; 4 import com.xtremelabs.robolectric.internal.Implementation; 5 import com.xtremelabs.robolectric.internal.Implements; 6 7 import java.util.ArrayList; 8 import java.util.List; 9 10 import static com.xtremelabs.robolectric.Robolectric.newInstanceOf; 11 import static com.xtremelabs.robolectric.Robolectric.shadowOf; 12 13 /** 14 * Shadows the {@code android.graphics.Canvas} class. 15 * <p/> 16 * Broken. 17 * This implementation is very specific to the application for which it was developed. 18 * Todo: Reimplement. Consider using the same strategy of collecting a history of draw events and providing methods for writing queries based on type, number, and order of events. 19 */ 20 @SuppressWarnings({"UnusedDeclaration"}) 21 @Implements(Canvas.class) 22 public class ShadowCanvas { 23 private List<PathPaintHistoryEvent> pathPaintEvents = new ArrayList<PathPaintHistoryEvent>(); 24 private List<CirclePaintHistoryEvent> circlePaintEvents = new ArrayList<CirclePaintHistoryEvent>(); 25 private Paint drawnPaint; 26 private Bitmap targetBitmap = newInstanceOf(Bitmap.class); 27 private float translateX; 28 private float translateY; 29 private float scaleX = 1; 30 private float scaleY = 1; 31 __constructor__(Bitmap bitmap)32 public void __constructor__(Bitmap bitmap) { 33 this.targetBitmap = bitmap; 34 } 35 appendDescription(String s)36 public void appendDescription(String s) { 37 shadowOf(targetBitmap).appendDescription(s); 38 } 39 getDescription()40 public String getDescription() { 41 return shadowOf(targetBitmap).getDescription(); 42 } 43 44 @Implementation translate(float x, float y)45 public void translate(float x, float y) { 46 this.translateX = x; 47 this.translateY = y; 48 } 49 50 @Implementation scale(float sx, float sy)51 public void scale(float sx, float sy) { 52 this.scaleX = sx; 53 this.scaleY = sy; 54 } 55 56 @Implementation scale(float sx, float sy, float px, float py)57 public void scale(float sx, float sy, float px, float py) { 58 this.scaleX = sx; 59 this.scaleY = sy; 60 } 61 62 @Implementation drawPaint(Paint paint)63 public void drawPaint(Paint paint) { 64 drawnPaint = paint; 65 } 66 67 @Implementation drawColor(int color)68 public void drawColor(int color) { 69 appendDescription("draw color " + color); 70 } 71 72 @Implementation drawBitmap(Bitmap bitmap, float left, float top, Paint paint)73 public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) { 74 describeBitmap(bitmap, paint); 75 76 int x = (int) (left + translateX); 77 int y = (int) (top + translateY); 78 if (x != 0 && y != 0) { 79 appendDescription(" at (" + x + "," + y + ")"); 80 } 81 82 if (scaleX != 1 && scaleY != 1) { 83 appendDescription(" scaled by (" + scaleX + "," + scaleY + ")"); 84 } 85 } 86 87 @Implementation drawPath(Path path, Paint paint)88 public void drawPath(Path path, Paint paint) { 89 pathPaintEvents.add(new PathPaintHistoryEvent(path, paint)); 90 91 separateLines(); 92 appendDescription("Path " + shadowOf(path).getPoints().toString()); 93 } 94 describeBitmap(Bitmap bitmap, Paint paint)95 private void describeBitmap(Bitmap bitmap, Paint paint) { 96 separateLines(); 97 98 appendDescription(shadowOf(bitmap).getDescription()); 99 100 if (paint != null) { 101 ColorFilter colorFilter = paint.getColorFilter(); 102 if (colorFilter != null) { 103 appendDescription(" with " + colorFilter); 104 } 105 } 106 } 107 separateLines()108 private void separateLines() { 109 if (getDescription().length() != 0) { 110 appendDescription("\n"); 111 } 112 } 113 114 @Implementation drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)115 public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) { 116 describeBitmap(bitmap, paint); 117 118 appendDescription(" transformed by matrix"); 119 } 120 getPathPaintHistoryCount()121 public int getPathPaintHistoryCount() { 122 return pathPaintEvents.size(); 123 } 124 getCirclePaintHistoryCount()125 public int getCirclePaintHistoryCount() { 126 return circlePaintEvents.size(); 127 } 128 hasDrawnPath()129 public boolean hasDrawnPath() { 130 return getPathPaintHistoryCount() > 0; 131 } 132 hasDrawnCircle()133 public boolean hasDrawnCircle() { 134 return circlePaintEvents.size() > 0; 135 } 136 getDrawnPathPaint(int i)137 public Paint getDrawnPathPaint(int i) { 138 return pathPaintEvents.get(i).pathPaint; 139 } 140 getDrawnPath(int i)141 public Path getDrawnPath(int i) { 142 return pathPaintEvents.get(i).drawnPath; 143 } 144 getDrawnCircle(int i)145 public CirclePaintHistoryEvent getDrawnCircle(int i) { 146 return circlePaintEvents.get(i); 147 } 148 resetCanvasHistory()149 public void resetCanvasHistory() { 150 pathPaintEvents.clear(); 151 circlePaintEvents.clear(); 152 } 153 getDrawnPaint()154 public Paint getDrawnPaint() { 155 return drawnPaint; 156 } 157 158 private static class PathPaintHistoryEvent { 159 private Path drawnPath; 160 private Paint pathPaint; 161 PathPaintHistoryEvent(Path drawnPath, Paint pathPaint)162 PathPaintHistoryEvent(Path drawnPath, Paint pathPaint) { 163 this.drawnPath = drawnPath; 164 this.pathPaint = pathPaint; 165 } 166 } 167 168 public static class CirclePaintHistoryEvent { 169 public Paint paint; 170 public float centerX; 171 public float centerY; 172 public float radius; 173 CirclePaintHistoryEvent(float centerX, float centerY, float radius, Paint paint)174 private CirclePaintHistoryEvent(float centerX, float centerY, float radius, Paint paint) { 175 this.paint = paint; 176 this.centerX = centerX; 177 this.centerY = centerY; 178 this.radius = radius; 179 } 180 } 181 } 182