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