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.cube1; 18 19 import android.graphics.Canvas; 20 import android.graphics.Paint; 21 import android.graphics.Rect; 22 import android.os.Handler; 23 import android.os.SystemClock; 24 import android.service.wallpaper.WallpaperService; 25 import android.util.Log; 26 import android.view.MotionEvent; 27 import android.view.SurfaceHolder; 28 29 /* 30 * This animated wallpaper draws a rotating wireframe cube. 31 */ 32 public class CubeWallpaper1 extends WallpaperService { 33 34 private final Handler mHandler = new Handler(); 35 36 @Override onCreate()37 public void onCreate() { 38 super.onCreate(); 39 } 40 41 @Override onDestroy()42 public void onDestroy() { 43 super.onDestroy(); 44 } 45 46 @Override onCreateEngine()47 public Engine onCreateEngine() { 48 return new CubeEngine(); 49 } 50 51 class CubeEngine extends Engine { 52 53 private final Paint mPaint = new Paint(); 54 private float mOffset; 55 private float mTouchX = -1; 56 private float mTouchY = -1; 57 private long mStartTime; 58 private float mCenterX; 59 private float mCenterY; 60 61 private final Runnable mDrawCube = new Runnable() { 62 public void run() { 63 drawFrame(); 64 } 65 }; 66 private boolean mVisible; 67 CubeEngine()68 CubeEngine() { 69 // Create a Paint to draw the lines for our cube 70 final Paint paint = mPaint; 71 paint.setColor(0xffffffff); 72 paint.setAntiAlias(true); 73 paint.setStrokeWidth(2); 74 paint.setStrokeCap(Paint.Cap.ROUND); 75 paint.setStyle(Paint.Style.STROKE); 76 77 mStartTime = SystemClock.elapsedRealtime(); 78 } 79 80 @Override onCreate(SurfaceHolder surfaceHolder)81 public void onCreate(SurfaceHolder surfaceHolder) { 82 super.onCreate(surfaceHolder); 83 84 // By default we don't get touch events, so enable them. 85 setTouchEventsEnabled(true); 86 } 87 88 @Override onDestroy()89 public void onDestroy() { 90 super.onDestroy(); 91 mHandler.removeCallbacks(mDrawCube); 92 } 93 94 @Override onVisibilityChanged(boolean visible)95 public void onVisibilityChanged(boolean visible) { 96 mVisible = visible; 97 if (visible) { 98 drawFrame(); 99 } else { 100 mHandler.removeCallbacks(mDrawCube); 101 } 102 } 103 104 @Override onSurfaceChanged(SurfaceHolder holder, int format, int width, int height)105 public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { 106 super.onSurfaceChanged(holder, format, width, height); 107 // store the center of the surface, so we can draw the cube in the right spot 108 mCenterX = width/2.0f; 109 mCenterY = height/2.0f; 110 drawFrame(); 111 } 112 113 @Override onSurfaceCreated(SurfaceHolder holder)114 public void onSurfaceCreated(SurfaceHolder holder) { 115 super.onSurfaceCreated(holder); 116 } 117 118 @Override onSurfaceDestroyed(SurfaceHolder holder)119 public void onSurfaceDestroyed(SurfaceHolder holder) { 120 super.onSurfaceDestroyed(holder); 121 mVisible = false; 122 mHandler.removeCallbacks(mDrawCube); 123 } 124 125 @Override onOffsetsChanged(float xOffset, float yOffset, float xStep, float yStep, int xPixels, int yPixels)126 public void onOffsetsChanged(float xOffset, float yOffset, 127 float xStep, float yStep, int xPixels, int yPixels) { 128 mOffset = xOffset; 129 drawFrame(); 130 } 131 132 /* 133 * Store the position of the touch event so we can use it for drawing later 134 */ 135 @Override onTouchEvent(MotionEvent event)136 public void onTouchEvent(MotionEvent event) { 137 if (event.getAction() == MotionEvent.ACTION_MOVE) { 138 mTouchX = event.getX(); 139 mTouchY = event.getY(); 140 } else { 141 mTouchX = -1; 142 mTouchY = -1; 143 } 144 super.onTouchEvent(event); 145 } 146 147 /* 148 * Draw one frame of the animation. This method gets called repeatedly 149 * by posting a delayed Runnable. You can do any drawing you want in 150 * here. This example draws a wireframe cube. 151 */ drawFrame()152 void drawFrame() { 153 final SurfaceHolder holder = getSurfaceHolder(); 154 155 Canvas c = null; 156 try { 157 c = holder.lockCanvas(); 158 if (c != null) { 159 // draw something 160 drawCube(c); 161 drawTouchPoint(c); 162 } 163 } finally { 164 if (c != null) holder.unlockCanvasAndPost(c); 165 } 166 167 // Reschedule the next redraw 168 mHandler.removeCallbacks(mDrawCube); 169 if (mVisible) { 170 mHandler.postDelayed(mDrawCube, 1000 / 25); 171 } 172 } 173 174 /* 175 * Draw a wireframe cube by drawing 12 3 dimensional lines between 176 * adjacent corners of the cube 177 */ drawCube(Canvas c)178 void drawCube(Canvas c) { 179 c.save(); 180 c.translate(mCenterX, mCenterY); 181 c.drawColor(0xff000000); 182 drawLine(c, -400, -400, -400, 400, -400, -400); 183 drawLine(c, 400, -400, -400, 400, 400, -400); 184 drawLine(c, 400, 400, -400, -400, 400, -400); 185 drawLine(c, -400, 400, -400, -400, -400, -400); 186 187 drawLine(c, -400, -400, 400, 400, -400, 400); 188 drawLine(c, 400, -400, 400, 400, 400, 400); 189 drawLine(c, 400, 400, 400, -400, 400, 400); 190 drawLine(c, -400, 400, 400, -400, -400, 400); 191 192 drawLine(c, -400, -400, 400, -400, -400, -400); 193 drawLine(c, 400, -400, 400, 400, -400, -400); 194 drawLine(c, 400, 400, 400, 400, 400, -400); 195 drawLine(c, -400, 400, 400, -400, 400, -400); 196 c.restore(); 197 } 198 199 /* 200 * Draw a 3 dimensional line on to the screen 201 */ drawLine(Canvas c, int x1, int y1, int z1, int x2, int y2, int z2)202 void drawLine(Canvas c, int x1, int y1, int z1, int x2, int y2, int z2) { 203 long now = SystemClock.elapsedRealtime(); 204 float xrot = ((float)(now - mStartTime)) / 1000; 205 float yrot = (0.5f - mOffset) * 2.0f; 206 float zrot = 0; 207 208 // 3D transformations 209 210 // rotation around X-axis 211 float newy1 = (float)(Math.sin(xrot) * z1 + Math.cos(xrot) * y1); 212 float newy2 = (float)(Math.sin(xrot) * z2 + Math.cos(xrot) * y2); 213 float newz1 = (float)(Math.cos(xrot) * z1 - Math.sin(xrot) * y1); 214 float newz2 = (float)(Math.cos(xrot) * z2 - Math.sin(xrot) * y2); 215 216 // rotation around Y-axis 217 float newx1 = (float)(Math.sin(yrot) * newz1 + Math.cos(yrot) * x1); 218 float newx2 = (float)(Math.sin(yrot) * newz2 + Math.cos(yrot) * x2); 219 newz1 = (float)(Math.cos(yrot) * newz1 - Math.sin(yrot) * x1); 220 newz2 = (float)(Math.cos(yrot) * newz2 - Math.sin(yrot) * x2); 221 222 // 3D-to-2D projection 223 float startX = newx1 / (4 - newz1 / 400); 224 float startY = newy1 / (4 - newz1 / 400); 225 float stopX = newx2 / (4 - newz2 / 400); 226 float stopY = newy2 / (4 - newz2 / 400); 227 228 c.drawLine(startX, startY, stopX, stopY, mPaint); 229 } 230 231 /* 232 * Draw a circle around the current touch point, if any. 233 */ drawTouchPoint(Canvas c)234 void drawTouchPoint(Canvas c) { 235 if (mTouchX >=0 && mTouchY >= 0) { 236 c.drawCircle(mTouchX, mTouchY, 80, mPaint); 237 } 238 } 239 240 } 241 } 242