diff options
author | Jim Miller <jaggies@google.com> | 2010-09-26 18:59:34 -0700 |
---|---|---|
committer | Jim Miller <jaggies@google.com> | 2010-09-26 18:59:34 -0700 |
commit | a3cb716626b477c98ba912698c765eab20f27286 (patch) | |
tree | d82b5c0cdab7b8642e8d28767439ab55a74b6dae /carousel/java | |
parent | 7867abe6e7af226fc29285890d6decb0ce3daa0f (diff) | |
download | android_frameworks_ex-a3cb716626b477c98ba912698c765eab20f27286.tar.gz android_frameworks_ex-a3cb716626b477c98ba912698c765eab20f27286.tar.bz2 android_frameworks_ex-a3cb716626b477c98ba912698c765eab20f27286.zip |
Major improvements to Carousel.
Added CarouselViewHelper class to simplify writing applications
that use the widged.
Updated examples to use new CarouselViewHelper class.
Added sample "lighting" to CarouselTestActivity.
Change-Id: I1b4a7e0d79f94781add16e1d2e7ec8b4657744d8
Diffstat (limited to 'carousel/java')
4 files changed, 309 insertions, 56 deletions
diff --git a/carousel/java/com/android/ex/carousel/CarouselRS.java b/carousel/java/com/android/ex/carousel/CarouselRS.java index e6433d2..f9fbadf 100644 --- a/carousel/java/com/android/ex/carousel/CarouselRS.java +++ b/carousel/java/com/android/ex/carousel/CarouselRS.java @@ -296,7 +296,7 @@ public class CarouselRS { programStoreBuilder.setDepthFunc(ProgramStore.DepthFunc.LESS); programStoreBuilder.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA, ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA); - programStoreBuilder.setDitherEnable(false); + programStoreBuilder.setDitherEnable(true); programStoreBuilder.setDepthMask(true); mProgramStore = programStoreBuilder.create(); mScript.set_programStore(mProgramStore); @@ -363,7 +363,7 @@ public class CarouselRS { { if (bitmap == null) return null; Allocation allocation = Allocation.createFromBitmap(mRS, bitmap, - elementForBitmap(bitmap, Bitmap.Config.RGB_565), mipmap); + elementForBitmap(bitmap, Bitmap.Config.ARGB_4444), mipmap); allocation.uploadToTexture(0); return allocation; } @@ -380,7 +380,8 @@ public class CarouselRS { } if (bitmap != null) { if (DBG) Log.v(TAG, "creating new bitmap"); - item.texture = Allocation.createFromBitmap(mRS, bitmap, RGB_565(mRS), MIPMAP); + item.texture = Allocation.createFromBitmap(mRS, bitmap, + elementForBitmap(bitmap, Bitmap.Config.ARGB_4444), MIPMAP); if (DBG) Log.v(TAG, "uploadToTexture(" + n + ")"); item.texture.uploadToTexture(0); if (DBG) Log.v(TAG, "done..."); diff --git a/carousel/java/com/android/ex/carousel/CarouselView.java b/carousel/java/com/android/ex/carousel/CarouselView.java index 92e870e..740c4b9 100644 --- a/carousel/java/com/android/ex/carousel/CarouselView.java +++ b/carousel/java/com/android/ex/carousel/CarouselView.java @@ -21,6 +21,7 @@ import com.android.ex.carousel.CarouselRS.CarouselCallback; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.PixelFormat; import android.graphics.Bitmap.Config; import android.renderscript.FileA3D; import android.renderscript.Float4; @@ -80,6 +81,7 @@ public abstract class CarouselView extends RSSurfaceView { private float mAt[] = { 14.7255f, -3.40001f, -1.30184f }; private float mUp[] = { 0.0f, 1.0f, 0.0f }; private Float4 mBackgroundColor = new Float4(0.0f, 0.0f, 0.0f, 1.0f); + private CarouselCallback mCarouselCallback; public static class Info { public Info(int _resId) { resId = _resId; } @@ -243,6 +245,10 @@ public abstract class CarouselView extends RSSurfaceView { } } + public int getCardCount() { + return mCardCount; + } + /** * This sets the texture on card n. It should only be called in response to * {@link CarouselCallback#onRequestTexture(int)}. Since there's no guarantee @@ -504,57 +510,4 @@ public abstract class CarouselView extends RSSurfaceView { return true; } - - private final CarouselCallback DEBUG_CALLBACK = new CarouselCallback() { - @Override - public void onAnimationStarted() { - if (DBG) Log.v(TAG, "onAnimationStarted()"); - } - - @Override - public void onAnimationFinished() { - if (DBG) Log.v(TAG, "onAnimationFinished()"); - } - - @Override - public void onCardSelected(int n) { - if (DBG) Log.v(TAG, "onCardSelected(" + n + ")"); - } - - @Override - public void onRequestGeometry(int n) { - if (DBG) Log.v(TAG, "onRequestGeometry(" + n + ")"); - } - - @Override - public void onInvalidateGeometry(int n) { - if (DBG) Log.v(TAG, "onInvalidateGeometry(" + n + ")"); - } - - @Override - public void onRequestTexture(int n) { - if (DBG) Log.v(TAG, "onRequestTexture(" + n + ")"); - } - - @Override - public void onInvalidateTexture(int n) { - if (DBG) Log.v(TAG, "onInvalidateTexture(" + n + ")"); - } - - public void onRequestDetailTexture(int n) { - if (DBG) Log.v(TAG, "onRequestDetailTexture(" + n + ")"); - } - - public void onInvalidateDetailTexture(int n) { - if (DBG) Log.v(TAG, "onInvalidateDetailTexture(" + n + ")"); - } - - @Override - public void onReportFirstCardPosition(int n) { - Log.v(TAG, "onReportFirstCardPosition(" + n + ")"); - } - }; - - private CarouselCallback mCarouselCallback = DEBUG_CALLBACK; - } diff --git a/carousel/java/com/android/ex/carousel/CarouselViewHelper.java b/carousel/java/com/android/ex/carousel/CarouselViewHelper.java new file mode 100644 index 0000000..55feb09 --- /dev/null +++ b/carousel/java/com/android/ex/carousel/CarouselViewHelper.java @@ -0,0 +1,260 @@ +package com.android.ex.carousel; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Matrix; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.renderscript.Mesh; +import android.util.Log; + +import com.android.ex.carousel.CarouselRS.CarouselCallback; + +/** + * CarouselViewHelper wraps all of the threading and event handling of the CarouselView, + * providing a simpler interface. Most users will just need to implement a handful of + * methods to get an application working. + * + */ +public class CarouselViewHelper implements CarouselCallback { + private static final String TAG = "CarouselViewHelper"; + private static final int SET_TEXTURE_N = 1; + private static final int SET_DETAIL_TEXTURE_N = 2; + private static final int SET_GEOMETRY_N = 3; + + // This is an ordered list of base message ids to allow removal of a single item from the + // list for a particular card. The implementation currently supports up to a million cards. + private static final int REQUEST_TEXTURE_N = 1000000; + private static final int REQUEST_DETAIL_TEXTURE_N = 2000000; + private static final int REQUEST_GEOMETRY_N = 3000000; + private static final int REQUEST_END = 4000000; + + private HandlerThread mHandlerThread; + private Context mContext; + private CarouselView mCarouselView; + private boolean DBG = true; + private long HOLDOFF_DELAY = 100; + private Handler mAsyncHandler; // Background thread handler for reading textures, geometry, etc. + private Handler mSyncHandler; // Synchronous handler for interacting with UI elements. + + public class TextureParameters { + public TextureParameters(Matrix _matrix) { matrix = _matrix; } + public Matrix matrix; + }; + + public class DetailTextureParameters { + public DetailTextureParameters(float offX, float offY) { + offsetX = offX; + offsetY = offY; + } + public float offsetX; + public float offsetY; + }; + + public void setCarouselView(CarouselView carouselView) { + mCarouselView = carouselView; + mCarouselView.setCallback(this); + } + + public CarouselViewHelper(Context context, CarouselView carouselView) { + this(context); + setCarouselView(carouselView); + } + + public CarouselViewHelper(Context context) { + mContext = context; + + mHandlerThread = new HandlerThread(TAG + ".handler"); + mHandlerThread.start(); + + mAsyncHandler = new AsyncHandler(mHandlerThread.getLooper()); + mSyncHandler = new SyncHandler(); // runs in calling thread + } + + class AsyncHandler extends Handler { + AsyncHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + int id = msg.arg1; + if (id >= mCarouselView.getCardCount()) { + Log.e(TAG, "Index out of range for get, card:" + id); + return; + } + if (msg.what < REQUEST_TEXTURE_N || msg.what > REQUEST_END) { + Log.e(TAG, "Unknown message: " + id); + return; + } + if (msg.what < REQUEST_DETAIL_TEXTURE_N) { + // REQUEST_TEXTURE_N + final Bitmap bitmap = getTexture(id); + if (bitmap != null) { + mSyncHandler.obtainMessage(SET_TEXTURE_N, id, 0, bitmap).sendToTarget(); + } + } else if (msg.what < REQUEST_GEOMETRY_N) { + // REQUEST_DETAIL_TEXTURE_N + final Bitmap bitmap = getDetailTexture(id); + if (bitmap != null) { + mSyncHandler.obtainMessage(SET_DETAIL_TEXTURE_N, id, 0, bitmap).sendToTarget(); + } + } else if (msg.what < REQUEST_END) { + // REQUEST_GEOMETRY_N + Mesh mesh = getGeometry(id); + if (mesh != null) { + mSyncHandler.obtainMessage(SET_GEOMETRY_N, id, 0, mesh).sendToTarget(); + } + } + } + }; + + class SyncHandler extends Handler { + @Override + public void handleMessage(Message msg) { + int id = msg.arg1; + if (id >= mCarouselView.getCardCount()) { + Log.e(TAG, "Index out of range for set, card:" + id); + return; + } + + switch (msg.what) { + case SET_TEXTURE_N: + mCarouselView.setTextureForItem(id, (Bitmap) msg.obj); + break; + + case SET_DETAIL_TEXTURE_N: + DetailTextureParameters params = getDetailTextureParameters(id); + float x = params != null ? params.offsetX : 0.0f; + float y = params != null ? params.offsetY : 0.0f; + mCarouselView.setDetailTextureForItem(id, x, y, (Bitmap) msg.obj); + break; + + case SET_GEOMETRY_N: + mCarouselView.setGeometryForItem(id, (Mesh) msg.obj); + break; + } + } + }; + + /** + * Implement this method if you want to load a texture for + * the given card. Most subclasses will implement this. Note: this will generally + * <b>not</b> be called in the UI thread, so proper locking should be ensured. + * + * @param id of the texture to load + * @return a valid bitmap + */ + public Bitmap getTexture(int id) { + return null; + } + + /** + * Implement this method if you want to load a detail texture for + * the given card. Most subclasses will implement this. Note: this will generally + * <b>not</b> be called in the UI thread, so proper locking should be ensured. + * + * @param id + * @return + */ + public Bitmap getDetailTexture(int id) { + return null; + } + + /** + * Implement this method if you want to load geometry for the given card. Most subclasses + * will implement this. Note: this will generally <b>not</b> be called in the UI thread, + * so proper locking should be ensured. + * + * @param id + * @return + */ + private Mesh getGeometry(int id) { + return null; + } + + /** + * Implement this method if you want custom texture parameters for + * the given id. Note: this will generally + * <b>not</b> be called in the UI thread, so proper locking should be ensured. + * + * @param id + * @return texture parameters + */ + public TextureParameters getTextureParameters(int id) { + return null; + } + + /** + * Implement this method if you want custom detail texture parameters for + * the given id. Note: this will generally + * <b>not</b> be called in the UI thread, so proper locking should be ensured. + * + * @param id the id of the texture being requested + * @return detail texture parameters + */ + public DetailTextureParameters getDetailTextureParameters(int id) { + return null; + } + + public void onRequestTexture(int id) { + if (DBG) Log.v(TAG, "onRequestTexture(" + id + ")" ); + mAsyncHandler.removeMessages(REQUEST_TEXTURE_N + id); + Message message = mAsyncHandler.obtainMessage(REQUEST_TEXTURE_N + id, id, 0); + mAsyncHandler.sendMessageDelayed(message, HOLDOFF_DELAY); + } + + public void onInvalidateTexture(final int id) { + if (DBG) Log.v(TAG, "onInvalidateTexture(" + id + ")"); + mAsyncHandler.removeMessages(REQUEST_TEXTURE_N + id); + } + + public void onRequestGeometry(int id) { + if (DBG) Log.v(TAG, "onRequestGeometry(" + id + ")"); + mAsyncHandler.removeMessages(REQUEST_GEOMETRY_N + id); + mAsyncHandler.sendMessage(mAsyncHandler.obtainMessage(REQUEST_GEOMETRY_N + id, id, 0)); + } + + public void onInvalidateGeometry(int id) { + if (DBG) Log.v(TAG, "onInvalidateGeometry(" + id + ")"); + mAsyncHandler.removeMessages(REQUEST_GEOMETRY_N + id); + } + + public void onRequestDetailTexture(int id) { + if (DBG) Log.v(TAG, "onRequestDetailTexture(" + id + ")" ); + mAsyncHandler.removeMessages(REQUEST_DETAIL_TEXTURE_N + id); + Message message = mAsyncHandler.obtainMessage(REQUEST_DETAIL_TEXTURE_N + id, id, 0); + mAsyncHandler.sendMessageDelayed(message, HOLDOFF_DELAY); + } + + public void onInvalidateDetailTexture(int id) { + if (DBG) Log.v(TAG, "onInvalidateDetailTexture(" + id + ")"); + mAsyncHandler.removeMessages(REQUEST_DETAIL_TEXTURE_N + id); + } + + public void onCardSelected(int n) { + if (DBG) Log.v(TAG, "onCardSelected(" + n + ")"); + } + + public void onAnimationStarted() { + + } + + public void onAnimationFinished() { + + } + + public void onReportFirstCardPosition(int n) { + + } + + public void onResume() { + mCarouselView.onResume(); + } + + public void onPause() { + mCarouselView.onPause(); + } +} diff --git a/carousel/java/com/android/ex/carousel/CarouselViewUtilities.java b/carousel/java/com/android/ex/carousel/CarouselViewUtilities.java new file mode 100644 index 0000000..8b53734 --- /dev/null +++ b/carousel/java/com/android/ex/carousel/CarouselViewUtilities.java @@ -0,0 +1,39 @@ +package com.android.ex.carousel; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import android.content.Context; +import android.graphics.Bitmap; +import android.media.MediaScannerConnection; +import android.os.Environment; +import android.util.Log; + +public class CarouselViewUtilities { + /** + * Debug utility to write the given bitmap to a file. + * + * @param context calling context + * @param bitmap the bitmap to write + * @param filename the name of the file to write + * @return + */ + public static boolean writeBitmapToFile(Context context, Bitmap bitmap, String filename) { + File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); + File file = new File(path, filename); + boolean result = false; + try { + path.mkdirs(); + OutputStream os = new FileOutputStream(file); + MediaScannerConnection.scanFile(context, new String[] { file.toString() }, null, null); + bitmap.compress(Bitmap.CompressFormat.PNG, 100, os); + result = true; + } catch (IOException e) { + Log.w("ExternalStorage", "Error writing " + file, e); + } + return result; + } + +} |