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