start rewriting rollo so it's a little more parameterized.
diff --git a/res/raw/rollo.c b/res/raw/rollo.c
index 5ed562a..428ff78 100644
--- a/res/raw/rollo.c
+++ b/res/raw/rollo.c
@@ -3,10 +3,22 @@
 #pragma stateFragment(PF)
 #pragma stateFragmentStore(PFS)
 
-// Scratch buffer layout
-#define SCRATCH_FADE 0
-#define SCRATCH_ZOOM 1
-#define SCRATCH_ROT 2
+#define PI 3.14159f
+
+// Allocations ======
+#define ALLOC_PARAMS    0
+#define ALLOC_STATE     1
+#define ALLOC_SCRATCH   2
+#define ALLOC_ICON_IDS  3
+#define ALLOC_LABEL_IDS 4
+
+// Variables from java ======
+
+// Parameters ======
+#define PARAM_BUBBLE_WIDTH              0
+#define PARAM_BUBBLE_HEIGHT             1
+#define PARAM_BUBBLE_BITMAP_WIDTH       2
+#define PARAM_BUBBLE_BITMAP_HEIGHT      3
 
 //#define STATE_POS_X             0
 #define STATE_DONE              1
@@ -19,166 +31,124 @@
 #define STATE_COUNT             8
 #define STATE_TOUCH             9
 
+// Scratch variables ======
+#define SCRATCH_FADE 0
+#define SCRATCH_ZOOM 1
+#define SCRATCH_ROT 2
 
-float filter(float val, float target, float str)
+// Drawing constants, should be parameters ======
+#define SCREEN_WIDTH 480
+#define SCREEN_HEIGHT 854
+#define COLUMNS_PER_PAGE 4
+#define ROWS_PER_PAGE 4
+#define DIAMETER 8.0f
+
+#define PAGE_PADDING_TOP_PX 80
+#define CELL_PADDING_TOP_PX 5
+#define ICON_HEIGHT_PX 64
+#define ICON_LABEL_GUTTER_PX 5
+#define CELL_PADDING_BOTTOM_PX 5
+#define ROW_GUTTER_PX 10
+
+#define PAGE_PADDING_LEFT_PX 22
+#define CELL_WIDTH_PX 105
+#define ICON_WIDTH_PX 64
+#define COLUMN_GUTTER_PX 5
+#define LABEL_WIDTH_PX 105
+
+int
+count_pages(int iconCount)
 {
-    float delta = (target - val);
-    return val + delta * str;
+    int iconsPerPage = COLUMNS_PER_PAGE * ROWS_PER_PAGE;
+    int pages = iconCount / iconsPerPage;
+    if (pages*iconsPerPage != iconCount) {
+        iconCount++;
+    }
+    return iconCount;
 }
 
