1package com.android.mail.bitmap; 2 3import android.graphics.Canvas; 4import android.graphics.ColorFilter; 5import android.graphics.PixelFormat; 6import android.graphics.Rect; 7import android.graphics.drawable.Drawable; 8 9import com.android.bitmap.Trace; 10 11import java.util.ArrayList; 12import java.util.List; 13 14/** 15 * A drawable that contains up to 4 other smaller drawables in a regular grid. This class attempts 16 * to reuse inner drawables when feasible to promote object reuse. This design goal makes the API 17 * to reuse an instance a little awkward: you must first zero out the count, then set it to a new 18 * value, then populate the entries with {@link #getOrCreateDrawable(int)} and a drawable subclass 19 * bind() method of your design. 20 */ 21public abstract class CompositeDrawable<T extends Drawable> extends Drawable 22 implements Drawable.Callback { 23 24 protected final List<T> mDrawables; 25 protected int mCount; 26 27 public CompositeDrawable(int maxDivisions) { 28 if (maxDivisions >= 4) { 29 throw new IllegalArgumentException("CompositeDrawable only supports 4 divisions"); 30 } 31 mDrawables = new ArrayList<T>(maxDivisions); 32 for (int i = 0; i < maxDivisions; i++) { 33 mDrawables.add(i, null); 34 } 35 mCount = 0; 36 } 37 38 protected abstract T createDivisionDrawable(); 39 40 public void setCount(int count) { 41 // zero out the composite bounds, which will propagate to the division drawables 42 // this invalidates any old division bounds, which may change with the count 43 setBounds(0, 0, 0, 0); 44 mCount = count; 45 } 46 47 public int getCount() { 48 return mCount; 49 } 50 51 public T getOrCreateDrawable(int i) { 52 if (i >= mCount) { 53 throw new IllegalArgumentException("bad index: " + i); 54 } 55 56 T result = mDrawables.get(i); 57 if (result == null) { 58 Trace.beginSection("create division drawable"); 59 result = createDivisionDrawable(); 60 mDrawables.set(i, result); 61 result.setCallback(this); 62 // Make sure drawables created after the bounds were already set have their bounds 63 // set initially (the other unaffected drawables basically de-bounce this). 64 onBoundsChange(getBounds()); 65 Trace.endSection(); 66 } 67 return result; 68 } 69 70 @Override 71 protected void onBoundsChange(Rect bounds) { 72 final int w = bounds.width(); 73 final int h = bounds.height(); 74 final int mw = w / 2; 75 final int mh = h / 2; 76 switch (mCount) { 77 case 1: 78 // 1 bitmap: passthrough 79 applyBounds(0, 0, 0, w, h); 80 break; 81 case 2: 82 // 2 bitmaps split vertically 83 applyBounds(0, 0, 0, mw, h); 84 applyBounds(1, mw, 0, w, h); 85 break; 86 case 3: 87 // 1st is tall on the left, 2nd/3rd stacked vertically on the right 88 applyBounds(0, 0, 0, mw, h); 89 applyBounds(1, mw, 0, w, mh); 90 applyBounds(2, mw, mh, w, h); 91 break; 92 case 4: 93 // 4 bitmaps in a 2x2 grid 94 applyBounds(0, 0, 0, mw, mh); 95 applyBounds(1, mw, 0, w, mh); 96 applyBounds(2, 0, mh, mw, h); 97 applyBounds(3, mw, mh, w, h); 98 break; 99 } 100 } 101 102 private void applyBounds(int index, int left, int top, int right, int bottom) { 103 final T d = mDrawables.get(index); 104 if (d == null) { 105 return; 106 } 107 d.setBounds(left, top, right, bottom); 108 } 109 110 @Override 111 public void draw(Canvas canvas) { 112 for (int i = 0; i < mCount; i++) { 113 mDrawables.get(i).draw(canvas); 114 } 115 } 116 117 @Override 118 public void setAlpha(int alpha) { 119 for (int i = 0; i < mCount; i++) { 120 mDrawables.get(i).setAlpha(alpha); 121 } 122 } 123 124 @Override 125 public void setColorFilter(ColorFilter cf) { 126 for (int i = 0; i < mCount; i++) { 127 mDrawables.get(i).setColorFilter(cf); 128 } 129 } 130 131 @Override 132 public int getOpacity() { 133 int opacity = PixelFormat.OPAQUE; 134 for (int i = 0; i < mCount; i++) { 135 if (mDrawables.get(i).getOpacity() != PixelFormat.OPAQUE) { 136 opacity = PixelFormat.TRANSLUCENT; 137 break; 138 } 139 } 140 return opacity; 141 } 142 143 @Override 144 public void invalidateDrawable(Drawable who) { 145 invalidateSelf(); 146 } 147 148 @Override 149 public void scheduleDrawable(Drawable who, Runnable what, long when) { 150 scheduleSelf(what, when); 151 } 152 153 @Override 154 public void unscheduleDrawable(Drawable who, Runnable what) { 155 unscheduleSelf(what); 156 } 157 158} 159