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