BouncyDroid.java revision 9bb57352244a7e2db1e1041ebf91ebef692152c0
19bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerpackage com.android.dreamtheater;
29bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
39bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.animation.PropertyValuesHolder;
49bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.animation.TimeAnimator;
59bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.app.Activity;
69bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.content.Context;
79bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.content.Intent;
89bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.dreams.BasicDream;
99bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.graphics.Canvas;
109bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.graphics.Matrix;
119bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.graphics.Paint;
129bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.graphics.RectF;
139bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.os.Bundle;
149bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.util.AttributeSet;
159bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.util.Log;
169bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.view.MotionEvent;
179bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.view.View;
189bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.view.Gravity;
199bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.view.ViewGroup;
209bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.widget.Button;
219bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.widget.FrameLayout;
229bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport android.widget.ImageView;
239bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
249bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport java.util.LinkedList;
259bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerimport java.util.HashMap;
269bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
279bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandlerpublic class BouncyDroid extends Activity {
289bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler    static final boolean DEBUG = true;
299bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler    static final boolean CENTER_DROID = true;
309bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
319bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler    public static class BouncyView extends FrameLayout
329bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler    {
339bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        boolean mShowDebug = false;
349bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
359bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        static final int RADIUS = 128;
369bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
379bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        static final boolean HAS_INITIAL_IMPULSE = true;
389bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        static final boolean HAS_GRAVITY = true;
399bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        static final boolean HAS_FRICTION = false;
409bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        static final boolean HAS_EDGES = true;
419bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
429bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        static final boolean STICKY_FINGERS = true;
439bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
449bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        static final float MAX_SPEED = 5000f;
459bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
469bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        public static class World {
479bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            public static final float PX_PER_METER = 100f;
489bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            public static final float GRAVITY = 1000f;
499bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            public static class Vec {
509bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                float x;
519bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                float y;
529bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                public Vec() {
539bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    x = y = 0;
549bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
559bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                public Vec(float _x, float _y) {
569bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    x = _x;
579bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    y = _y;
589bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
599bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                public Vec add(Vec v) {
609bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    return new Vec(x + v.x, y + v.y);
619bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
629bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                public Vec mul(float a) {
639bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    return new Vec(x * a, y * a);
649bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
659bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                public Vec sub(Vec v) {
669bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    return new Vec(x - v.x, y - v.y);
679bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
689bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                public float mag() {
699bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    return (float) Math.hypot(x, y);
709bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
719bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                public Vec norm() {
729bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    float k = 1/mag();
739bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    return new Vec(x*k, y*k);
749bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
759bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                public String toString() {
769bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    return "(" + x + "," + y + ")";
779bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
789bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            }
799bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            public static class Body {
809bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                float m, r;
819bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                Vec p = new Vec();
829bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                Vec v = new Vec();
839bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                LinkedList<Vec> forces = new LinkedList<Vec>();
849bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                LinkedList<Vec> impulses = new LinkedList<Vec>();
859bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                public Body(float _m, Vec _p) {
869bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    m = _m;
879bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    p = _p;
889bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
899bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                public void applyForce(Vec f) {
909bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    forces.add(f);
919bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
929bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                public void applyImpulse(Vec f) {
939bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    impulses.add(f);
949bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
959bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                public void clearForces() {
969bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    forces.clear();
979bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
989bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                public void removeForce(Vec f) {
999bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    forces.remove(f);
1009bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
1019bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                public void step(float dt) {
1029bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    p = p.add(v.mul(dt));
1039bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    for (Vec f : impulses) {
1049bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        v = v.add(f.mul(dt/m));
1059bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    }
1069bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    impulses.clear();
1079bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    for (Vec f : forces) {
1089bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        v = v.add(f.mul(dt/m));
1099bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    }
1109bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
1119bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                public String toString() {
1129bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    return "Body(m=" + m + " p=" + p + " v=" + v + ")";
1139bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
1149bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            }
1159bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            LinkedList<Body> mBodies = new LinkedList<Body>();
1169bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            public void addBody(Body b) {
1179bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                mBodies.add(b);
1189bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            }
1199bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
1209bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            public void step(float dt) {
1219bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                for (Body b : mBodies) {
1229bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    b.step(dt);
1239bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
1249bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            }
1259bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        }
1269bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
1279bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
1289bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        TimeAnimator mAnim;
1299bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        World mWorld;
1309bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        ImageView mBug;
1319bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        View mShowDebugView;
1329bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        HashMap<Integer, World.Vec> mFingers = new HashMap<Integer, World.Vec>();
1339bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        World.Body mBody;
1349bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        World.Vec mGrabSpot;
1359bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        int mGrabbedPointer = -1;
1369bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
1379bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        public BouncyView(Context context, AttributeSet as) {
1389bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            super(context, as);
1399bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
1409bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            /*
1419bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
1429bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                @Override
1439bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                public void onSystemUiVisibilityChange(int visibility) {
1449bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    if (visibility == View.STATUS_BAR_VISIBLE) {
1459bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        ((Activity)getContext()).finish();
1469bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    }
1479bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
1489bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            });
1499bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            */
1509bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
1519bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            mBug = new ImageView(context);
1529bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            mBug.setScaleType(ImageView.ScaleType.MATRIX);
1539bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            addView(mBug, new ViewGroup.LayoutParams(
1549bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        ViewGroup.LayoutParams.WRAP_CONTENT,
1559bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        ViewGroup.LayoutParams.WRAP_CONTENT));
1569bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
1579bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            if (DEBUG) {
1589bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                Button b = new Button(getContext());
1599bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                b.setText("Debugzors");
1609bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                b.setBackgroundColor(0); // very hard to see! :)
1619bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                b.setOnClickListener(new View.OnClickListener() {
1629bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    @Override
1639bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    public void onClick(View v) {
1649bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        setDebug(!mShowDebug);
1659bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    }
1669bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                });
1679bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                addView(b, new FrameLayout.LayoutParams(
1689bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            ViewGroup.LayoutParams.WRAP_CONTENT,
1699bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            ViewGroup.LayoutParams.WRAP_CONTENT,
1709bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            Gravity.TOP|Gravity.RIGHT));
1719bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            }
1729bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        }
1739bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
1749bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        public void setDebug(boolean d) {
1759bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            if (d != mShowDebug) {
1769bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                if (d) {
1779bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    mShowDebugView = new DebugView(getContext());
1789bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    mShowDebugView.setLayoutParams(
1799bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        new ViewGroup.LayoutParams(
1809bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            ViewGroup.LayoutParams.MATCH_PARENT,
1819bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            ViewGroup.LayoutParams.MATCH_PARENT
1829bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        ));
1839bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    addView(mShowDebugView);
1849bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
1859bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    mBug.setBackgroundColor(0x2000FF00);
1869bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                } else {
1879bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    if (mShowDebugView != null) {
1889bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        removeView(mShowDebugView);
1899bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        mShowDebugView = null;
1909bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    }
1919bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    mBug.setBackgroundColor(0);
1929bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
1939bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                invalidate();
1949bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                mShowDebug = d;
1959bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            }
1969bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        }
1979bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
1989bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        private void reset() {
1999bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            mWorld = new World();
2009bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            final float mass = 100;
2019bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            mBody = new World.Body(mass, new World.Vec(200,200));
2029bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            mBody.r = RADIUS;
2039bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            mWorld.addBody(mBody);
2049bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            mGrabbedPointer = -1;
2059bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
2069bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            mAnim = new TimeAnimator();
2079bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            mAnim.setTimeListener(new TimeAnimator.TimeListener() {
2089bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
2099bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    if (deltaTime > 0) {
2109bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        int STEPS = 5;
2119bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        final float dt = deltaTime / (float) STEPS;
2129bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        while (STEPS-->0) {
2139bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            mBody.clearForces();
2149bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
2159bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            if (HAS_INITIAL_IMPULSE) {
2169bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                // initial oomph
2179bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                if (totalTime == 0) {
2189bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    mBody.applyImpulse(new World.Vec(400000, -200000));
2199bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                }
2209bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            }
2219bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
2229bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            if (HAS_GRAVITY) {
2239bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                // gravity points down
2249bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                mBody.applyForce(new World.Vec(0, mass * World.GRAVITY));
2259bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            }
2269bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
2279bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            if (mGrabbedPointer >= 0) {
2289bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                World.Vec finger = mFingers.get(mGrabbedPointer);
2299bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                if (finger == null) {
2309bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    // let go!
2319bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    mGrabbedPointer = -1;
2329bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                } else {
2339bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    // never gonna let you go
2349bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    World.Vec newPos = finger.add(mGrabSpot);
2359bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    mBody.v = mBody.v.add(newPos.sub(mBody.p).mul(dt));
2369bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    mBody.p = newPos;
2379bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                }
2389bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            } else {
2399bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                // springs
2409bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                // ideal Hooke's Law plus a maximum force and a minimum length cutoff
2419bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                for (Integer i : mFingers.keySet()) {
2429bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    World.Vec finger = mFingers.get(i);
2439bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    World.Vec springForce = finger.sub(mBody.p);
2449bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    float mag = springForce.mag();
2459bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
2469bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    if (STICKY_FINGERS && mag < mBody.r*0.75) {
2479bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                        // close enough; we'll call this a "stick"
2489bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                        mGrabbedPointer = i;
2499bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                        mGrabSpot = mBody.p.sub(finger);
2509bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                        mBody.v = new World.Vec(0,0);
2519bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                        break;
2529bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    }
2539bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
2549bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    final float SPRING_K = 300000;
2559bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    final float FORCE_MAX = 10*SPRING_K;
2569bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    mag = (float) Math.min(mag * SPRING_K, FORCE_MAX); // Hooke's law
2579bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            //                    float mag = (float) (FORCE_MAX / Math.pow(springForce.mag(), 2)); // Gravitation
2589bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    springForce = springForce.norm().mul(mag);
2599bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    mBody.applyForce(springForce);
2609bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                }
2619bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            }
2629bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
2639bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            if (HAS_FRICTION) {
2649bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                // sliding friction opposes movement
2659bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                mBody.applyForce(mBody.v.mul(-4f * mBody.m));
2669bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            }
2679bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
2689bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            if (HAS_EDGES) {
2699bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                if (mBody.p.x - mBody.r < 0) {
2709bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    mBody.v.x = (float) Math.abs(mBody.v.x) *
2719bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                        (HAS_FRICTION ? 0.7f : 1f);
2729bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                } else if (mBody.p.x + mBody.r > getWidth()) {
2739bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    mBody.v.x = (float) Math.abs(mBody.v.x) *
2749bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                        (HAS_FRICTION ? -0.7f : -1f);
2759bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                }
2769bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                if (mBody.p.y - mBody.r < 0) {
2779bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    mBody.v.y = (float) Math.abs(mBody.v.y) *
2789bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                        (HAS_FRICTION ? 0.7f : 1f);
2799bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                } else if (mBody.p.y + mBody.r > getHeight()) {
2809bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    mBody.v.y = (float) Math.abs(mBody.v.y) *
2819bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                        (HAS_FRICTION ? -0.7f : -1f);
2829bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                }
2839bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            }
2849bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
2859bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            if (MAX_SPEED > 0) {
2869bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                if (mBody.v.mag() > MAX_SPEED) {
2879bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                    mBody.v = mBody.v.norm().mul(MAX_SPEED);
2889bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                }
2899bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            }
2909bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
2919bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            // ok, Euler, do your thing
2929bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            mWorld.step(dt / 1000f); // dt is in sec
2939bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        }
2949bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    }
2959bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    mBug.setTranslationX(mBody.p.x - mBody.r);
2969bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    mBug.setTranslationY(mBody.p.y - mBody.r);
2979bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
2989bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    Matrix m = new Matrix();
2999bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    m.setScale(
3009bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        (mBody.v.x < 0)    ? -1 : 1,
3019bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        (mBody.v.y > 1500) ? -1 : 1, // AAAAAAAAAAAAAAAA
3029bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        RADIUS, RADIUS);
3039bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    mBug.setImageMatrix(m);
3049bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    if (CENTER_DROID) {
3059bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        mBug.setImageResource(
3069bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                            (Math.abs(mBody.v.x) < 25)
3079bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                ? R.drawable.bouncy_center
3089bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                : R.drawable.bouncy);
3099bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    }
3109bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
3119bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    if (mShowDebug) mShowDebugView.invalidate();
3129bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
3139bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            });
3149bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        }
3159bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
3169bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        @Override
3179bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        protected void onAttachedToWindow() {
3189bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            super.onAttachedToWindow();
3199bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            setSystemUiVisibility(View.STATUS_BAR_HIDDEN);
3209bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
3219bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            reset();
3229bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            mAnim.start();
3239bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        }
3249bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
3259bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        @Override
3269bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        protected void onDetachedFromWindow() {
3279bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            super.onDetachedFromWindow();
3289bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            mAnim.cancel();
3299bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        }
3309bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
3319bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        @Override
3329bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        public boolean onTouchEvent(MotionEvent event) {
3339bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            int i;
3349bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            for (i=0; i<event.getPointerCount(); i++) {
3359bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                switch (event.getActionMasked()) {
3369bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    case MotionEvent.ACTION_DOWN:
3379bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    case MotionEvent.ACTION_MOVE:
3389bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    case MotionEvent.ACTION_POINTER_DOWN:
3399bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        mFingers.put(event.getPointerId(i),
3409bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                                new World.Vec(event.getX(i), event.getY(i)));
3419bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        break;
3429bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
3439bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    case MotionEvent.ACTION_UP:
3449bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    case MotionEvent.ACTION_POINTER_UP:
3459bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        mFingers.remove(event.getPointerId(i));
3469bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        break;
3479bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
3489bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    case MotionEvent.ACTION_CANCEL:
3499bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        mFingers.clear();
3509bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        break;
3519bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
3529bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            }
3539bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            // expired pointers
3549bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler    //        for (; i<mFingers.length; i++) {
3559bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler    //            mFingers[i] = null;
3569bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler    //        }
3579bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            return true;
3589bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        }
3599bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
3609bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        @Override
3619bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        public boolean isOpaque() {
3629bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            return true;
3639bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        }
3649bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
3659bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        class DebugView extends View {
3669bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            public DebugView(Context ct) {
3679bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                super(ct);
3689bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            }
3699bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
3709bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            private void drawVector(Canvas canvas,
3719bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    float x, float y, float vx, float vy,
3729bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    Paint pt) {
3739bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                final float mag = (float) Math.hypot(vx, vy);
3749bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
3759bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                canvas.save();
3769bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                Matrix mx = new Matrix();
3779bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                mx.setSinCos(-vx/mag, vy/mag);
3789bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                mx.postTranslate(x, y);
3799bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                canvas.setMatrix(mx);
3809bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
3819bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                canvas.drawLine(0,0, 0, mag, pt);
3829bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                canvas.drawLine(0, mag, -4, mag-4, pt);
3839bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                canvas.drawLine(0, mag, 4, mag-4, pt);
3849bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
3859bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                canvas.restore();
3869bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            }
3879bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
3889bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            @Override
3899bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            protected void onDraw(Canvas canvas) {
3909bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                super.onDraw(canvas);
3919bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
3929bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                Paint pt = new Paint(Paint.ANTI_ALIAS_FLAG);
3939bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                pt.setColor(0xFFCC0000);
3949bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                pt.setTextSize(30f);
3959bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                pt.setStrokeWidth(1.0f);
3969bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
3979bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                for (Integer id : mFingers.keySet()) {
3989bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    World.Vec v = mFingers.get(id);
3999bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    float x = v.x;
4009bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    float y = v.y;
4019bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    pt.setStyle(Paint.Style.FILL);
4029bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    canvas.drawText("#"+id, x+38, y-38, pt);
4039bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    pt.setStyle(Paint.Style.STROKE);
4049bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    canvas.drawLine(x-40, y, x+40, y, pt);
4059bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    canvas.drawLine(x, y-40, x, y+40, pt);
4069bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    canvas.drawCircle(x, y, 40, pt);
4079bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
4089bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                pt.setStyle(Paint.Style.STROKE);
4099bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                if (mBody != null) {
4109bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    float x = mBody.p.x;
4119bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    float y = mBody.p.y;
4129bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    float r = mBody.r;
4139bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    pt.setColor(0xFF6699FF);
4149bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    RectF bounds = new RectF(x-r, y-r, x+r, y+r);
4159bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    canvas.drawOval(bounds, pt);
4169bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
4179bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    pt.setStrokeWidth(3);
4189bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    drawVector(canvas, x, y, mBody.v.x/1000, mBody.v.y/1000, pt);
4199bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
4209bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    pt.setColor(0xFF0033FF);
4219bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    for (World.Vec f : mBody.forces) {
4229bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                        drawVector(canvas, x, y, f.x/1000, f.y/1000, pt);
4239bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                    }
4249bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler                }
4259bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler            }
4269bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        }
4279bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler    }
4289bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler
4299bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler    @Override
4309bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler    public void onStart() {
4319bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        super.onStart();
4329bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler        setContentView(new BouncyView(this, null));
4339bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler    }
4349bb57352244a7e2db1e1041ebf91ebef692152c0Daniel Sandler}
435