fling
diff --git a/res/raw/rollo.c b/res/raw/rollo.c
index 7648270..bae390f 100644
--- a/res/raw/rollo.c
+++ b/res/raw/rollo.c
@@ -5,13 +5,6 @@
#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 ======
@@ -23,11 +16,13 @@
// State ======
#define STATE_ICON_COUNT 0
#define STATE_SCROLL_X 1
+#define STATE_FLING_TIME 2
+#define STATE_FLING_VELOCITY_X 3
+#define STATE_ADJUSTED_DECELERATION 4
+#define STATE_CURRENT_SCROLL_X 5 /* with fling offset applied */
// Scratch variables ======
-#define SCRATCH_FADE 0
-#define SCRATCH_ZOOM 1
-#define SCRATCH_ROT 2
+#define SCRATCH_ADJUSTED_DECELERATION 0
// Drawing constants, should be parameters ======
#define SCREEN_WIDTH 480
@@ -49,19 +44,31 @@
#define COLUMN_GUTTER_PX 5
#define LABEL_WIDTH_PX 105
+
int
count_pages(int iconCount)
{
int iconsPerPage = COLUMNS_PER_PAGE * ROWS_PER_PAGE;
int pages = iconCount / iconsPerPage;
if (pages*iconsPerPage != iconCount) {
- iconCount++;
+ pages++;
}
- return iconCount;
+ return pages;
+}
+
+int current_page(float scrollXPx)
+{
+ return -scrollXPx / SCREEN_WIDTH;
+}
+
+float
+modf(float x, float y)
+{
+ return x-(y*floorf(x/y));
}
int
-main(void* con, int ft, int launchID)
+main(int launchID)
{
// Clear to transparent
pfClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -91,25 +98,104 @@
float labelTextureWidth = loadI32(ALLOC_PARAMS, PARAM_BUBBLE_BITMAP_WIDTH) * densityScale;
float labelTextureHeight = loadI32(ALLOC_PARAMS, PARAM_BUBBLE_BITMAP_HEIGHT) * densityScale;
- float pageLeft = -1;
- int icon = 0;
+ float scrollXPx = loadI32(ALLOC_STATE, STATE_SCROLL_X);
+ float maxScrollX = -(pageCount-1) * SCREEN_WIDTH;
+ int done = 0;
+
+ // If we've been given a velocity, start a fling
+ float flingVelocityPxMs = loadI32(ALLOC_STATE, STATE_FLING_VELOCITY_X);
+ if (flingVelocityPxMs != 0) {
+ // how many screens will this velocity do? TODO: use long
+ // G * ppi * friction // why G? // friction = 0.015
+ float deceleration = loadF(ALLOC_STATE, STATE_ADJUSTED_DECELERATION);
+ if (deceleration == 0) {
+ // On the first frame, calculate which animation we're going to do. If it's
+ // going to end up less than halfway into a page, we'll bounce back the previous
+ // page. Otherwise, we'll adjust the deceleration so it just makes it to the
+ // page boundary.
+ if (flingVelocityPxMs > 0) {
+ deceleration = -1000;
+ } else {
+ deceleration = 1000;
+ }
+ // v' = v + at --> t = -v / a
+ // x' = x + vt + .5 a t^2 --> x' = x + (-v^2/a) + (v^2/2a)
+ float endPos = scrollXPx + (-(flingVelocityPxMs*flingVelocityPxMs)/deceleration)
+ + ((flingVelocityPxMs*flingVelocityPxMs)/(2.0f*deceleration));
+
+ if (endPos > 0) {
+ endPos = 0;
+ }
+ if (endPos < maxScrollX) {
+ endPos = maxScrollX;
+ }
+ float screenWidthFloat = SCREEN_WIDTH;
+ float scrollOnPage = modf(endPos, screenWidthFloat);
+ }
+
+ // adjust the deceleration so we always hit a page boundary
+
+ int flingTime = loadI32(ALLOC_STATE, STATE_FLING_TIME);
+ int now = uptimeMillis();
+ float elapsedTime = (now - flingTime) / 1000.0f;
+ int animEndTime = -flingVelocityPxMs / deceleration;
+
+ done = elapsedTime >= animEndTime;
+ if (done) {
+ // clamp the time to the end value
+ elapsedTime = animEndTime;
+ }
+
+ float tension = 2.0f;
+ float interp = elapsedTime * elapsedTime * ((tension + 1) * elapsedTime + tension) + 1.0f; // normalized 0..1
+
+ int flingOffsetPx = (flingVelocityPxMs * elapsedTime)
+ + (deceleration * elapsedTime * elapsedTime / 2.0f);
+ scrollXPx += flingOffsetPx;
+
+ }
+
+ if (scrollXPx > 0) {
+ scrollXPx = 0;
+ }
+ if (scrollXPx < maxScrollX) {
+ scrollXPx = maxScrollX;
+ }
+
+ storeI32(ALLOC_STATE, STATE_CURRENT_SCROLL_X, scrollXPx);
+ if (done) {
+ storeI32(ALLOC_STATE, STATE_SCROLL_X, scrollXPx);
+ storeI32(ALLOC_STATE, STATE_FLING_VELOCITY_X, 0);
+ storeF(ALLOC_STATE, STATE_ADJUSTED_DECELERATION, 0);
+ }
+
+ // don't draw everything, just the page before and after what we're viewing.
+ int currentPage = current_page(scrollXPx);
+ float screenWidth = SCREEN_WIDTH * densityScale;
+
+ float pageLeft = -1 + ((currentPage-1)*screenWidth);
+ int iconsPerPage = COLUMNS_PER_PAGE * ROWS_PER_PAGE;
+ int icon = (currentPage-1) * iconsPerPage;
+ if (icon < 0) {
+ icon = 0;
+ }
int page;
-
- int scrollXPx = loadI32(ALLOC_STATE, STATE_SCROLL_X);
- debugI32("scrollXPx", scrollXPx);
+ int lastIcon = icon + (iconsPerPage*3);
+ if (lastIcon >= iconCount) {
+ lastIcon = iconCount-1;
+ }
pageLeft += scrollXPx * densityScale;
-
- for (page=0; page<pageCount; page++) {
+ for (page=currentPage-1; page<pageCount && page<=(currentPage+1); 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++) {
+ for (row=0; row<ROWS_PER_PAGE && icon<=lastIcon; 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++) {
+ for (col=0; col<COLUMNS_PER_PAGE && icon<=lastIcon; col++) {
// icon
float iconLeft = s + ((cellWidth-iconWidth)/2.0f);
float iconRight = iconLeft + iconWidth;
@@ -141,7 +227,6 @@
pageLeft += 2.0f;
}
- return 1;
+ return !done;
}
-
diff --git a/src/com/android/launcher2/AllAppsView.java b/src/com/android/launcher2/AllAppsView.java
index 78e3f1a..662a9dc 100644
--- a/src/com/android/launcher2/AllAppsView.java
+++ b/src/com/android/launcher2/AllAppsView.java
@@ -44,13 +44,16 @@
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
+import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.ViewConfiguration;
import android.graphics.PixelFormat;
@@ -58,12 +61,16 @@
private RenderScript mRS;
private RolloRS mRollo;
+ private ViewConfiguration mConfig;
+ private VelocityTracker mVelocity;
+ private int mLastScrollX;
private int mLastMotionX;
public AllAppsView(Context context) {
super(context);
setFocusable(true);
getHolder().setFormat(PixelFormat.TRANSLUCENT);
+ mConfig = ViewConfiguration.get(context);
}
public AllAppsView(Context context, AttributeSet attrs) {
@@ -98,18 +105,34 @@
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastMotionX = x;
+ mRollo.mState.read();
+ mRollo.mState.scrollX = mLastScrollX = mRollo.mState.currentScrollX;
+ mRollo.mState.flingVelocityX = 0;
+ mRollo.mState.adjustedDeceleration = 0;
+ mRollo.mState.save();
+ mVelocity = VelocityTracker.obtain();
+ mVelocity.addMovement(ev);
break;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_OUTSIDE:
deltaX = x - mLastMotionX;
- mRollo.mState.scrollX += deltaX;
- Log.d(Launcher.LOG_TAG, "updated scrollX=" + mRollo.mState.scrollX);
+ mVelocity.addMovement(ev);
+ mRollo.mState.currentScrollX = mLastScrollX;
+ mLastScrollX += deltaX;
+ mRollo.mState.scrollX = mLastScrollX;
mRollo.mState.save();
mLastMotionX = x;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
+ mVelocity.computeCurrentVelocity(1000 /* px/sec */,
+ mConfig.getScaledMaximumFlingVelocity());
+ mRollo.mState.flingTimeMs = (int)SystemClock.uptimeMillis(); // TODO: use long
+ mRollo.mState.flingVelocityX = (int)mVelocity.getXVelocity();
+ mRollo.mState.save();
mLastMotionX = -10000;
+ mVelocity.recycle();
+ mVelocity = null;
break;
}
return true;
@@ -131,11 +154,6 @@
public class RolloRS {
// Allocations ======
- 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;
private int mWidth;
private int mHeight;
@@ -168,6 +186,14 @@
Params mParams;
State mState;
+ class Defines {
+ public static final int ALLOC_PARAMS = 0;
+ public static final int ALLOC_STATE = 1;
+ public static final int ALLOC_SCRATCH = 2;
+ public static final int ALLOC_ICON_IDS = 3;
+ public static final int ALLOC_LABEL_IDS = 4;
+ }
+
class Params extends IntAllocation {
Params(RenderScript rs) {
super(rs);
@@ -184,6 +210,10 @@
}
@AllocationIndex(0) public int iconCount;
@AllocationIndex(1) public int scrollX;
+ @AllocationIndex(2) public int flingTimeMs;
+ @AllocationIndex(3) public int flingVelocityX;
+ @AllocationIndex(4) public int adjustedDeceleration;
+ @AllocationIndex(5) public int currentScrollX;
}
public RolloRS() {
@@ -261,15 +291,14 @@
mRS.contextBindProgramVertex(mPV);
mAllocScratchBuf = new int[32];
- mAllocScratch = Allocation.createSized(mRS,
- Element.USER_I32, mAllocScratchBuf.length);
+ mAllocScratch = Allocation.createSized(mRS, Element.USER_I32, mAllocScratchBuf.length);
mAllocScratch.data(mAllocScratchBuf);
Log.e("rs", "Done loading named");
}
private void initData() {
- final int count = 29;
+ final int count = 100;
mParams = new Params(mRS);
mState = new State(mRS);
@@ -324,14 +353,15 @@
ScriptC.Builder sb = new ScriptC.Builder(mRS);
sb.setScript(mRes, R.raw.rollo);
sb.setRoot(true);
+ sb.addDefines(Defines.class);
mScript = sb.create();
mScript.setClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- mScript.bindAllocation(mParams.getAllocation(), ALLOC_PARAMS);
- mScript.bindAllocation(mState.getAllocation(), ALLOC_STATE);
- mScript.bindAllocation(mAllocIconID, ALLOC_ICON_IDS);
- mScript.bindAllocation(mAllocScratch, ALLOC_SCRATCH);
- mScript.bindAllocation(mAllocLabelID, ALLOC_LABEL_IDS);
+ mScript.bindAllocation(mParams.getAllocation(), Defines.ALLOC_PARAMS);
+ mScript.bindAllocation(mState.getAllocation(), Defines.ALLOC_STATE);
+ mScript.bindAllocation(mAllocIconID, Defines.ALLOC_ICON_IDS);
+ mScript.bindAllocation(mAllocScratch, Defines.ALLOC_SCRATCH);
+ mScript.bindAllocation(mAllocLabelID, Defines.ALLOC_LABEL_IDS);
mRS.contextBindRootScript(mScript);
}
diff --git a/src/com/android/launcher2/IntAllocation.java b/src/com/android/launcher2/IntAllocation.java
index ab9d915..dde3d22 100644
--- a/src/com/android/launcher2/IntAllocation.java
+++ b/src/com/android/launcher2/IntAllocation.java
@@ -81,6 +81,24 @@
mAlloc.data(buf);
}
+ public void read() {
+ int[] buf = mBuffer;
+ if (buf != null) {
+ mAlloc.readData(buf);
+ Field[] fields = this.getClass().getFields();
+ for (Field f: fields) {
+ AllocationIndex index = f.getAnnotation(AllocationIndex.class);
+ if (index != null) {
+ try {
+ f.setInt(this, buf[index.value()]);
+ } catch (IllegalAccessException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ }
+ }
+ }
+
Allocation getAllocation() {
return mAlloc;
}