Update RecentApplications to use shared Carousel widget.

Change-Id: I5ca7389aeca9ee6f03f48317f9d1034f9fb8c1ca
diff --git a/Android.mk b/Android.mk
index 9d7906e..50e05d9 100644
--- a/Android.mk
+++ b/Android.mk
@@ -39,9 +39,6 @@
        core/java/android/webkit/EventLogTags.logtags \
        telephony/java/com/android/internal/telephony/EventLogTags.logtags \
 
-# RenderScript files for internal widgets
-LOCAL_SRC_FILES += $(call all-renderscript-files-under, core/java/com/android/internal/widget)
-
 # The following filters out code we are temporarily not including at all.
 # TODO: Move AWT and beans (and associated harmony code) back into libcore.
 # TODO: Maybe remove javax.microedition entirely?
diff --git a/core/java/com/android/internal/widget/CarouselRS.java b/core/java/com/android/internal/widget/CarouselRS.java
deleted file mode 100644
index 7589531..0000000
--- a/core/java/com/android/internal/widget/CarouselRS.java
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.renderscript.*;
-import android.renderscript.RenderScript.RSMessage;
-import android.renderscript.Sampler.Value;
-import android.renderscript.ProgramRaster.CullMode;
-import android.util.Log;
-
-import com.android.internal.R;
-
-import static android.renderscript.Element.*;
-import static android.renderscript.Sampler.Value.LINEAR;
-import static android.renderscript.Sampler.Value.WRAP;
-import static android.renderscript.Sampler.Value.CLAMP;
-
-public class CarouselRS  {
-    private static final int DEFAULT_VISIBLE_SLOTS = 1;
-    private static final int DEFAULT_CARD_COUNT = 1;
-    
-    // Client messages *** THIS LIST MUST MATCH THOSE IN carousel.rs ***
-    public static final int CMD_CARD_SELECTED = 100;
-    public static final int CMD_REQUEST_TEXTURE = 200;
-    public static final int CMD_INVALIDATE_TEXTURE = 210;
-    public static final int CMD_REQUEST_GEOMETRY = 300;
-    public static final int CMD_INVALIDATE_GEOMETRY = 310;
-    public static final int CMD_ANIMATION_STARTED = 400;
-    public static final int CMD_ANIMATION_FINISHED = 500;
-    public static final int CMD_PING = 600; // for debugging
-    
-    private static final String TAG = "CarouselRS";
-    private static final int DEFAULT_SLOT_COUNT = 10;
-    private static final boolean MIPMAP = false;
-    
-    private RenderScriptGL mRS;
-    private Resources mRes;
-    private ScriptC_Carousel mScript;
-    private ScriptField_Card mCards;
-    private Sampler mSampler;
-    private ProgramRaster mProgramRaster;
-    private ProgramStore mProgramStore;
-    private ProgramFragment mFragmentProgram;
-    private ProgramVertex mVertexProgram;
-    private ProgramRaster mRasterProgram;
-    private CarouselCallback mCallback;
-    private float[] mEyePoint = new float[3];
-    private float[] mAtPoint = new float[3];
-    private float[] mUp = new float[3];
-    
-    public static interface CarouselCallback {
-        /**
-         * Called when a card is selected
-         * @param n the id of the card
-         */
-        void onCardSelected(int n);
-        
-        /**
-         * Called when texture is needed for card n.  This happens when the given card becomes
-         * visible.
-         * @param n the id of the card
-         */
-        void onRequestTexture(int n);
-        
-        /**
-         * Called when a texture is no longer needed for card n.  This happens when the card
-         * goes out of view.
-         * @param n the id of the card
-         */
-        void onInvalidateTexture(int n);
-        
-        /**
-         * Called when geometry is needed for card n.
-         * @param n the id of the card.
-         */
-        void onRequestGeometry(int n);
-        
-        /**
-         * Called when geometry is no longer needed for card n. This happens when the card goes 
-         * out of view.
-         * @param n the id of the card
-         */
-        void onInvalidateGeometry(int n);
-        
-        /**
-         * Called when card animation (e.g. a fling) has started.
-         */
-        void onAnimationStarted();
-        
-        /**
-         * Called when card animation has stopped.
-         */
-        void onAnimationFinished();
-    };
-    
-    private RSMessage mRsMessage = new RSMessage() {
-        public void run() {
-            if (mCallback == null) return;
-            switch (mID) {
-                case CMD_CARD_SELECTED:
-                    mCallback.onCardSelected(mData[0]);
-                    break;
-                    
-                case CMD_REQUEST_TEXTURE:
-                    mCallback.onRequestTexture(mData[0]);
-                    break;
-                   
-                case CMD_INVALIDATE_TEXTURE:
-                    mCallback.onInvalidateTexture(mData[0]);
-                    break;
-                    
-                case CMD_REQUEST_GEOMETRY:
-                    mCallback.onRequestGeometry(mData[0]);
-                    break;
-                    
-                case CMD_INVALIDATE_GEOMETRY:
-                    mCallback.onInvalidateGeometry(mData[0]);
-                    break;
-                    
-                case CMD_ANIMATION_STARTED:
-                    mCallback.onAnimationStarted();
-                    break;
-                    
-                case CMD_ANIMATION_FINISHED:
-                    mCallback.onAnimationFinished();
-                    break;
-                    
-                case CMD_PING:
-                    Log.v(TAG, "PING...");
-                    break;
-                    
-                default:
-                    Log.e(TAG, "Unknown RSMessage: " + mID);
-            }
-        }
-    };
-    
-    public void init(RenderScriptGL rs, Resources res) {
-        mRS = rs;
-        mRes = res;
-
-        // create the script object
-        mScript = new ScriptC_Carousel(mRS, mRes, R.raw.carousel, true);
-        mRS.mMessageCallback = mRsMessage;
-
-        initProgramStore();
-        initFragmentProgram();
-        initRasterProgram();
-        initVertexProgram();
-        
-        setSlotCount(DEFAULT_SLOT_COUNT);
-        setVisibleSlots(DEFAULT_VISIBLE_SLOTS);
-        createCards(DEFAULT_CARD_COUNT);
-        
-        setStartAngle(0.0f);
-        setRadius(1.0f);
-        
-        // update the camera
-        boolean pcam = true;
-        if (pcam) {
-            float eye[] = { 20.6829f, 2.77081f, 16.7314f };
-            float at[] = { 14.7255f, -3.40001f, -1.30184f };
-            float up[] = { 0.0f, 1.0f, 0.0f };
-            setLookAt(eye, at, up);
-            setRadius(20.0f);
-            // Fov: 25
-        } else {
-            mScript.invoke_lookAt(2.5f, 2.0f, 2.5f, 0.0f, -0.75f, 0.0f,  0.0f, 1.0f, 0.0f);
-            mScript.set_cardRotation(0.0f);
-            setRadius(1.5f);
-        }
-
-        resumeRendering();
-    }
-
-    public void setLookAt(float[] eye, float[] at, float[] up) {
-        for (int i = 0; i < 3; i++) {
-            mEyePoint[i] = eye[i];
-            mAtPoint[i] = at[i];
-            mUp[i] = up[i];
-        }
-        mScript.invoke_lookAt(eye[0], eye[1], eye[2], at[0], at[1], at[2], up[0], up[1], up[2]);
-    }
-
-    public void setRadius(float radius) {
-        mScript.set_radius(radius);
-    }
-
-    private void initVertexProgram() {
-        ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null);
-        mVertexProgram = pvb.create();
-        ProgramVertex.MatrixAllocation pva = new ProgramVertex.MatrixAllocation(mRS);
-        mVertexProgram.bindAllocation(pva);
-        pva.setupProjectionNormalized(1, 1);
-        mScript.set_vertexProgram(mVertexProgram);
-    }
-
-    private void initRasterProgram() {
-        ProgramRaster.Builder programRasterBuilder = new ProgramRaster.Builder(mRS);
-        mRasterProgram = programRasterBuilder.create();
-        //mRasterProgram.setCullMode(CullMode.NONE);
-        mScript.set_rasterProgram(mRasterProgram);
-    }
-
-    private void initFragmentProgram() {
-        Sampler.Builder sampleBuilder = new Sampler.Builder(mRS);
-        sampleBuilder.setMin(Value.LINEAR_MIP_LINEAR);
-        sampleBuilder.setMag(LINEAR);
-        sampleBuilder.setWrapS(CLAMP);
-        sampleBuilder.setWrapT(CLAMP);
-        mSampler = sampleBuilder.create();
-        ProgramFragment.Builder fragmentBuilder = new ProgramFragment.Builder(mRS);
-        fragmentBuilder.setTexture(ProgramFragment.Builder.EnvMode.DECAL,
-                           ProgramFragment.Builder.Format.RGBA, 0);
-        mFragmentProgram = fragmentBuilder.create();
-        mFragmentProgram.bindSampler(mSampler, 0);
-        mScript.set_fragmentProgram(mFragmentProgram);
-    }
-
-    private void initProgramStore() {
-        ProgramStore.Builder programStoreBuilder = new ProgramStore.Builder(mRS, null, null);
-        programStoreBuilder.setDepthFunc(ProgramStore.DepthFunc.LESS);
-        programStoreBuilder.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA, 
-                ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
-        programStoreBuilder.setDitherEnable(false);
-        programStoreBuilder.setDepthMask(true);
-        mProgramStore = programStoreBuilder.create();
-        mScript.set_programStore(mProgramStore);
-    }
-    
-    public void createCards(int count)
-    {
-        mCards = count > 0 ? new ScriptField_Card(mRS, count) : null;
-        mScript.bind_cards(mCards);
-        mScript.invoke_createCards(count);
-    }
-    
-    public void setVisibleSlots(int count)
-    {
-        mScript.set_visibleSlotCount(count);
-    }
-    
-    public void setDefaultBitmap(Bitmap bitmap)
-    {
-        mScript.set_defaultTexture(allocationFromBitmap(bitmap, MIPMAP));
-    }
-    
-    public void setLoadingBitmap(Bitmap bitmap)
-    {
-        mScript.set_loadingTexture(allocationFromBitmap(bitmap, MIPMAP));
-    }
-    
-    public void setDefaultGeometry(Mesh mesh)
-    {
-        mScript.set_defaultGeometry(mesh);
-    }
-    
-    public void setLoadingGeometry(Mesh mesh)
-    {
-        mScript.set_loadingGeometry(mesh);
-    }
-    
-    public void setStartAngle(float theta)
-    {
-        mScript.set_startAngle(theta);
-    }
-    
-    public void setCallback(CarouselCallback callback)
-    {
-        mCallback = callback;
-    }
-    
-    private Allocation allocationFromBitmap(Bitmap bitmap, boolean mipmap)
-    {
-        if (bitmap == null) return null;
-        Allocation allocation = Allocation.createFromBitmap(mRS, bitmap, RGB_565(mRS), mipmap);
-        allocation.uploadToTexture(0);
-        return allocation;
-    }
-    
-    public void setTexture(int n, Bitmap bitmap)
-    {
-        ScriptField_Card.Item item = mCards.get(n);
-        if (item == null) {
-            Log.v(TAG, "setTexture(): no item at index " + n);
-            item = new ScriptField_Card.Item();
-        }
-        if (bitmap != null) {
-            Log.v(TAG, "creating new bitmap");
-            item.texture = Allocation.createFromBitmap(mRS, bitmap, RGB_565(mRS), MIPMAP);
-            Log.v(TAG, "uploadToTexture(" + n + ")");
-            item.texture.uploadToTexture(0);
-            Log.v(TAG, "done...");
-        } else {
-            if (item.texture != null) {
-                Log.v(TAG, "unloading texture " + n);
-                // Don't wait for GC to free native memory.
-                // Only works if textures are not shared.
-                item.texture.destroy(); 
-                item.texture = null;
-            }
-        }
-        mCards.set(item, n, false); // This is primarily used for reference counting.
-        mScript.invoke_setTexture(n, item.texture);
-    }
-    
-    public void setGeometry(int n, Mesh geometry)
-    {
-        final boolean mipmap = false;
-        ScriptField_Card.Item item = mCards.get(n);
-        if (item == null) {
-            Log.v(TAG, "setGeometry(): no item at index " + n);
-            item = new ScriptField_Card.Item();
-        }
-        if (geometry != null) {
-            item.geometry = geometry;
-        } else {
-            Log.v(TAG, "unloading geometry " + n);
-            if (item.geometry != null) {
-                // item.geometry.destroy(); 
-                item.geometry = null;
-            }
-        }
-        mCards.set(item, n, false);
-        mScript.invoke_setGeometry(n, item.geometry);
-    }
-
-    public void pauseRendering() {
-        // Used to update multiple states at once w/o redrawing for each.
-        mRS.contextBindRootScript(null);
-    }
-    
-    public void resumeRendering() {
-        mRS.contextBindRootScript(mScript);
-    }
-    
-    public void doMotion(float x, float y) {
-        mScript.invoke_doMotion(x,y);
-    }
-    
-    public void doSelection(float x, float y) {
-        mScript.invoke_doSelection(x, y);
-    }
-
-    public void doStart(float x, float y) {
-        mScript.invoke_doStart(x, y);
-    }
-
-    public void doStop(float x, float y) {
-        mScript.invoke_doStop(x, y);
-    }
-
-    public void setSlotCount(int n) {
-        mScript.set_slotCount(n);
-    }
-}
diff --git a/core/java/com/android/internal/widget/CarouselView.java b/core/java/com/android/internal/widget/CarouselView.java
deleted file mode 100644
index 217805b..0000000
--- a/core/java/com/android/internal/widget/CarouselView.java
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.widget;
-
-import com.android.internal.R;
-import com.android.internal.widget.CarouselRS.CarouselCallback;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Rect;
-import android.graphics.Bitmap.Config;
-import android.renderscript.FileA3D;
-import android.renderscript.Mesh;
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScriptGL;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.SurfaceHolder;
-
-public class CarouselView extends RSSurfaceView {
-    private static final boolean USE_DEPTH_BUFFER = true;
-    private final int DEFAULT_SLOT_COUNT = 10;
-    private final Bitmap DEFAULT_BITMAP = Bitmap.createBitmap(1, 1, Config.RGB_565);
-    private static final String TAG = "CarouselView";
-    private CarouselRS mRenderScript;
-    private RenderScriptGL mRS;
-    private Context mContext;
-    private boolean mTracking;
-    private Bitmap mDefaultBitmap;
-    private Bitmap mLoadingBitmap;
-    private Mesh mDefaultGeometry;
-    private Mesh mLoadingGeometry;
-    private int mCardCount = 0;
-    private int mVisibleSlots = 0;
-    private float mStartAngle;
-    private int mSlotCount = DEFAULT_SLOT_COUNT;
-
-    public CarouselView(Context context) {
-        this(context, null);
-    }
-
-    /**
-     * Constructor used when this widget is created from a layout file.
-     */
-    public CarouselView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mContext = context;
-        boolean useDepthBuffer = true;
-        mRS = createRenderScript(USE_DEPTH_BUFFER);
-        mRenderScript = new CarouselRS();
-        mRenderScript.init(mRS, getResources());
-        // TODO: add parameters to layout
-    }
-
-    @Override
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-        //mRS.contextSetSurface(w, h, holder.getSurface());
-        mRenderScript.init(mRS, getResources());
-        setSlotCount(mSlotCount);
-        createCards(mCardCount);
-        setVisibleSlots(mVisibleSlots);
-        setCallback(mCarouselCallback);
-        setDefaultBitmap(mDefaultBitmap);
-        setLoadingBitmap(mLoadingBitmap);
-        setDefaultGeometry(mDefaultGeometry);
-        setLoadingGeometry(mLoadingGeometry);
-        setStartAngle(mStartAngle);
-    }
-
-    /**
-     * Loads geometry from a resource id.
-     * 
-     * @param resId
-     * @return the loaded mesh or null if it cannot be loaded
-     */
-    public Mesh loadGeometry(int resId) {
-        Resources res = mContext.getResources();
-        FileA3D model = FileA3D.createFromResource(mRS, res, resId);
-        FileA3D.IndexEntry entry = model.getIndexEntry(0);
-        if(entry == null || entry.getClassID() != FileA3D.ClassID.MESH) {
-            return null;
-        }
-        return (Mesh) entry.getObject();
-    }
-    
-    /**
-     * Load A3D file from resource.  If resId == 0, will clear geometry for this item.
-     * @param n
-     * @param resId
-     */
-    public void setGeometryForItem(int n, Mesh mesh) {
-        mRenderScript.setGeometry(n, mesh);
-    }
-    
-    public void setSlotCount(int n) {
-        mSlotCount = n;
-        if (mRenderScript != null) {
-            mRenderScript.setSlotCount(n);
-        }
-    }
-
-    public void setVisibleSlots(int n) {
-        mVisibleSlots = n;
-        if (mRenderScript != null) {
-            mRenderScript.setVisibleSlots(n);
-        }
-    }
-
-    public void createCards(int n) {
-        mCardCount = n;
-        if (mRenderScript != null) {
-            mRenderScript.createCards(n);
-        }
-    }
-    
-    public void setTextureForItem(int n, Bitmap bitmap) {
-        if (mRenderScript != null) {
-            Log.v(TAG, "setTextureForItem(" + n + ")");
-            mRenderScript.setTexture(n, bitmap); 
-            Log.v(TAG, "done");
-        }
-    }
-
-    public void setDefaultBitmap(Bitmap bitmap) {
-        mDefaultBitmap = bitmap; 
-        if (mRenderScript != null) {
-            mRenderScript.setDefaultBitmap(bitmap);
-        }
-    }
-    
-    public void setLoadingBitmap(Bitmap bitmap) {
-        mLoadingBitmap = bitmap;
-        if (mRenderScript != null) {
-            mRenderScript.setLoadingBitmap(bitmap);
-        }
-    }
-    
-    public void setDefaultGeometry(Mesh mesh) {
-        mDefaultGeometry = mesh;
-        if (mRenderScript != null) {
-            mRenderScript.setDefaultGeometry(mesh);
-        }
-    }
-    
-    public void setLoadingGeometry(Mesh mesh) {
-        mLoadingGeometry = mesh;
-        if (mRenderScript != null) {
-            mRenderScript.setLoadingGeometry(mesh);
-        }
-    }
-    
-    public void setCallback(CarouselCallback callback)
-    {
-        mCarouselCallback = callback;
-        if (mRenderScript != null) {
-            mRenderScript.setCallback(callback);
-        }
-    }
-
-    public void setStartAngle(float angle)
-    {
-        mStartAngle = angle;
-        if (mRenderScript != null) {
-            mRenderScript.setStartAngle(angle);
-        }
-    }
-    
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        if(mRS != null) {
-            mRS = null;
-            destroyRenderScript();
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        if (mRS == null) {
-            mRS = createRenderScript(USE_DEPTH_BUFFER);
-        }
-    }
-    
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        final int action = event.getAction();
-        final float x = event.getX();
-        final float y = event.getY();
-        
-        if (mRenderScript == null) {
-            return true;
-        }
-
-        switch (action) {
-            case MotionEvent.ACTION_DOWN:
-                mTracking = true;
-                mRenderScript.doStart(x, y);
-                break;
-                
-            case MotionEvent.ACTION_MOVE:
-                if (mTracking) {
-                    mRenderScript.doMotion(x, y);
-                }
-                break;
-                
-            case MotionEvent.ACTION_UP:
-                mRenderScript.doStop(x, y);
-                mTracking = false;
-                break;
-        }
-
-        return true;
-    }
-    
-    private final CarouselCallback DEBUG_CALLBACK = new CarouselCallback() {
-        public void onAnimationStarted() {
-            Log.v(TAG, "onAnimationStarted()");
-        }
-        
-        public void onAnimationFinished() {
-            Log.v(TAG, "onAnimationFinished()");
-        }
-
-        public void onCardSelected(int n) {
-            Log.v(TAG, "onCardSelected(" + n + ")");
-        }
-
-        public void onRequestGeometry(int n) {
-            Log.v(TAG, "onRequestGeometry(" + n + ")");
-        }
-
-        public void onInvalidateGeometry(int n) {
-            Log.v(TAG, "onInvalidateGeometry(" + n + ")");
-        }
-        
-        public void onRequestTexture(final int n) {
-            Log.v(TAG, "onRequestTexture(" + n + ")");
-        }
-
-        public void onInvalidateTexture(int n) {
-            Log.v(TAG, "onInvalidateTexture(" + n + ")");
-        }
-
-    };
-    
-    private CarouselCallback mCarouselCallback = DEBUG_CALLBACK;
-}
diff --git a/core/java/com/android/internal/widget/carousel.rs b/core/java/com/android/internal/widget/carousel.rs
deleted file mode 100644
index 87e24c0..0000000
--- a/core/java/com/android/internal/widget/carousel.rs
+++ /dev/null
@@ -1,788 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.internal.widget)
-#pragma rs set_reflect_license()
-
-#include "rs_graphics.rsh"
-
-typedef struct __attribute__((aligned(4))) Card {
-    rs_allocation texture;
-    rs_mesh geometry;
-    //rs_matrix4x4 matrix; // custom transform for this card/geometry
-    int textureState;  // whether or not the texture is loaded.
-    int geometryState; // whether or not geometry is loaded
-    int visible; // not bool because of packing bug?
-} Card_t;
-
-typedef struct Ray_s {
-    float3 position;
-    float3 direction;
-} Ray;
-
-typedef struct PerspectiveCamera_s {
-    float3 from;
-    float3 at;
-    float3 up;
-    float  fov;
-    float  aspect;
-    float  near;
-    float  far;
-} PerspectiveCamera;
-
-// Request states. Used for loading 3D object properties from the Java client.
-// Typical properties: texture, geometry and matrices.
-enum {
-    STATE_INVALID = 0, // item hasn't been loaded
-    STATE_LOADING, // we've requested an item but are waiting for it to load
-    STATE_LOADED // item was delivered
-};
-
-// Client messages *** THIS LIST MUST MATCH THOSE IN CarouselRS.java. ***
-static const int CMD_CARD_SELECTED = 100;
-static const int CMD_REQUEST_TEXTURE = 200;
-static const int CMD_INVALIDATE_TEXTURE = 210;
-static const int CMD_REQUEST_GEOMETRY = 300;
-static const int CMD_INVALIDATE_GEOMETRY = 310;
-static const int CMD_ANIMATION_STARTED = 400;
-static const int CMD_ANIMATION_FINISHED = 500;
-static const int CMD_PING = 600;
-
-// Constants
-static const int ANIMATION_SCALE_TIME = 200; // Time it takes to animate selected card, in ms
-static const float3 SELECTED_SCALE_FACTOR = { 0.2f, 0.2f, 0.2f }; // increase by this %
-
-// Debug flags
-bool debugCamera = false; // dumps ray/camera coordinate stuff
-bool debugPicking = false; // renders picking area on top of geometry
-
-// Exported variables. These will be reflected to Java set_* variables.
-Card_t *cards; // array of cards to draw
-float startAngle; // position of initial card, in radians
-int slotCount; // number of positions where a card can be
-int cardCount; // number of cards in stack
-int visibleSlotCount; // number of visible slots (for culling)
-float radius; // carousel radius. Cards will be centered on a circle with this radius
-float cardRotation; // rotation of card in XY plane relative to Z=1
-rs_program_store programStore;
-rs_program_fragment fragmentProgram;
-rs_program_vertex vertexProgram;
-rs_program_raster rasterProgram;
-rs_allocation defaultTexture; // shown when no other texture is assigned
-rs_allocation loadingTexture; // progress texture (shown when app is fetching the texture)
-rs_mesh defaultGeometry; // shown when no geometry is loaded
-rs_mesh loadingGeometry; // shown when geometry is loading
-rs_matrix4x4 projectionMatrix;
-rs_matrix4x4 modelviewMatrix;
-
-#pragma rs export_var(radius, cards, slotCount, visibleSlotCount, cardRotation)
-#pragma rs export_var(programStore, fragmentProgram, vertexProgram, rasterProgram)
-#pragma rs export_var(startAngle, defaultTexture, loadingTexture, defaultGeometry, loadingGeometry)
-#pragma rs export_func(createCards, lookAt, doStart, doStop, doMotion, doSelection, setTexture)
-#pragma rs export_func(setGeometry, debugCamera, debugPicking)
-
-// Local variables
-static float bias; // rotation bias, in radians. Used for animation and dragging.
-static bool updateCamera;    // force a recompute of projection and lookat matrices
-static bool initialized;
-static float3 backgroundColor = { 0.0f, 0.0f, 0.0f };
-static const float FLT_MAX = 1.0e37;
-static int currentSelection = -1;
-static int64_t touchTime = -1;  // time of first touch (see doStart())
-static float touchBias = 0.0f; // bias on first touch
-
-// Default geometry when card.geometry is not set.
-static const float3 cardVertices[4] = {
-        { -1.0, -1.0, 0.0 },
-        { 1.0, -1.0, 0.0 },
-        { 1.0, 1.0, 0.0 },
-        {-1.0, 1.0, 0.0 }
-};
-
-// Default camera
-static PerspectiveCamera camera = {
-        {2,2,2}, // from
-        {0,0,0}, // at
-        {0,1,0}, // up
-        25.0f,   // field of view
-        1.0f,    // aspect
-        0.1f,    // near
-        100.0f   // far
-};
-
-// Forward references
-static int intersectGeometry(Ray* ray, float *bestTime);
-static bool makeRayForPixelAt(Ray* ray, float x, float y);
-static float deltaTimeInSeconds(int64_t current);
-
-void init() {
-    // initializers currently have a problem when the variables are exported, so initialize
-    // globals here.
-    rsDebug("Renderscript: init()", 0);
-    startAngle = 0.0f;
-    slotCount = 10;
-    visibleSlotCount = 1;
-    bias = 0.0f;
-    radius = 1.0f;
-    cardRotation = 0.0f;
-    updateCamera = true;
-    initialized = false;
-}
-
-static void updateAllocationVars()
-{
-    // Cards
-    rs_allocation cardAlloc = rsGetAllocation(cards);
-    // TODO: use new rsIsObject()
-    cardCount = cardAlloc.p != 0 ? rsAllocationGetDimX(cardAlloc) : 0;
-}
-
-void createCards(int n)
-{
-    rsDebug("CreateCards: ", n);
-    initialized = false;
-    updateAllocationVars();
-}
-
-// Return angle for position p. Typically p will be an integer position, but can be fractional.
-static float cardPosition(float p)
-{
-    return startAngle + bias + 2.0f * M_PI * p / slotCount;
-}
-
-// Return slot for a card in position p. Typically p will be an integer slot, but can be fractional.
-static float slotPosition(float p)
-{
-    return startAngle + 2.0f * M_PI * p / slotCount;
-}
-
-// Return the lowest slot number for a given angular position.
-static int cardIndex(float angle)
-{
-    return floor(angle - startAngle - bias) * slotCount / (2.0f * M_PI);
-}
-
-// Set basic camera properties:
-//    from - position of the camera in x,y,z
-//    at - target we're looking at - used to compute view direction
-//    up - a normalized vector indicating up (typically { 0, 1, 0})
-//
-// NOTE: the view direction and up vector cannot be parallel/antiparallel with each other
-void lookAt(float fromX, float fromY, float fromZ,
-        float atX, float atY, float atZ,
-        float upX, float upY, float upZ)
-{
-    camera.from.x = fromX;
-    camera.from.y = fromY;
-    camera.from.z = fromZ;
-    camera.at.x = atX;
-    camera.at.y = atY;
-    camera.at.z = atZ;
-    camera.up.x = upX;
-    camera.up.y = upY;
-    camera.up.z = upZ;
-    updateCamera = true;
-}
-
-// Load a projection matrix for the given parameters.  This is equivalent to gluPerspective()
-static void loadPerspectiveMatrix(rs_matrix4x4* matrix, float fovy, float aspect, float near, float far)
-{
-    rsMatrixLoadIdentity(matrix);
-    float top = near * tan((float) (fovy * M_PI / 360.0f));
-    float bottom = -top;
-    float left = bottom * aspect;
-    float right = top * aspect;
-    rsMatrixLoadFrustum(matrix, left, right, bottom, top, near, far);
-}
-
-// Construct a matrix based on eye point, center and up direction. Based on the
-// man page for gluLookat(). Up must be normalized.
-static void loadLookatMatrix(rs_matrix4x4* matrix, float3 eye, float3 center, float3 up)
-{
-    float3 f = normalize(center - eye);
-    float3 s = normalize(cross(f, up));
-    float3 u = cross(s, f);
-    float m[16];
-    m[0] = s.x;
-    m[4] = s.y;
-    m[8] = s.z;
-    m[12] = 0.0f;
-    m[1] = u.x;
-    m[5] = u.y;
-    m[9] = u.z;
-    m[13] = 0.0f;
-    m[2] = -f.x;
-    m[6] = -f.y;
-    m[10] = -f.z;
-    m[14] = 0.0f;
-    m[3] = m[7] = m[11] = 0.0f;
-    m[15] = 1.0f;
-    rsMatrixLoad(matrix, m);
-    rsMatrixTranslate(matrix, -eye.x, -eye.y, -eye.z);
-}
-
-void setTexture(int n, rs_allocation texture)
-{
-    cards[n].texture = texture;
-    if (cards[n].texture.p != 0)
-        cards[n].textureState = STATE_LOADED;
-    else
-        cards[n].textureState = STATE_INVALID;
-}
-
-void setGeometry(int n, rs_mesh geometry)
-{
-    cards[n].geometry = geometry;
-    if (cards[n].geometry.p != 0)
-        cards[n].geometryState = STATE_LOADED;
-    else
-        cards[n].geometryState = STATE_INVALID;
-}
-
-static float3 getAnimatedScaleForSelected()
-{
-    int64_t dt = (rsUptimeMillis() - touchTime);
-    float fraction = (dt < ANIMATION_SCALE_TIME) ? (float) dt / ANIMATION_SCALE_TIME : 1.0f;
-    const float3 one = { 1.0f, 1.0f, 1.0f };
-    return one + fraction * SELECTED_SCALE_FACTOR;
-}
-
-static void getMatrixForCard(rs_matrix4x4* matrix, int i)
-{
-    float theta = cardPosition(i);
-    rsMatrixRotate(matrix, degrees(theta), 0, 1, 0);
-    rsMatrixTranslate(matrix, radius, 0, 0);
-    rsMatrixRotate(matrix, degrees(-theta + cardRotation), 0, 1, 0);
-    if (i == currentSelection) {
-        float3 scale = getAnimatedScaleForSelected();
-        rsMatrixScale(matrix, scale.x, scale.y, scale.z);
-    }
-    // TODO: apply custom matrix for cards[i].geometry
-}
-
-static void drawCards()
-{
-    float depth = 1.0f;
-    for (int i = 0; i < cardCount; i++) {
-        if (cards[i].visible) {
-            // Bind texture
-            if (cards[i].textureState == STATE_LOADED) {
-                rsgBindTexture(fragmentProgram, 0, cards[i].texture);
-            } else if (cards[i].textureState == STATE_LOADING) {
-                rsgBindTexture(fragmentProgram, 0, loadingTexture);
-            } else {
-                rsgBindTexture(fragmentProgram, 0, defaultTexture);
-            }
-
-            // Draw geometry
-            rs_matrix4x4 matrix = modelviewMatrix;
-            getMatrixForCard(&matrix, i);
-            rsgProgramVertexLoadModelMatrix(&matrix);
-            if (cards[i].geometryState == STATE_LOADED && cards[i].geometry.p != 0) {
-                rsgDrawMesh(cards[i].geometry);
-            } else if (cards[i].geometryState == STATE_LOADING && loadingGeometry.p != 0) {
-                rsgDrawMesh(loadingGeometry);
-            } else if (defaultGeometry.p != 0) {
-                rsgDrawMesh(defaultGeometry);
-            } else {
-                // Draw place-holder geometry
-                rsgDrawQuad(
-                    cardVertices[0].x, cardVertices[0].y, cardVertices[0].z,
-                    cardVertices[1].x, cardVertices[1].y, cardVertices[1].z,
-                    cardVertices[2].x, cardVertices[2].y, cardVertices[2].z,
-                    cardVertices[3].x, cardVertices[3].y, cardVertices[3].z);
-            }
-        }
-    }
-}
-
-static void updateCameraMatrix(float width, float height)
-{
-    float aspect = width / height;
-    if (aspect != camera.aspect || updateCamera) {
-        camera.aspect = aspect;
-        loadPerspectiveMatrix(&projectionMatrix, camera.fov, camera.aspect, camera.near, camera.far);
-        rsgProgramVertexLoadProjectionMatrix(&projectionMatrix);
-
-        loadLookatMatrix(&modelviewMatrix, camera.from, camera.at, camera.up);
-        rsgProgramVertexLoadModelMatrix(&modelviewMatrix);
-        updateCamera = false;
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Behavior/Physics
-////////////////////////////////////////////////////////////////////////////////////////////////////
-static float velocity = 0.0f;  // angular velocity in radians/s
-static bool isDragging;
-static int64_t lastTime = 0L; // keep track of how much time has passed between frames
-static float2 lastPosition;
-static bool animating = false;
-static float velocityThreshold = 0.1f * M_PI / 180.0f;
-static float velocityTracker;
-static int velocityTrackerCount;
-static float mass = 5.0f; // kg
-
-static const float G = 9.80f; // gravity constant, in m/s
-static const float springConstant = 0.0f;
-static const float frictionCoeff = 10.0f;
-static const float dragFactor = 0.25f;
-
-static float dragFunction(float x, float y)
-{
-    return dragFactor * ((x - lastPosition.x) / rsgGetWidth()) * M_PI;
-}
-
-static float deltaTimeInSeconds(int64_t current)
-{
-    return (lastTime > 0L) ? (float) (current - lastTime) / 1000.0f : 0.0f;
-}
-
-int doSelection(float x, float y)
-{
-    Ray ray;
-    if (makeRayForPixelAt(&ray, x, y)) {
-        float bestTime = FLT_MAX;
-        return intersectGeometry(&ray, &bestTime);
-    }
-    return -1;
-}
-
-void doStart(float x, float y)
-{
-    lastPosition.x = x;
-    lastPosition.y = y;
-    velocity = 0.0f;
-    if (animating) {
-        rsSendToClient(CMD_ANIMATION_FINISHED);
-        animating = false;
-    }
-    velocityTracker = 0.0f;
-    velocityTrackerCount = 0;
-    touchTime = rsUptimeMillis();
-    touchBias = bias;
-    currentSelection = doSelection(x, y);
-}
-
-
-void doStop(float x, float y)
-{
-    int64_t currentTime = rsUptimeMillis();
-    updateAllocationVars();
-    if (currentSelection != -1 && (currentTime - touchTime) < ANIMATION_SCALE_TIME) {
-        rsDebug("HIT!", currentSelection);
-        int data[1];
-        data[0] = currentSelection;
-        rsSendToClientBlocking(CMD_CARD_SELECTED, data, sizeof(data));
-    } else {
-        velocity = velocityTrackerCount > 0 ?
-                    (velocityTracker / velocityTrackerCount) : 0.0f;  // avg velocity
-        if (fabs(velocity) > velocityThreshold) {
-            animating = true;
-            rsSendToClient(CMD_ANIMATION_STARTED);
-        }
-    }
-    currentSelection = -1;
-    lastTime = rsUptimeMillis();
-}
-
-void doMotion(float x, float y)
-{
-    int64_t currentTime = rsUptimeMillis();
-    float deltaOmega = dragFunction(x, y);
-    bias += deltaOmega;
-    lastPosition.x = x;
-    lastPosition.y = y;
-    float dt = deltaTimeInSeconds(currentTime);
-    if (dt > 0.0f) {
-        float v = deltaOmega / dt;
-        //if ((velocityTracker > 0.0f) == (v > 0.0f)) {
-            velocityTracker += v;
-            velocityTrackerCount++;
-        //} else {
-        //    velocityTracker = v;
-        //    velocityTrackerCount = 1;
-        //}
-    }
-
-    // Drop current selection if user drags position +- a partial slot
-    if (currentSelection != -1) {
-        const float slotMargin = 0.5f * (2.0f * M_PI / slotCount);
-        if (fabs(touchBias - bias) > slotMargin) {
-            currentSelection = -1;
-        }
-    }
-    lastTime = currentTime;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Hit detection using ray casting.
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-static bool
-rayTriangleIntersect(Ray* ray, float3 p0, float3 p1, float3 p2, float *tout)
-{
-    static const float tmin = 0.0f;
-
-    float3 e1 = p1 - p0;
-    float3 e2 = p2 - p0;
-    float3 s1 = cross(ray->direction, e2);
-
-    float div = dot(s1, e1);
-    if (div == 0.0f) return false;  // ray is parallel to plane.
-
-    float3 d = ray->position - p0;
-    float invDiv = 1.0f / div;
-
-    float u = dot(d, s1) * invDiv;
-    if (u < 0.0f || u > 1.0f) return false;
-
-    float3 s2 = cross(d, e1);
-    float v = dot(ray->direction, s2) * invDiv;
-    if ( v < 0.0f || (u+v) > 1.0f) return false;
-
-    float t = dot(e2, s2) * invDiv;
-    if (t < tmin || t > *tout)
-        return false;
-    *tout = t;
-    return true;
-}
-
-// Creates a ray for an Android pixel coordinate.
-// Note that the Y coordinate is opposite of GL rendering coordinates.
-static bool makeRayForPixelAt(Ray* ray, float x, float y)
-{
-    if (debugCamera) {
-        rsDebug("------ makeRay() -------", 0);
-        rsDebug("Camera.from:", camera.from);
-        rsDebug("Camera.at:", camera.at);
-        rsDebug("Camera.dir:", normalize(camera.at - camera.from));
-    }
-
-    // Vector math.  This has the potential to be much faster.
-    // TODO: pre-compute lowerLeftRay, du, dv to eliminate most of this math.
-    if (true) {
-        const float u = x / rsgGetWidth();
-        const float v = 1.0f - (y / rsgGetHeight());
-        const float aspect = (float) rsgGetWidth() / rsgGetHeight();
-        const float tanfov2 = 2.0f * tan(radians(camera.fov / 2.0f));
-        float3 dir = normalize(camera.at - camera.from);
-        float3 du = tanfov2 * normalize(cross(dir, camera.up));
-        float3 dv = tanfov2 * normalize(cross(du, dir));
-        du *= aspect;
-        float3 lowerLeftRay = dir - (0.5f * du) - (0.5f * dv);
-        const float3 rayPoint = camera.from;
-        const float3 rayDir = normalize(lowerLeftRay + u*du + v*dv);
-        if (debugCamera) {
-            rsDebug("Ray direction (vector math) = ", rayDir);
-        }
-
-        ray->position =  rayPoint;
-        ray->direction = rayDir;
-    }
-
-    // Matrix math.  This is more generic if we allow setting model view and projection matrices
-    // directly
-    else {
-        rs_matrix4x4 pm = modelviewMatrix;
-        rsMatrixLoadMultiply(&pm, &projectionMatrix, &modelviewMatrix);
-        if (!rsMatrixInverse(&pm)) {
-            rsDebug("ERROR: SINGULAR PM MATRIX", 0);
-            return false;
-        }
-        const float width = rsgGetWidth();
-        const float height = rsgGetHeight();
-        const float winx = 2.0f * x / width - 1.0f;
-        const float winy = 2.0f * y / height - 1.0f;
-
-        float4 eye = { 0.0f, 0.0f, 0.0f, 1.0f };
-        float4 at = { winx, winy, 1.0f, 1.0f };
-
-        eye = rsMatrixMultiply(&pm, eye);
-        eye *= 1.0f / eye.w;
-
-        at = rsMatrixMultiply(&pm, at);
-        at *= 1.0f / at.w;
-
-        const float3 rayPoint = { eye.x, eye.y, eye.z };
-        const float3 atPoint = { at.x, at.y, at.z };
-        const float3 rayDir = normalize(atPoint - rayPoint);
-        if (debugCamera) {
-            rsDebug("winx: ", winx);
-            rsDebug("winy: ", winy);
-            rsDebug("Ray position (transformed) = ", eye);
-            rsDebug("Ray direction (transformed) = ", rayDir);
-        }
-        ray->position =  rayPoint;
-        ray->direction = rayDir;
-    }
-
-    return true;
-}
-
-static int intersectGeometry(Ray* ray, float *bestTime)
-{
-    int hit = -1;
-    for (int id = 0; id < cardCount; id++) {
-        if (cards[id].visible) {
-            rs_matrix4x4 matrix;
-            float3 p[4];
-
-            // Transform card vertices to world space
-            rsMatrixLoadIdentity(&matrix);
-            getMatrixForCard(&matrix, id);
-            for (int vertex = 0; vertex < 4; vertex++) {
-                float4 tmp = rsMatrixMultiply(&matrix, cardVertices[vertex]);
-                if (tmp.w != 0.0f) {
-                    p[vertex].x = tmp.x;
-                    p[vertex].y = tmp.y;
-                    p[vertex].z = tmp.z;
-                    p[vertex] *= 1.0f / tmp.w;
-                } else {
-                    rsDebug("Bad w coord: ", tmp);
-                }
-            }
-
-            // Intersect card geometry
-            if (rayTriangleIntersect(ray, p[0], p[1], p[2], bestTime)
-                || rayTriangleIntersect(ray, p[2], p[3], p[0], bestTime)) {
-                hit = id;
-            }
-        }
-    }
-    return hit;
-}
-
-// This method computes the position of all the cards by updating bias based on a
-// simple physics model.
-// If the cards are still in motion, returns true.
-static bool updateNextPosition(int64_t currentTime)
-{
-    if (animating) {
-        float dt = deltaTimeInSeconds(currentTime);
-        if (dt <= 0.0f)
-            return animating;
-        const float minStepTime = 1.0f / 300.0f; // ~5 steps per frame
-        const int N = (dt > minStepTime) ? (1 + round(dt / minStepTime)) : 1;
-        dt /= N;
-        for (int i = 0; i < N; i++) {
-            // Force friction - always opposes motion
-            const float Ff = -frictionCoeff * velocity;
-
-            // Restoring force to match cards with slots
-            const float theta = startAngle + bias;
-            const float dtheta = 2.0f * M_PI / slotCount;
-            const float position = theta / dtheta;
-            const float fraction = position - floor(position); // fractional position between slots
-            float x;
-            if (fraction > 0.5f) {
-                x = - (1.0f - fraction);
-            } else {
-                x = fraction;
-            }
-            const float Fr = - springConstant * x;
-
-            // compute velocity
-            const float momentum = mass * velocity + (Ff + Fr)*dt;
-            velocity = momentum / mass;
-            bias += velocity * dt;
-        }
-
-        // TODO: Add animation to smoothly move back to slots. Currently snaps to location.
-        if (cardCount <= visibleSlotCount) {
-            // TODO: this aligns the cards to the first slot (theta = startAngle) when there aren't
-            // enough visible cards. It should be generalized to allow alignment to front,
-            // middle or back of the stack.
-            if (cardPosition(0) != slotPosition(0)) {
-                bias = 0.0f;
-            }
-        } else {
-            if (cardPosition(cardCount) < 0.0f) {
-                bias = -slotPosition(cardCount);
-            } else if (cardPosition(0) > slotPosition(0)) {
-                bias = 0.0f;
-            }
-        }
-
-        animating = fabs(velocity) > velocityThreshold;
-        if (!animating) {
-            const float dtheta = 2.0f * M_PI / slotCount;
-            bias = round((startAngle + bias) / dtheta) * dtheta - startAngle;
-            rsSendToClient(CMD_ANIMATION_FINISHED);
-        }
-    }
-    lastTime = currentTime;
-
-    return animating;
-}
-
-// Cull cards based on visibility and visibleSlotCount.
-// If visibleSlotCount is > 0, then only show those slots and cull the rest.
-// Otherwise, it should cull based on bounds of geometry.
-static int cullCards()
-{
-    const float thetaFirst = slotPosition(-1); // -1 keeps the card in front around a bit longer
-    const float thetaLast = slotPosition(visibleSlotCount);
-
-    int count = 0;
-    for (int i = 0; i < cardCount; i++) {
-        if (visibleSlotCount > 0) {
-            // If visibleSlotCount is specified, then only show up to visibleSlotCount cards.
-            float p = cardPosition(i);
-            if (p >= thetaFirst && p < thetaLast) {
-                cards[i].visible = true;
-                count++;
-            } else {
-                cards[i].visible = false;
-            }
-        } else {
-            // Cull the rest of the cards using bounding box of geometry.
-            // TODO
-            cards[i].visible = true;
-            count++;
-        }
-    }
-    return count;
-}
-
-// Request texture/geometry for items that have come into view
-// or doesn't have a texture yet.
-static void updateCardResources()
-{
-    for (int i = 0; i < cardCount; i++) {
-        int data[1];
-        if (cards[i].visible) {
-            // request texture from client if not loaded
-            if (cards[i].textureState == STATE_INVALID) {
-                data[0] = i;
-                bool enqueued = rsSendToClient(CMD_REQUEST_TEXTURE, data, sizeof(data));
-                if (enqueued) {
-                    cards[i].textureState = STATE_LOADING;
-                } else {
-                    rsDebug("Couldn't send CMD_REQUEST_TEXTURE", 0);
-                }
-            }
-            // request geometry from client if not loaded
-            if (cards[i].geometryState == STATE_INVALID) {
-                data[0] = i;
-                bool enqueued = rsSendToClient(CMD_REQUEST_GEOMETRY, data, sizeof(data));
-                if (enqueued) {
-                    cards[i].geometryState = STATE_LOADING;
-                } else {
-                    rsDebug("Couldn't send CMD_REQUEST_GEOMETRY", 0);
-                }
-            }
-        } else {
-            // ask the host to remove the texture
-            if (cards[i].textureState == STATE_LOADED) {
-                data[0] = i;
-                bool enqueued = rsSendToClient(CMD_INVALIDATE_TEXTURE, data, sizeof(data));
-                if (enqueued) {
-                    cards[i].textureState = STATE_INVALID;
-                } else {
-                    rsDebug("Couldn't send CMD_INVALIDATE_TEXTURE", 0);
-                }
-            }
-            // ask the host to remove the geometry
-            if (cards[i].geometryState == STATE_LOADED) {
-                data[0] = i;
-                bool enqueued = rsSendToClient(CMD_INVALIDATE_GEOMETRY, data, sizeof(data));
-                if (enqueued) {
-                    cards[i].geometryState = STATE_INVALID;
-                } else {
-                    rsDebug("Couldn't send CMD_INVALIDATE_GEOMETRY", 0);
-                }
-            }
-
-        }
-    }
-}
-
-// Places dots on geometry to visually inspect that objects can be seen by rays.
-// NOTE: the color of the dot is somewhat random, as it depends on texture of previously-rendered
-// card.
-static void renderWithRays()
-{
-    const float w = rsgGetWidth();
-    const float h = rsgGetHeight();
-    const int skip = 8;
-    color(1.0f, 0.0f, 0.0f, 1.0f);
-    for (int j = 0; j < (int) h; j+=skip) {
-        float posY = (float) j;
-        for (int i = 0; i < (int) w; i+=skip) {
-            float posX = (float) i;
-            Ray ray;
-            if (makeRayForPixelAt(&ray, posX, posY)) {
-                float bestTime = FLT_MAX;
-                if (intersectGeometry(&ray, &bestTime) != -1) {
-                    rsgDrawSpriteScreenspace(posX, h - posY - 1, 0.0f, 2.0f, 2.0f);
-                }
-            }
-        }
-    }
-}
-
-int root() {
-    int64_t currentTime = rsUptimeMillis();
-
-    rsgClearDepth(1.0f);
-    rsgBindProgramVertex(vertexProgram);
-    rsgBindProgramFragment(fragmentProgram);
-    rsgBindProgramStore(programStore);
-    rsgBindProgramRaster(rasterProgram);
-
-    updateAllocationVars();
-
-    if (!initialized) {
-        for (int i = 0; i < cardCount; i++)
-            cards[i].textureState = STATE_INVALID;
-        initialized = true;
-    }
-
-    if (false) { // for debugging - flash the screen so we know we're still rendering
-        static bool toggle;
-        if (toggle)
-            rsgClearColor(backgroundColor.x, backgroundColor.y, backgroundColor.z, 1.0);
-        else
-            rsgClearColor(1.0f, 0.0f, 0.0f, 1.f);
-        toggle = !toggle;
-    } else {
-        rsgClearColor(backgroundColor.x, backgroundColor.y, backgroundColor.z, 1.0);
-    }
-
-    updateCameraMatrix(rsgGetWidth(), rsgGetHeight());
-
-    const bool timeExpired = (currentTime - touchTime) > ANIMATION_SCALE_TIME;
-    if (timeExpired) {
-        //currentSelection = -1;
-    }
-    bool stillAnimating = updateNextPosition(currentTime) || !timeExpired;
-
-    cullCards();
-
-    updateCardResources();
-
-    drawCards();
-
-    if (debugPicking) {
-        renderWithRays();
-    }
-
-    //rsSendToClient(CMD_PING);
-
-    return stillAnimating ? 1 : 0;
-}
diff --git a/core/res/Android.mk b/core/res/Android.mk
index 9fafc59..22f4fdc 100644
--- a/core/res/Android.mk
+++ b/core/res/Android.mk
@@ -36,12 +36,12 @@
 # Include resources generated by system RenderScript files.
 framework_GENERATED_SOURCE_DIR := $(call intermediates-dir-for,JAVA_LIBRARIES,framework,,COMMON)/src
 framework_RenderScript_STAMP_FILE := $(framework_GENERATED_SOURCE_DIR)/RenderScript.stamp
-LOCAL_RESOURCE_DIR := $(framework_GENERATED_SOURCE_DIR)/renderscript/res $(LOCAL_PATH)/res
+#LOCAL_RESOURCE_DIR := $(framework_GENERATED_SOURCE_DIR)/renderscript/res $(LOCAL_PATH)/res
 
 include $(BUILD_PACKAGE)
 
 # Make sure the system .rs files get compiled before building the package-export.apk.
-$(resource_export_package): $(framework_RenderScript_STAMP_FILE)
+# $(resource_export_package): $(framework_RenderScript_STAMP_FILE)
 
 # define a global intermediate target that other module may depend on.
 .PHONY: framework-res-package-target
diff --git a/core/res/res/layout/recent_apps_activity.xml b/core/res/res/layout/recent_apps_activity.xml
index d962339..45a200e 100644
--- a/core/res/res/layout/recent_apps_activity.xml
+++ b/core/res/res/layout/recent_apps_activity.xml
@@ -45,11 +45,11 @@
         android:text="@android:string/no_recent_tasks"
         android:visibility="gone"/>
 
-    <com.android.internal.widget.CarouselView
+    <com.android.systemui.statusbar.RecentApplicationsCarouselView
         android:id="@+id/carousel"
         android:layout_width="match_parent"
         android:layout_height="0dip"
         android:layout_weight="1">
-    </com.android.internal.widget.CarouselView>
+    </com.android.systemui.statusbar.RecentApplicationsCarouselView>
 
 </LinearLayout>
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 910e84e..cfad939 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -3,10 +3,13 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_SRC_FILES := $(call all-subdir-java-files) \
+    ../../../ex/carousel/java/com/android/ex/carousel/carousel.rs
 
 LOCAL_JAVA_LIBRARIES := services
 
+LOCAL_STATIC_JAVA_LIBRARIES := android-common-carousel
+
 LOCAL_PACKAGE_NAME := SystemUI
 LOCAL_CERTIFICATE := platform
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RecentApplicationsActivity.java b/packages/SystemUI/src/com/android/systemui/statusbar/RecentApplicationsActivity.java
index a5ba7e2..6e5d241 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RecentApplicationsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RecentApplicationsActivity.java
@@ -17,14 +17,13 @@
 
 package com.android.systemui.statusbar;
 
+import com.android.ex.carousel.CarouselView;
+import com.android.ex.carousel.CarouselRS.CarouselCallback;
 import com.android.internal.R;
 
 import java.util.ArrayList;
 import java.util.List;
 
-import com.android.internal.widget.CarouselView;
-import com.android.internal.widget.CarouselRS.CarouselCallback;
-
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.IThumbnailReceiver;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RecentApplicationsCarouselView.java b/packages/SystemUI/src/com/android/systemui/statusbar/RecentApplicationsCarouselView.java
new file mode 100644
index 0000000..f5fcb11
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RecentApplicationsCarouselView.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import com.android.ex.carousel.CarouselView;
+import com.android.systemui.R;
+
+public class RecentApplicationsCarouselView extends CarouselView {
+
+    public RecentApplicationsCarouselView(Context context) {
+        this(context, null);
+    }
+
+    public RecentApplicationsCarouselView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public Info getRenderScriptInfo() {
+        return new Info(R.raw.carousel);
+    }
+
+}