• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.android.mail.bitmap;
2 
3 import android.graphics.Canvas;
4 import android.graphics.ColorFilter;
5 import android.graphics.PixelFormat;
6 import android.graphics.Rect;
7 import android.graphics.drawable.Drawable;
8 
9 import com.android.bitmap.Trace;
10 
11 import java.util.ArrayList;
12 import 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  */
21 public abstract class CompositeDrawable<T extends Drawable> extends Drawable
22         implements Drawable.Callback {
23 
24     protected final List<T> mDrawables;
25     protected int mCount;
26 
CompositeDrawable(int maxDivisions)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 
createDivisionDrawable()38     protected abstract T createDivisionDrawable();
39 
setCount(int count)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 
getCount()47     public int getCount() {
48         return mCount;
49     }
50 
getOrCreateDrawable(int i)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
onBoundsChange(Rect bounds)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 
applyBounds(int index, int left, int top, int right, int bottom)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
draw(Canvas canvas)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
setAlpha(int alpha)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
setColorFilter(ColorFilter cf)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
getOpacity()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
invalidateDrawable(Drawable who)144     public void invalidateDrawable(Drawable who) {
145         invalidateSelf();
146     }
147 
148     @Override
scheduleDrawable(Drawable who, Runnable what, long when)149     public void scheduleDrawable(Drawable who, Runnable what, long when) {
150         scheduleSelf(what, when);
151     }
152 
153     @Override
unscheduleDrawable(Drawable who, Runnable what)154     public void unscheduleDrawable(Drawable who, Runnable what) {
155         unscheduleSelf(what);
156     }
157 
158 }
159