Home | History | Annotate | Download | only in cube2
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.livecubes.cube2;
     18 
     19 import android.content.SharedPreferences;
     20 import android.graphics.Canvas;
     21 import android.graphics.Paint;
     22 import android.graphics.Rect;
     23 import android.os.Handler;
     24 import android.os.SystemClock;
     25 import android.service.wallpaper.WallpaperService;
     26 import android.view.MotionEvent;
     27 import android.view.SurfaceHolder;
     28 
     29 /*
     30  * This animated wallpaper draws a rotating wireframe shape. It is similar to
     31  * example #1, but has a choice of 2 shapes, which are user selectable and
     32  * defined in resources instead of in code.
     33  */
     34 
     35 public class CubeWallpaper2 extends WallpaperService {
     36 
     37     public static final String SHARED_PREFS_NAME="cube2settings";
     38 
     39     static class ThreeDPoint {
     40         float x;
     41         float y;
     42         float z;
     43     }
     44 
     45     static class ThreeDLine {
     46         int startPoint;
     47         int endPoint;
     48     }
     49 
     50     @Override
     51     public void onCreate() {
     52         super.onCreate();
     53     }
     54 
     55     @Override
     56     public void onDestroy() {
     57         super.onDestroy();
     58     }
     59 
     60     @Override
     61     public Engine onCreateEngine() {
     62         return new CubeEngine();
     63     }
     64 
     65     class CubeEngine extends Engine
     66         implements SharedPreferences.OnSharedPreferenceChangeListener {
     67 
     68         private final Handler mHandler = new Handler();
     69 
     70         ThreeDPoint [] mOriginalPoints;
     71         ThreeDPoint [] mRotatedPoints;
     72         ThreeDLine [] mLines;
     73         private final Paint mPaint = new Paint();
     74         private float mOffset;
     75         private float mTouchX = -1;
     76         private float mTouchY = -1;
     77         private long mStartTime;
     78         private float mCenterX;
     79         private float mCenterY;
     80 
     81         private final Runnable mDrawCube = new Runnable() {
     82             public void run() {
     83                 drawFrame();
     84             }
     85         };
     86         private boolean mVisible;
     87         private SharedPreferences mPrefs;
     88 
     89         CubeEngine() {
     90             // Create a Paint to draw the lines for our cube
     91             final Paint paint = mPaint;
     92             paint.setColor(0xffffffff);
     93             paint.setAntiAlias(true);
     94             paint.setStrokeWidth(2);
     95             paint.setStrokeCap(Paint.Cap.ROUND);
     96             paint.setStyle(Paint.Style.STROKE);
     97 
     98             mStartTime = SystemClock.elapsedRealtime();
     99 
    100             mPrefs = CubeWallpaper2.this.getSharedPreferences(SHARED_PREFS_NAME, 0);
    101             mPrefs.registerOnSharedPreferenceChangeListener(this);
    102             onSharedPreferenceChanged(mPrefs, null);
    103         }
    104 
    105         public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
    106 
    107             String shape = prefs.getString("cube2_shape", "cube");
    108 
    109             // read the 3D model from the resource
    110             readModel(shape);
    111         }
    112 
    113         private void readModel(String prefix) {
    114             // Read the model definition in from a resource.
    115 
    116             // get the resource identifiers for the arrays for the selected shape
    117             int pid = getResources().getIdentifier(prefix + "points", "array", getPackageName());
    118             int lid = getResources().getIdentifier(prefix + "lines", "array", getPackageName());
    119 
    120             String [] p = getResources().getStringArray(pid);
    121             int numpoints = p.length;
    122             mOriginalPoints = new ThreeDPoint[numpoints];
    123             mRotatedPoints = new ThreeDPoint[numpoints];
    124 
    125             for (int i = 0; i < numpoints; i++) {
    126                 mOriginalPoints[i] = new ThreeDPoint();
    127                 mRotatedPoints[i] = new ThreeDPoint();
    128                 String [] coord = p[i].split(" ");
    129                 mOriginalPoints[i].x = Float.valueOf(coord[0]);
    130                 mOriginalPoints[i].y = Float.valueOf(coord[1]);
    131                 mOriginalPoints[i].z = Float.valueOf(coord[2]);
    132             }
    133 
    134             String [] l = getResources().getStringArray(lid);
    135             int numlines = l.length;
    136             mLines = new ThreeDLine[numlines];
    137 
    138             for (int i = 0; i < numlines; i++) {
    139                 mLines[i] = new ThreeDLine();
    140                 String [] idx = l[i].split(" ");
    141                 mLines[i].startPoint = Integer.valueOf(idx[0]);
    142                 mLines[i].endPoint = Integer.valueOf(idx[1]);
    143             }
    144         }
    145 
    146         @Override
    147         public void onCreate(SurfaceHolder surfaceHolder) {
    148             super.onCreate(surfaceHolder);
    149             setTouchEventsEnabled(true);
    150         }
    151 
    152         @Override
    153         public void onDestroy() {
    154             super.onDestroy();
    155             mHandler.removeCallbacks(mDrawCube);
    156         }
    157 
    158         @Override
    159         public void onVisibilityChanged(boolean visible) {
    160             mVisible = visible;
    161             if (visible) {
    162                 drawFrame();
    163             } else {
    164                 mHandler.removeCallbacks(mDrawCube);
    165             }
    166         }
    167 
    168         @Override
    169         public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    170             super.onSurfaceChanged(holder, format, width, height);
    171             // store the center of the surface, so we can draw the cube in the right spot
    172             mCenterX = width/2.0f;
    173             mCenterY = height/2.0f;
    174             drawFrame();
    175         }
    176 
    177         @Override
    178         public void onSurfaceCreated(SurfaceHolder holder) {
    179             super.onSurfaceCreated(holder);
    180         }
    181 
    182         @Override
    183         public void onSurfaceDestroyed(SurfaceHolder holder) {
    184             super.onSurfaceDestroyed(holder);
    185             mVisible = false;
    186             mHandler.removeCallbacks(mDrawCube);
    187         }
    188 
    189         @Override
    190         public void onOffsetsChanged(float xOffset, float yOffset,
    191                 float xStep, float yStep, int xPixels, int yPixels) {
    192             mOffset = xOffset;
    193             drawFrame();
    194         }
    195 
    196         /*
    197          * Store the position of the touch event so we can use it for drawing later
    198          */
    199         @Override
    200         public void onTouchEvent(MotionEvent event) {
    201             if (event.getAction() == MotionEvent.ACTION_MOVE) {
    202                 mTouchX = event.getX();
    203                 mTouchY = event.getY();
    204             } else {
    205                 mTouchX = -1;
    206                 mTouchY = -1;
    207             }
    208             super.onTouchEvent(event);
    209         }
    210 
    211         /*
    212          * Draw one frame of the animation. This method gets called repeatedly
    213          * by posting a delayed Runnable. You can do any drawing you want in
    214          * here. This example draws a wireframe cube.
    215          */
    216         void drawFrame() {
    217             final SurfaceHolder holder = getSurfaceHolder();
    218             final Rect frame = holder.getSurfaceFrame();
    219             final int width = frame.width();
    220             final int height = frame.height();
    221 
    222             Canvas c = null;
    223             try {
    224                 c = holder.lockCanvas();
    225                 if (c != null) {
    226                     // draw something
    227                     drawCube(c);
    228                     drawTouchPoint(c);
    229                 }
    230             } finally {
    231                 if (c != null) holder.unlockCanvasAndPost(c);
    232             }
    233 
    234             mHandler.removeCallbacks(mDrawCube);
    235             if (mVisible) {
    236                 mHandler.postDelayed(mDrawCube, 1000 / 25);
    237             }
    238         }
    239 
    240         void drawCube(Canvas c) {
    241             c.save();
    242             c.translate(mCenterX, mCenterY);
    243             c.drawColor(0xff000000);
    244 
    245             long now = SystemClock.elapsedRealtime();
    246             float xrot = ((float)(now - mStartTime)) / 1000;
    247             float yrot = (0.5f - mOffset) * 2.0f;
    248             rotateAndProjectPoints(xrot, yrot);
    249             drawLines(c);
    250             c.restore();
    251         }
    252 
    253         void rotateAndProjectPoints(float xrot, float yrot) {
    254             int n = mOriginalPoints.length;
    255             for (int i = 0; i < n; i++) {
    256                 // rotation around X-axis
    257                 ThreeDPoint p = mOriginalPoints[i];
    258                 float x = p.x;
    259                 float y = p.y;
    260                 float z = p.z;
    261                 float newy = (float)(Math.sin(xrot) * z + Math.cos(xrot) * y);
    262                 float newz = (float)(Math.cos(xrot) * z - Math.sin(xrot) * y);
    263 
    264                 // rotation around Y-axis
    265                 float newx = (float)(Math.sin(yrot) * newz + Math.cos(yrot) * x);
    266                 newz = (float)(Math.cos(yrot) * newz - Math.sin(yrot) * x);
    267 
    268                 // 3D-to-2D projection
    269                 float screenX = newx / (4 - newz / 400);
    270                 float screenY = newy / (4 - newz / 400);
    271 
    272                 mRotatedPoints[i].x = screenX;
    273                 mRotatedPoints[i].y = screenY;
    274                 mRotatedPoints[i].z = 0;
    275             }
    276         }
    277 
    278         void drawLines(Canvas c) {
    279             int n = mLines.length;
    280             for (int i = 0; i < n; i++) {
    281                 ThreeDLine l = mLines[i];
    282                 ThreeDPoint start = mRotatedPoints[l.startPoint];
    283                 ThreeDPoint end = mRotatedPoints[l.endPoint];
    284                 c.drawLine(start.x, start.y, end.x, end.y, mPaint);
    285             }
    286         }
    287 
    288         void drawTouchPoint(Canvas c) {
    289             if (mTouchX >=0 && mTouchY >= 0) {
    290                 c.drawCircle(mTouchX, mTouchY, 80, mPaint);
    291             }
    292         }
    293     }
    294 }
    295