-int main(void* con, int ft, int launchID)
+int
+main(void* con, int ft, int launchID)
 {
-    int rowCount;
-    int row;
-    int col;
-    int imageID;
-    int done = loadI32(0, STATE_DONE);
-    int selectedID = loadI32(0, STATE_SELECTION);
-
-    float f = loadF(2, 0);
-
+    // Clear to transparent
     pfClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-    if (done) {
-        if (f > 0.02f) {
-            //f = f - 0.02f;
-            //storeF(2, 0, f);
-        }
-    } else {
-        if (f < 0.8f) {
-            f = f + 0.02f;
-            storeF(2, 0, f);
-        }
-    }
 
-    float touchCut = 1.f;
-    if (loadI32(0, STATE_TOUCH)) {
-        touchCut = 4.f;
-    }
+    // icons & labels
+    int iconCount = loadI32(ALLOC_STATE, STATE_COUNT);
+    int pageCount = count_pages(iconCount);
+
+    float densityScale = 2.0f / SCREEN_WIDTH;
+    float screenTop = SCREEN_HEIGHT/(float)SCREEN_WIDTH; // == (SCREEN_HEIGHT/2)*densityScale;
+
+    float pagePaddingTop = screenTop - (PAGE_PADDING_TOP_PX * densityScale);
+    float pageGutterY = ROW_GUTTER_PX * densityScale;
+    float cellHeight = (CELL_PADDING_TOP_PX + ICON_HEIGHT_PX + ICON_LABEL_GUTTER_PX
+            + loadI32(ALLOC_PARAMS, PARAM_BUBBLE_HEIGHT)
+            + CELL_PADDING_BOTTOM_PX + ROW_GUTTER_PX) * densityScale;
+    float cellPaddingTop = CELL_PADDING_TOP_PX * densityScale;
+    float iconHeight = ICON_HEIGHT_PX * densityScale;
+    float iconLabelGutter = ICON_LABEL_GUTTER_PX * densityScale;
+
+    float pagePaddingLeft = PAGE_PADDING_LEFT_PX * densityScale;
+    float cellWidth = CELL_WIDTH_PX * densityScale;
+    float iconWidth = ICON_WIDTH_PX * densityScale;
+    float columnGutter = COLUMN_GUTTER_PX * densityScale;
+
+    float pageLeft = -1;
+    int icon = 0;
+    int page;
+
+    float labelWidth = loadI32(ALLOC_PARAMS, PARAM_BUBBLE_WIDTH) * densityScale;
+    float labelTextureWidth = loadI32(ALLOC_PARAMS, PARAM_BUBBLE_BITMAP_WIDTH) * densityScale;
+    float labelTextureHeight = loadI32(ALLOC_PARAMS, PARAM_BUBBLE_BITMAP_HEIGHT) * densityScale;
+
+    int scrollXPx = 100;
+    pageLeft -= scrollXPx * densityScale;
 
 
-    float targetZoom = ((float)loadI32(0, STATE_ZOOM)) / 1000.f;
-    float zoom = filter(loadF(2, SCRATCH_ZOOM), targetZoom, 0.15 * touchCut);
-    storeF(2, SCRATCH_ZOOM, zoom);
+    for (page=0; page<pageCount; page++) {
+        // Bug makes 1.0f alpha fail.
+        color(1.0f, 1.0f, 1.0f, 0.99f);
+        
+        float cellTop = pagePaddingTop;
+        int row;
+        for (row=0; row<ROWS_PER_PAGE && icon<iconCount; row++) {
+            float s = pageLeft; // distance along the linear strip of icons in normalized coords
+            s += pagePaddingLeft;
+            int col;
+            for (col=0; col<COLUMNS_PER_PAGE && icon<iconCount; col++) {
+                // icon
+                float iconLeft = s + ((cellWidth-iconWidth)/2.0f);
+                float iconRight = iconLeft + iconWidth;
+                float iconTop = cellTop - cellPaddingTop;
+                float iconBottom = iconTop - iconHeight;
 
-    float targetRot = loadI32(0, STATE_FIRST_VISIBLE) / 180.0f * 3.14f;
-    targetRot = targetRot * 0.80f - .12f;
-    float drawRot = filter(loadF(2, SCRATCH_ROT), targetRot, 0.1f * touchCut);
-    storeF(2, SCRATCH_ROT, drawRot);
+                bindProgramFragment(NAMED_PF);
+                bindProgramFragmentStore(NAMED_PFS);
 
-    float diam = 8.f;
-    float scale = 1.0f / zoom;
+                bindTexture(NAMED_PF, 0, loadI32(ALLOC_ICON_IDS, icon));
+                drawRect(iconLeft, iconTop, iconRight, iconBottom, 0.0f);
 
-    // Bug makes 1.0f alpha fail.
-    color(1.0f, 1.0f, 1.0f, 0.99f);
+                // label
+                float labelLeft = s + ((cellWidth-labelWidth)/2.0f);
+                float labelTop = iconBottom - iconLabelGutter;
 
-    float rot = drawRot * scale;
-    float rotStep = 16.0f / 180.0f * 3.14f * scale;
-    rowCount = 4;
-    int index = 0;
-    int iconCount = loadI32(0, STATE_COUNT);
-    while (iconCount) {
-        float tmpSin = sinf(rot);
-        float tmpCos = cosf(rot);
-            //debugF("rot", rot);
+                bindProgramFragment(NAMED_PFText);
+                bindProgramFragmentStore(NAMED_PFSText);
 
-        float tx1 = tmpSin * diam - (tmpCos * scale * 0.9f);
-        float tx2 = tx1 + (tmpCos * scale * 1.8f);
-        float tz1 = tmpCos * diam + (tmpSin * scale * 0.9f);
-        float tz2 = tz1 - (tmpSin * scale * 1.8f);
+                bindTexture(NAMED_PFText, 0, loadI32(ALLOC_LABEL_IDS, icon));
+                drawRect(labelLeft, labelTop, labelLeft+labelTextureWidth,
+                        labelTop-labelTextureHeight, 0.0f);
 
-        int y;
-        for (y = rowCount -1; (y >= 0) && iconCount; y--) {
-            float ty1 = ((y * 3.1f) - 5.f) * scale;
-            float ty2 = ty1 + scale * 1.8f;
-            bindTexture(NAMED_PF, 0, loadI32(1, index));
-            drawQuad(tx1, ty1, tz1,
-                     tx2, ty1, tz2,
-                     tx2, ty2, tz2,
-                     tx1, ty2, tz1);
-
-            iconCount--;
-            index++;
-        }
-        rot = rot + rotStep;
-    }
-
-    if ((zoom < 1.1f) && (zoom > 0.9f)) {
-        bindProgramVertex(NAMED_PVOrtho);
-        bindProgramFragment(NAMED_PFText);
-        bindProgramFragmentStore(NAMED_PFSText);
-
-        rot = drawRot * scale;
-        index = 0;
-        iconCount = loadI32(0, STATE_COUNT);
-        while (iconCount) {
-            int y;
-
-            float tx = 240.f + floorf(sinf(rot) * 430.f) - 64.f + 16.f;
-
-            float alpha = 2.4f - (fabsf(tx - 240.f + 48.f) / 76.f);
-            if (alpha > 0.99f) {
-                alpha = 0.99f;
+                s += cellWidth + columnGutter;
+                icon++;
             }
-            alpha = alpha * (1.f - (fabsf(zoom - 1.f) * 10.f));
-
-            tx = tx + 0.25f;
-
-            for (y = rowCount -1; (y >= 0) && iconCount; y--) {
-
-                if (alpha > 0) {
-                    color(1.0f, 1.0f, 1.0f, alpha);
-
-                    float ty = 654.f - y * 150.f;
-
-                    ty = ty + 0.25f;
-
-                    bindTexture(NAMED_PFText, 0, loadI32(3, index));
-                    drawRect(tx, ty, tx + 128.f, ty + 64.f, 0.5f);
-                }
-                iconCount--;
-                index++;
-            }
-            rot = rot + rotStep;
+            cellTop -= cellHeight;
         }
-
-
-        bindProgramVertex(NAMED_PV);
-        bindProgramFragment(NAMED_PF);
-        bindProgramFragmentStore(NAMED_PFS);
+        pageLeft += 2.0f;
     }
 
-    // Draw the selected icon
-    color(1.0f, 1.0f, 1.0f, 0.9f);
-    rot = drawRot * scale;
-    index = 0;
-    iconCount = loadI32(0, STATE_COUNT);
-    while (iconCount) {
-        int y;
-        for (y = rowCount -1; (y >= 0) && iconCount; y--) {
-            if (index == selectedID) {
-
-                float tmpSin = sinf(rot) * scale;
-                float tmpCos = cosf(rot) * scale;
-                float tx1 = tmpSin * diam * 0.9f - tmpCos * 2.f;
-                float tx2 = tx1 + (tmpCos * 4.f);
-                float tz1 = tmpCos * diam * 0.9f + tmpSin * 2.f;
-                float tz2 = tz1 - (tmpSin * 4.f);
-
-                float ty1 = ((y * 3.1f) - 4.5f) * scale;
-                float ty2 = ty1 + scale * 4.f;
-                bindTexture(NAMED_PF, 0, loadI32(1, index));
-                drawQuad(tx1, ty1, tz1,
-                         tx2, ty1, tz2,
-                         tx2, ty2, tz2,
-                         tx1, ty2, tz1);
-            }
-            iconCount--;
-            index++;
-        }
-        rot = rot + rotStep;
-    }
-
-    return 1;
+    return 0;
 }
 
 
diff --git a/rollo-old.c b/rollo-old.c
new file mode 100644
index 0000000..5ed562a
--- /dev/null
+++ b/rollo-old.c
@@ -0,0 +1,184 @@
+#pragma version(1)
+#pragma stateVertex(PV)
+#pragma stateFragment(PF)
+#pragma stateFragmentStore(PFS)
+
+// Scratch buffer layout
+#define SCRATCH_FADE 0
+#define SCRATCH_ZOOM 1
+#define SCRATCH_ROT 2
+
+//#define STATE_POS_X             0
+#define STATE_DONE              1
+//#define STATE_PRESSURE          2
+#define STATE_ZOOM              3
+//#define STATE_WARP              4
+#define STATE_ORIENTATION       5
+#define STATE_SELECTION         6
+#define STATE_FIRST_VISIBLE     7
+#define STATE_COUNT             8
+#define STATE_TOUCH             9
+
+
+float filter(float val, float target, float str)
+{
+    float delta = (target - val);
+    return val + delta * str;
+}
+
+int main(void* con, int ft, int launchID)
+{
+    int rowCount;
+    int row;
+    int col;
+    int imageID;
+    int done = loadI32(0, STATE_DONE);
+    int selectedID = loadI32(0, STATE_SELECTION);
+
+    float f = loadF(2, 0);
+
+    pfClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+    if (done) {
+        if (f > 0.02f) {
+            //f = f - 0.02f;
+            //storeF(2, 0, f);
+        }
+    } else {
+        if (f < 0.8f) {
+            f = f + 0.02f;
+            storeF(2, 0, f);
+        }
+    }
+
+    float touchCut = 1.f;
+    if (loadI32(0, STATE_TOUCH)) {
+        touchCut = 4.f;
+    }
+
+
+    float targetZoom = ((float)loadI32(0, STATE_ZOOM)) / 1000.f;
+    float zoom = filter(loadF(2, SCRATCH_ZOOM), targetZoom, 0.15 * touchCut);
+    storeF(2, SCRATCH_ZOOM, zoom);
+
+    float targetRot = loadI32(0, STATE_FIRST_VISIBLE) / 180.0f * 3.14f;
+    targetRot = targetRot * 0.80f - .12f;
+    float drawRot = filter(loadF(2, SCRATCH_ROT), targetRot, 0.1f * touchCut);
+    storeF(2, SCRATCH_ROT, drawRot);
+
+    float diam = 8.f;
+    float scale = 1.0f / zoom;
+
+    // Bug makes 1.0f alpha fail.
+    color(1.0f, 1.0f, 1.0f, 0.99f);
+
+    float rot = drawRot * scale;
+    float rotStep = 16.0f / 180.0f * 3.14f * scale;
+    rowCount = 4;
+    int index = 0;
+    int iconCount = loadI32(0, STATE_COUNT);
+    while (iconCount) {
+        float tmpSin = sinf(rot);
+        float tmpCos = cosf(rot);
+            //debugF("rot", rot);
+
+        float tx1 = tmpSin * diam - (tmpCos * scale * 0.9f);
+        float tx2 = tx1 + (tmpCos * scale * 1.8f);
+        float tz1 = tmpCos * diam + (tmpSin * scale * 0.9f);
+        float tz2 = tz1 - (tmpSin * scale * 1.8f);
+
+        int y;
+        for (y = rowCount -1; (y >= 0) && iconCount; y--) {
+            float ty1 = ((y * 3.1f) - 5.f) * scale;
+            float ty2 = ty1 + scale * 1.8f;
+            bindTexture(NAMED_PF, 0, loadI32(1, index));
+            drawQuad(tx1, ty1, tz1,
+                     tx2, ty1, tz2,
+                     tx2, ty2, tz2,
+                     tx1, ty2, tz1);
+
+            iconCount--;
+            index++;
+        }
+        rot = rot + rotStep;
+    }
+
+    if ((zoom < 1.1f) && (zoom > 0.9f)) {
+        bindProgramVertex(NAMED_PVOrtho);
+        bindProgramFragment(NAMED_PFText);
+        bindProgramFragmentStore(NAMED_PFSText);
+
+        rot = drawRot * scale;
+        index = 0;
+        iconCount = loadI32(0, STATE_COUNT);
+        while (iconCount) {
+            int y;
+
+            float tx = 240.f + floorf(sinf(rot) * 430.f) - 64.f + 16.f;
+
+            float alpha = 2.4f - (fabsf(tx - 240.f + 48.f) / 76.f);
+            if (alpha > 0.99f) {
+                alpha = 0.99f;
+            }
+            alpha = alpha * (1.f - (fabsf(zoom - 1.f) * 10.f));
+
+            tx = tx + 0.25f;
+
+            for (y = rowCount -1; (y >= 0) && iconCount; y--) {
+
+                if (alpha > 0) {
+                    color(1.0f, 1.0f, 1.0f, alpha);
+
+                    float ty = 654.f - y * 150.f;
+
+                    ty = ty + 0.25f;
+
+                    bindTexture(NAMED_PFText, 0, loadI32(3, index));
+                    drawRect(tx, ty, tx + 128.f, ty + 64.f, 0.5f);
+                }
+                iconCount--;
+                index++;
+            }
+            rot = rot + rotStep;
+        }
+
+
+        bindProgramVertex(NAMED_PV);
+        bindProgramFragment(NAMED_PF);
+        bindProgramFragmentStore(NAMED_PFS);
+    }
+
+    // Draw the selected icon
+    color(1.0f, 1.0f, 1.0f, 0.9f);
+    rot = drawRot * scale;
+    index = 0;
+    iconCount = loadI32(0, STATE_COUNT);
+    while (iconCount) {
+        int y;
+        for (y = rowCount -1; (y >= 0) && iconCount; y--) {
+            if (index == selectedID) {
+
+                float tmpSin = sinf(rot) * scale;
+                float tmpCos = cosf(rot) * scale;
+                float tx1 = tmpSin * diam * 0.9f - tmpCos * 2.f;
+                float tx2 = tx1 + (tmpCos * 4.f);
+                float tz1 = tmpCos * diam * 0.9f + tmpSin * 2.f;
+                float tz2 = tz1 - (tmpSin * 4.f);
+
+                float ty1 = ((y * 3.1f) - 4.5f) * scale;
+                float ty2 = ty1 + scale * 4.f;
+                bindTexture(NAMED_PF, 0, loadI32(1, index));
+                drawQuad(tx1, ty1, tz1,
+                         tx2, ty1, tz2,
+                         tx2, ty2, tz2,
+                         tx1, ty2, tz1);
+            }
+            iconCount--;
+            index++;
+        }
+        rot = rot + rotStep;
+    }
+
+    return 1;
+}
+
+
diff --git a/src/com/android/launcher2/AllAppsView.java b/src/com/android/launcher2/AllAppsView.java
index 7bf0c7c..0a522ae 100644
--- a/src/com/android/launcher2/AllAppsView.java
+++ b/src/com/android/launcher2/AllAppsView.java
@@ -243,6 +243,12 @@
         public static final int STATE_COUNT = 8;
         public static final int STATE_TOUCH = 9;
 
+        static final int ALLOC_PARAMS = 0;
+        static final int ALLOC_STATE = 1;
+        static final int ALLOC_SCRATCH = 2;
+        static final int ALLOC_ICON_IDS = 3;
+        static final int ALLOC_LABEL_IDS = 4;
+
         public RolloRS() {
         }
 
@@ -291,6 +297,7 @@
         private Sampler mSamplerText;
         private ProgramStore mPSBackground;
         private ProgramStore mPSText;
+        private ProgramFragment mPFDebug;
         private ProgramFragment mPFImages;
         private ProgramFragment mPFText;
         private ProgramVertex mPV;
@@ -312,6 +319,18 @@
         private int[] mAllocScratchBuf;
         private Allocation mAllocScratch;
 
+        Params mParams;
+
+        class Params extends IntAllocation {
+            Params(RenderScript rs) {
+                super(rs);
+            }
+            @AllocationIndex(0) public int bubbleWidth;
+            @AllocationIndex(1) public int bubbleHeight;
+            @AllocationIndex(2) public int bubbleBitmapWidth;
+            @AllocationIndex(3) public int bubbleBitmapHeight;
+        }
+
         private void initNamed() {
             Sampler.Builder sb = new Sampler.Builder(mRS);
             sb.setMin(Sampler.Value.LINEAR);//_MIP_LINEAR);
@@ -324,6 +343,9 @@
             sb.setMag(Sampler.Value.NEAREST);
             mSamplerText = sb.create();
 
+            ProgramFragment.Builder dbg = new ProgramFragment.Builder(mRS, null, null);
+            mPFDebug = dbg.create();
+            mPFDebug.setName("PFDebug");
 
             ProgramFragment.Builder bf = new ProgramFragment.Builder(mRS, null, null);
             bf.setTexEnable(true, 0);
@@ -380,6 +402,8 @@
         }
         
         private void initIcons(int count) {
+            mParams = new Params(mRS);
+
             mIcons = new Allocation[count];
             mAllocIconIDBuf = new int[count];
             mAllocIconID = Allocation.createSized(mRS,
@@ -394,6 +418,12 @@
 
             final Utilities.BubbleText bubble = new Utilities.BubbleText(getContext());
 
+            mParams.bubbleWidth = bubble.getBubbleWidth();
+            mParams.bubbleHeight = bubble.getMaxBubbleHeight();
+            mParams.bubbleBitmapWidth = bubble.getBitmapWidth();
+            mParams.bubbleBitmapHeight = bubble.getBitmapHeight();
+            mParams.save();
+
             for (int i=0; i<count; i++) {
                 mIcons[i] = Allocation.createFromBitmapResource(
                         mRS, mRes, R.raw.maps, ie8888, true);
@@ -430,10 +460,12 @@
             mAllocStateBuf = new int[] {0, 0, 0, 8, 0, 0, -1, 0, mAllocIconIDBuf.length, 0, 0};
             mAllocState = Allocation.createSized(mRS,
                 Element.USER_I32, mAllocStateBuf.length);
-            mScript.bindAllocation(mAllocState, 0);
-            mScript.bindAllocation(mAllocIconID, 1);
-            mScript.bindAllocation(mAllocScratch, 2);
-            mScript.bindAllocation(mAllocLabelID, 3);
+
+            mScript.bindAllocation(mParams.getAllocation(), ALLOC_PARAMS);
+            mScript.bindAllocation(mAllocState, ALLOC_STATE);
+            mScript.bindAllocation(mAllocIconID, ALLOC_ICON_IDS);
+            mScript.bindAllocation(mAllocScratch, ALLOC_SCRATCH);
+            mScript.bindAllocation(mAllocLabelID, ALLOC_LABEL_IDS);
             setPosition(0);
             setZoom(1);
 
diff --git a/src/com/android/launcher2/AllocationIndex.java b/src/com/android/launcher2/AllocationIndex.java
new file mode 100644
index 0000000..0202db5
--- /dev/null
+++ b/src/com/android/launcher2/AllocationIndex.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2009 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.launcher2;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Annotate fields of a subclass of {@link IntAllocaiton} or
+ * FloatAllocation with this, and the save() method on those
+ * those classes will find the field an save it.
+ * <p>
+ * TODO: This would be even better if the allocations were
+ * named, and renderscript automatically added them into to
+ * the renderscript namespace.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AllocationIndex {
+    /**
+     * The index in the allocation to use inside renderscript.
+     */
+    int value();
+}
diff --git a/src/com/android/launcher2/IntAllocation.java b/src/com/android/launcher2/IntAllocation.java
new file mode 100644
index 0000000..3d96c5e
--- /dev/null
+++ b/src/com/android/launcher2/IntAllocation.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2009 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.launcher2;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.RenderScript;
+
+import java.lang.reflect.Field;
+
+public class IntAllocation {
+    private RenderScript mRS;
+    private int[] mBuffer;
+    private Allocation mAlloc;
+
+    public IntAllocation(RenderScript rs) {
+        mRS = rs;
+    }
+
+    public void save() {
+        Field[] fields = this.getClass().getFields();
+        if (mBuffer == null) {
+            int maxIndex = 0;
+            for (Field f: fields) {
+                AllocationIndex index = f.getAnnotation(AllocationIndex.class);
+                if (index != null) {
+                    int value = index.value();
+                    if (value > maxIndex) {
+                        maxIndex = value;
+                    }
+                }
+            }
+            mBuffer = new int[maxIndex+1];
+            mAlloc = Allocation.createSized(mRS, Element.USER_I32, mBuffer.length);
+        }
+        int[] buf = mBuffer;
+        for (Field f: fields) {
+            AllocationIndex index = f.getAnnotation(AllocationIndex.class);
+            if (index != null) {
+                try {
+                    buf[index.value()] = f.getInt(this);
+                } catch (IllegalAccessException ex) {
+                    throw new RuntimeException(ex);
+                }
+            }
+        }
+        mAlloc.data(buf);
+    }
+
+    Allocation getAllocation() {
+        return mAlloc;
+    }
+}
diff --git a/src/com/android/launcher2/Utilities.java b/src/com/android/launcher2/Utilities.java
index c710615..9e715d1 100644
--- a/src/com/android/launcher2/Utilities.java
+++ b/src/com/android/launcher2/Utilities.java
@@ -234,7 +234,7 @@
             final float paddingRight = 5.0f * scale;
             final float cellWidth = resources.getDimension(R.dimen.workspace_cell_width);
             final float bubbleWidth = cellWidth - paddingLeft - paddingRight;
-            mBubblePadding = 5.0f * scale;
+            mBubblePadding = 3.0f * scale;
 
             RectF bubbleRect = mBubbleRect;
             bubbleRect.left = 0;
@@ -245,27 +245,29 @@
             mTextWidth = bubbleWidth - mBubblePadding - mBubblePadding;
 
             Paint rectPaint = mRectPaint = new Paint();
-            rectPaint.setColor(0xff000000);
+            rectPaint.setColor(0xaa000000);
+            rectPaint.setAntiAlias(true);
 
             TextPaint textPaint = mTextPaint = new TextPaint();
             textPaint.setTypeface(Typeface.DEFAULT_BOLD);
             textPaint.setTextSize(20);
             textPaint.setColor(0xffffffff);
+            textPaint.setAntiAlias(true);
 
             float ascent = -textPaint.ascent();
             float descent = textPaint.descent();
-            float leading = (ascent+descent) * 0.1f;
+            float leading = 0.0f;//(ascent+descent) * 0.1f;
             mLeading = (int)(leading + 0.5f);
             mFirstLineY = (int)(leading + ascent + 0.5f);
             mLineHeight = (int)(leading + ascent + descent + 0.5f);
 
             roundToPow2(64);
             mBitmapWidth = roundToPow2((int)(mBubbleRect.width() + 0.5f));
-            mBitmapHeight = roundToPow2((int)((MAX_LINES * mLineHeight) + mLeading + 0.5f));
+            mBitmapHeight = roundToPow2((int)((MAX_LINES * mLineHeight) + leading + 0.5f));
 
             Log.d(Launcher.LOG_TAG, "mBitmapWidth=" + mBitmapWidth + " mBitmapHeight="
                     + mBitmapHeight + " w=" + ((int)(mBubbleRect.width() + 0.5f))
-                    + " h=" + ((int)((MAX_LINES * mLineHeight) + mLeading + 0.5f)));
+                    + " h=" + ((int)((MAX_LINES * mLineHeight) + leading + 0.5f)));
         }
 
         /** You own the bitmap after this and you must call recycle on it. */
@@ -281,9 +283,8 @@
             }
             if (lineCount > 0) {
                 RectF bubbleRect = mBubbleRect;
-                bubbleRect.bottom = (int)((lineCount * mLineHeight) + mLeading + mLeading + 0.0f);
+                bubbleRect.bottom = height(lineCount);
                 c.drawRoundRect(bubbleRect, mCornerRadius, mCornerRadius, mRectPaint);
-                Log.d(Launcher.LOG_TAG, "bubbleRect=" + bubbleRect);
             }
             for (int i=0; i<lineCount; i++) {
                 int x = (int)((mBubbleRect.width() - layout.getLineMax(i)) / 2.0f);
@@ -294,6 +295,26 @@
 
             return b;
         }
+
+        private int height(int lineCount) {
+            return (int)((lineCount * mLineHeight) + mLeading + mLeading + 0.0f);
+        }
+
+        int getBubbleWidth() {
+            return (int)(mBubbleRect.width() + 0.5f);
+        }
+
+        int getMaxBubbleHeight() {
+            return height(MAX_LINES);
+        }
+
+        int getBitmapWidth() {
+            return mBitmapWidth;
+        }
+
+        int getBitmapHeight() {
+            return mBitmapHeight;
+        }
     }
 
     /** Only works for positive numbers. */