CarouselViewHelper.java revision 594ff62c170509c0d69b30f4c2a5e71d4799a9c8
1package com.android.ex.carousel;
2
3import android.content.Context;
4import android.graphics.Bitmap;
5import android.graphics.Matrix;
6import android.os.Handler;
7import android.os.HandlerThread;
8import android.os.Looper;
9import android.os.Message;
10import android.renderscript.Mesh;
11import android.util.Log;
12
13import com.android.ex.carousel.CarouselRS.CarouselCallback;
14
15/**
16 * CarouselViewHelper wraps all of the threading and event handling of the CarouselView,
17 * providing a simpler interface.  Most users will just need to implement a handful of
18 * methods to get an application working.
19 *
20 */
21public class CarouselViewHelper implements CarouselCallback {
22    private static final String TAG = "CarouselViewHelper";
23    private static final int SET_TEXTURE_N = 1;
24    private static final int SET_DETAIL_TEXTURE_N = 2;
25    private static final int SET_GEOMETRY_N = 3;
26
27    // This is an ordered list of base message ids to allow removal of a single item from the
28    // list for a particular card. The implementation currently supports up to a million cards.
29    private static final int REQUEST_TEXTURE_N = 1000000;
30    private static final int REQUEST_DETAIL_TEXTURE_N = 2000000;
31    private static final int REQUEST_GEOMETRY_N = 3000000;
32    private static final int REQUEST_END = 4000000;
33
34    private HandlerThread mHandlerThread;
35    private Context mContext;
36    private CarouselView mCarouselView;
37    private boolean DBG = false;
38    private long HOLDOFF_DELAY = 100;
39    private Handler mAsyncHandler; // Background thread handler for reading textures, geometry, etc.
40    private Handler mSyncHandler; // Synchronous handler for interacting with UI elements.
41
42    public static class TextureParameters {
43        public TextureParameters(Matrix _matrix) { matrix = _matrix; }
44        public Matrix matrix;
45    };
46
47    public static class DetailTextureParameters {
48        public DetailTextureParameters(float textureOffsetX, float textureOffsetY) {
49            this.textureOffsetX = textureOffsetX;
50            this.textureOffsetY = textureOffsetY;
51            this.lineOffsetX = 0.0f;
52            this.lineOffsetY = 0.0f;
53        }
54        public DetailTextureParameters(
55                float textureOffsetX, float textureOffsetY,
56                float lineOffsetX, float lineOffsetY) {
57            this.textureOffsetX = textureOffsetX;
58            this.textureOffsetY = textureOffsetY;
59            this.lineOffsetX = lineOffsetX;
60            this.lineOffsetY = lineOffsetY;
61        }
62        public float textureOffsetX;
63        public float textureOffsetY;
64        public float lineOffsetX;
65        public float lineOffsetY;
66    };
67
68    public void setCarouselView(CarouselView carouselView) {
69        mCarouselView = carouselView;
70        mCarouselView.setCallback(this);
71    }
72
73    public CarouselViewHelper(Context context, CarouselView carouselView) {
74        this(context);
75        setCarouselView(carouselView);
76    }
77
78    public CarouselViewHelper(Context context) {
79        mContext = context;
80
81        mHandlerThread = new HandlerThread(TAG + ".handler");
82        mHandlerThread.start();
83
84        mAsyncHandler = new AsyncHandler(mHandlerThread.getLooper());
85        mSyncHandler = new SyncHandler(); // runs in calling thread
86    }
87
88    class AsyncHandler extends Handler {
89        AsyncHandler(Looper looper) {
90            super(looper);
91        }
92
93        @Override
94        public void handleMessage(Message msg) {
95            int id = msg.arg1;
96            if (id >= mCarouselView.getCardCount()) {
97                Log.e(TAG, "Index out of range for get, card:" + id);
98                return;
99            }
100            if (msg.what < REQUEST_TEXTURE_N || msg.what > REQUEST_END) {
101                Log.e(TAG, "Unknown message: " + id);
102                return;
103            }
104            if (msg.what < REQUEST_DETAIL_TEXTURE_N) {
105                // REQUEST_TEXTURE_N
106                final Bitmap bitmap = getTexture(id);
107                if (bitmap != null) {
108                    mSyncHandler.obtainMessage(SET_TEXTURE_N, id, 0, bitmap).sendToTarget();
109                }
110            } else if (msg.what < REQUEST_GEOMETRY_N) {
111                // REQUEST_DETAIL_TEXTURE_N
112                final Bitmap bitmap = getDetailTexture(id);
113                if (bitmap != null) {
114                    mSyncHandler.obtainMessage(SET_DETAIL_TEXTURE_N, id, 0, bitmap).sendToTarget();
115                }
116            } else if (msg.what < REQUEST_END) {
117                // REQUEST_GEOMETRY_N
118                Mesh mesh = getGeometry(id);
119                if (mesh != null) {
120                    mSyncHandler.obtainMessage(SET_GEOMETRY_N, id, 0, mesh).sendToTarget();
121                }
122            }
123        }
124    };
125
126    class SyncHandler extends Handler {
127        @Override
128        public void handleMessage(Message msg) {
129            int id = msg.arg1;
130            if (id >= mCarouselView.getCardCount()) {
131                Log.e(TAG, "Index out of range for set, card:" + id);
132                return;
133            }
134
135            switch (msg.what) {
136                case SET_TEXTURE_N:
137                    mCarouselView.setTextureForItem(id, (Bitmap) msg.obj);
138                    break;
139
140                case SET_DETAIL_TEXTURE_N:
141                    DetailTextureParameters params = getDetailTextureParameters(id);
142                    float x = params != null ? params.textureOffsetX : 0.0f;
143                    float y = params != null ? params.textureOffsetY : 0.0f;
144                    float lx = params != null ? params.lineOffsetX : 0.0f;
145                    float ly = params != null ? params.lineOffsetY : 0.0f;
146                    mCarouselView.setDetailTextureForItem(id, x, y, lx, ly, (Bitmap) msg.obj);
147                    break;
148
149                case SET_GEOMETRY_N:
150                    mCarouselView.setGeometryForItem(id, (Mesh) msg.obj);
151                    break;
152            }
153        }
154    };
155
156    /**
157     * Implement this method if you want to load a texture for
158     * the given card.  Most subclasses will implement this. Note: this will generally
159     * <b>not</b> be called in the UI thread, so proper locking should be ensured.
160     *
161     * @param id of the texture to load
162     * @return a valid bitmap
163     */
164    public Bitmap getTexture(int id) {
165        return null;
166    }
167
168    /**
169     * Implement this method if you want to load a detail texture for
170     * the given card.  Most subclasses will implement this. Note: this will generally
171     * <b>not</b> be called in the UI thread, so proper locking should be ensured.
172     *
173     * @param id
174     * @return
175     */
176    public Bitmap getDetailTexture(int id) {
177        return null;
178    }
179
180    /**
181     * Implement this method if you want to load geometry for the given card.  Most subclasses
182     * will implement this. Note: this will generally <b>not</b> be called in the UI thread,
183     * so proper locking should be ensured.
184     *
185     * @param id
186     * @return
187     */
188    public Mesh getGeometry(int id) {
189        return null;
190    }
191
192    /**
193     * Implement this method if you want custom texture parameters for
194     * the given id. Note: this will generally
195     * <b>not</b> be called in the UI thread, so proper locking should be ensured.
196     *
197     * @param id
198     * @return texture parameters
199     */
200    public TextureParameters getTextureParameters(int id) {
201        return null;
202    }
203
204    /**
205     * Implement this method if you want custom detail texture parameters for
206     * the given id. Note: this will generally
207     * <b>not</b> be called in the UI thread, so proper locking should be ensured.
208     *
209     * @param id the id of the texture being requested
210     * @return detail texture parameters
211     */
212    public DetailTextureParameters getDetailTextureParameters(int id) {
213        return null;
214    }
215
216    public void onRequestTexture(int id) {
217        if (DBG) Log.v(TAG, "onRequestTexture(" + id + ")" );
218        mAsyncHandler.removeMessages(REQUEST_TEXTURE_N + id);
219        Message message = mAsyncHandler.obtainMessage(REQUEST_TEXTURE_N + id, id, 0);
220        mAsyncHandler.sendMessageDelayed(message, HOLDOFF_DELAY);
221    }
222
223    public void onInvalidateTexture(final int id) {
224        if (DBG) Log.v(TAG, "onInvalidateTexture(" + id + ")");
225        mAsyncHandler.removeMessages(REQUEST_TEXTURE_N + id);
226    }
227
228    public void onRequestGeometry(int id) {
229        if (DBG) Log.v(TAG, "onRequestGeometry(" + id + ")");
230        mAsyncHandler.removeMessages(REQUEST_GEOMETRY_N + id);
231        mAsyncHandler.sendMessage(mAsyncHandler.obtainMessage(REQUEST_GEOMETRY_N + id, id, 0));
232    }
233
234    public void onInvalidateGeometry(int id) {
235        if (DBG) Log.v(TAG, "onInvalidateGeometry(" + id + ")");
236        mAsyncHandler.removeMessages(REQUEST_GEOMETRY_N + id);
237    }
238
239    public void onRequestDetailTexture(int id) {
240        if (DBG) Log.v(TAG, "onRequestDetailTexture(" + id + ")" );
241        mAsyncHandler.removeMessages(REQUEST_DETAIL_TEXTURE_N + id);
242        Message message = mAsyncHandler.obtainMessage(REQUEST_DETAIL_TEXTURE_N + id, id, 0);
243        mAsyncHandler.sendMessageDelayed(message, HOLDOFF_DELAY);
244    }
245
246    public void onInvalidateDetailTexture(int id) {
247        if (DBG) Log.v(TAG, "onInvalidateDetailTexture(" + id + ")");
248        mAsyncHandler.removeMessages(REQUEST_DETAIL_TEXTURE_N + id);
249    }
250
251    public void onCardSelected(int n) {
252        if (DBG) Log.v(TAG, "onCardSelected(" + n + ")");
253    }
254
255    public void onCardLongPress(int n) {
256        if (DBG) Log.v(TAG, "onCardLongPress(" + n + ")");
257    }
258
259    public void onAnimationStarted() {
260
261    }
262
263    public void onAnimationFinished() {
264
265    }
266
267    public void onReportFirstCardPosition(int n) {
268
269    }
270
271    public void onResume() {
272        mCarouselView.onResume();
273    }
274
275    public void onPause() {
276        mCarouselView.onPause();
277    }
278
279    public void onDestroy() {
280        mHandlerThread.quit();
281    }
282
283    protected Handler getAsyncHandler() {
284        return mAsyncHandler;
285    }
286
287    protected CarouselView getCarouselView() {
288        return mCarouselView;
289    }
290}
291