142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen/*
242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen * Copyright (C) 2009 The Android Open Source Project
342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen *
442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen * Licensed under the Apache License, Version 2.0 (the "License");
542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen * you may not use this file except in compliance with the License.
642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen * You may obtain a copy of the License at
742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen *
842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen *      http://www.apache.org/licenses/LICENSE-2.0
942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen *
1042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen * Unless required by applicable law or agreed to in writing, software
1142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen * distributed under the License is distributed on an "AS IS" BASIS,
1242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen * See the License for the specific language governing permissions and
1442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen * limitations under the License.
1542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen */
1642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
17b84cf9e1e378f6cc6642b4ac3f391a85b208a23bXavier Ducrohetpackage com.example.android.livecubes.cube2;
1842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
1942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissenimport android.content.SharedPreferences;
2042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissenimport android.graphics.Canvas;
2142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissenimport android.graphics.Paint;
2242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissenimport android.graphics.Rect;
2342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissenimport android.os.Handler;
2442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissenimport android.os.SystemClock;
2542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissenimport android.service.wallpaper.WallpaperService;
2642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissenimport android.view.MotionEvent;
2742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissenimport android.view.SurfaceHolder;
2842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
2942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen/*
3042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen * This animated wallpaper draws a rotating wireframe shape. It is similar to
3142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen * example #1, but has a choice of 2 shapes, which are user selectable and
3242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen * defined in resources instead of in code.
3342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen */
3442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
3542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissenpublic class CubeWallpaper2 extends WallpaperService {
3642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
3742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen    public static final String SHARED_PREFS_NAME="cube2settings";
3842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
3942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen    static class ThreeDPoint {
4042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        float x;
4142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        float y;
4242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        float z;
4342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen    }
4442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
4542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen    static class ThreeDLine {
4642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        int startPoint;
4742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        int endPoint;
4842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen    }
4942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
5042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen    @Override
5142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen    public void onCreate() {
5242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        super.onCreate();
5342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen    }
5442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
5542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen    @Override
5642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen    public void onDestroy() {
5742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        super.onDestroy();
5842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen    }
5942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
6042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen    @Override
6142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen    public Engine onCreateEngine() {
6242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        return new CubeEngine();
6342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen    }
6442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
6542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen    class CubeEngine extends Engine
6642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        implements SharedPreferences.OnSharedPreferenceChangeListener {
6742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
6842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        private final Handler mHandler = new Handler();
6942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
7042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        ThreeDPoint [] mOriginalPoints;
7142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        ThreeDPoint [] mRotatedPoints;
7242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        ThreeDLine [] mLines;
7342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        private final Paint mPaint = new Paint();
7442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        private float mOffset;
7542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        private float mTouchX = -1;
7642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        private float mTouchY = -1;
7742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        private long mStartTime;
7842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        private float mCenterX;
7942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        private float mCenterY;
8042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
8142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        private final Runnable mDrawCube = new Runnable() {
8242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            public void run() {
8342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                drawFrame();
8442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            }
8542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        };
8642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        private boolean mVisible;
8742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        private SharedPreferences mPrefs;
8842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
8942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        CubeEngine() {
9042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            // Create a Paint to draw the lines for our cube
9142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            final Paint paint = mPaint;
9242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            paint.setColor(0xffffffff);
9342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            paint.setAntiAlias(true);
9442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            paint.setStrokeWidth(2);
9542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            paint.setStrokeCap(Paint.Cap.ROUND);
9642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            paint.setStyle(Paint.Style.STROKE);
9742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
9842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            mStartTime = SystemClock.elapsedRealtime();
9942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
10042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            mPrefs = CubeWallpaper2.this.getSharedPreferences(SHARED_PREFS_NAME, 0);
10142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            mPrefs.registerOnSharedPreferenceChangeListener(this);
10242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            onSharedPreferenceChanged(mPrefs, null);
10342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        }
10442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
10542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
10642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
10742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            String shape = prefs.getString("cube2_shape", "cube");
10842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
10942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            // read the 3D model from the resource
11042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            readModel(shape);
11142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        }
11242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
11342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        private void readModel(String prefix) {
11442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            // Read the model definition in from a resource.
11542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
11642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            // get the resource identifiers for the arrays for the selected shape
11742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            int pid = getResources().getIdentifier(prefix + "points", "array", getPackageName());
11842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            int lid = getResources().getIdentifier(prefix + "lines", "array", getPackageName());
11942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
12042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            String [] p = getResources().getStringArray(pid);
12142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            int numpoints = p.length;
12242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            mOriginalPoints = new ThreeDPoint[numpoints];
12342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            mRotatedPoints = new ThreeDPoint[numpoints];
12442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
12542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            for (int i = 0; i < numpoints; i++) {
12642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                mOriginalPoints[i] = new ThreeDPoint();
12742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                mRotatedPoints[i] = new ThreeDPoint();
12842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                String [] coord = p[i].split(" ");
12942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                mOriginalPoints[i].x = Float.valueOf(coord[0]);
13042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                mOriginalPoints[i].y = Float.valueOf(coord[1]);
13142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                mOriginalPoints[i].z = Float.valueOf(coord[2]);
13242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            }
13342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
13442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            String [] l = getResources().getStringArray(lid);
13542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            int numlines = l.length;
13642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            mLines = new ThreeDLine[numlines];
13742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
13842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            for (int i = 0; i < numlines; i++) {
13942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                mLines[i] = new ThreeDLine();
14042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                String [] idx = l[i].split(" ");
14142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                mLines[i].startPoint = Integer.valueOf(idx[0]);
14242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                mLines[i].endPoint = Integer.valueOf(idx[1]);
14342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            }
14442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        }
14542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
14642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        @Override
14742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        public void onCreate(SurfaceHolder surfaceHolder) {
14842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            super.onCreate(surfaceHolder);
14942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            setTouchEventsEnabled(true);
15042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        }
15142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
15242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        @Override
15342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        public void onDestroy() {
15442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            super.onDestroy();
15542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            mHandler.removeCallbacks(mDrawCube);
15642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        }
15742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
15842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        @Override
15942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        public void onVisibilityChanged(boolean visible) {
16042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            mVisible = visible;
16142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            if (visible) {
16242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                drawFrame();
16342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            } else {
16442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                mHandler.removeCallbacks(mDrawCube);
16542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            }
16642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        }
16742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
16842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        @Override
16942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
17042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            super.onSurfaceChanged(holder, format, width, height);
17142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            // store the center of the surface, so we can draw the cube in the right spot
17242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            mCenterX = width/2.0f;
17342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            mCenterY = height/2.0f;
17442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            drawFrame();
17542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        }
17642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
17742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        @Override
17842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        public void onSurfaceCreated(SurfaceHolder holder) {
17942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            super.onSurfaceCreated(holder);
18042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        }
18142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
18242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        @Override
18342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        public void onSurfaceDestroyed(SurfaceHolder holder) {
18442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            super.onSurfaceDestroyed(holder);
18542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            mVisible = false;
18642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            mHandler.removeCallbacks(mDrawCube);
18742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        }
18842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
18942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        @Override
19042c35199db9b3ec2ec467f926538e5d748e0b49dMarco Nelissen        public void onOffsetsChanged(float xOffset, float yOffset,
19142c35199db9b3ec2ec467f926538e5d748e0b49dMarco Nelissen                float xStep, float yStep, int xPixels, int yPixels) {
19242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            mOffset = xOffset;
19342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            drawFrame();
19442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        }
19542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
19642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        /*
19742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen         * Store the position of the touch event so we can use it for drawing later
19842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen         */
19942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        @Override
20042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        public void onTouchEvent(MotionEvent event) {
20142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            if (event.getAction() == MotionEvent.ACTION_MOVE) {
20242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                mTouchX = event.getX();
20342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                mTouchY = event.getY();
20442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            } else {
20542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                mTouchX = -1;
20642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                mTouchY = -1;
20742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            }
20842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            super.onTouchEvent(event);
20942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        }
21042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
21142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        /*
21242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen         * Draw one frame of the animation. This method gets called repeatedly
21342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen         * by posting a delayed Runnable. You can do any drawing you want in
21442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen         * here. This example draws a wireframe cube.
21542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen         */
21642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        void drawFrame() {
21742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            final SurfaceHolder holder = getSurfaceHolder();
21842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            final Rect frame = holder.getSurfaceFrame();
21942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            final int width = frame.width();
22042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            final int height = frame.height();
22142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
22242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            Canvas c = null;
22342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            try {
22442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                c = holder.lockCanvas();
22542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                if (c != null) {
22642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                    // draw something
22742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                    drawCube(c);
22842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                    drawTouchPoint(c);
22942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                }
23042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            } finally {
23142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                if (c != null) holder.unlockCanvasAndPost(c);
23242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            }
23342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
23442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            mHandler.removeCallbacks(mDrawCube);
23542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            if (mVisible) {
23642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                mHandler.postDelayed(mDrawCube, 1000 / 25);
23742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            }
23842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        }
23942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
24042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        void drawCube(Canvas c) {
24142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            c.save();
24242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            c.translate(mCenterX, mCenterY);
24342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            c.drawColor(0xff000000);
24442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
24542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            long now = SystemClock.elapsedRealtime();
24642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            float xrot = ((float)(now - mStartTime)) / 1000;
24742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            float yrot = (0.5f - mOffset) * 2.0f;
24842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            rotateAndProjectPoints(xrot, yrot);
24942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            drawLines(c);
25042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            c.restore();
25142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        }
25242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
25342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        void rotateAndProjectPoints(float xrot, float yrot) {
25442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            int n = mOriginalPoints.length;
25542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            for (int i = 0; i < n; i++) {
25642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                // rotation around X-axis
25742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                ThreeDPoint p = mOriginalPoints[i];
25842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                float x = p.x;
25942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                float y = p.y;
26042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                float z = p.z;
26142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                float newy = (float)(Math.sin(xrot) * z + Math.cos(xrot) * y);
26242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                float newz = (float)(Math.cos(xrot) * z - Math.sin(xrot) * y);
26342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
26442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                // rotation around Y-axis
26542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                float newx = (float)(Math.sin(yrot) * newz + Math.cos(yrot) * x);
26642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                newz = (float)(Math.cos(yrot) * newz - Math.sin(yrot) * x);
26742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
26842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                // 3D-to-2D projection
26942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                float screenX = newx / (4 - newz / 400);
27042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                float screenY = newy / (4 - newz / 400);
27142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
27242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                mRotatedPoints[i].x = screenX;
27342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                mRotatedPoints[i].y = screenY;
27442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                mRotatedPoints[i].z = 0;
27542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            }
27642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        }
27742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
27842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        void drawLines(Canvas c) {
27942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            int n = mLines.length;
28042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            for (int i = 0; i < n; i++) {
28142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                ThreeDLine l = mLines[i];
28242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                ThreeDPoint start = mRotatedPoints[l.startPoint];
28342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                ThreeDPoint end = mRotatedPoints[l.endPoint];
28442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                c.drawLine(start.x, start.y, end.x, end.y, mPaint);
28542dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            }
28642dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        }
28742dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen
28842dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        void drawTouchPoint(Canvas c) {
28942dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            if (mTouchX >=0 && mTouchY >= 0) {
29042dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen                c.drawCircle(mTouchX, mTouchY, 80, mPaint);
29142dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen            }
29242dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen        }
29342dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen    }
29442dbb8b92b8c5c63d82fd9e571557b900a5bad7bMarco Nelissen}
295