aboutsummaryrefslogtreecommitdiff
path: root/mobileapp/src/smoots/udesign/canvas/CanvasView.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobileapp/src/smoots/udesign/canvas/CanvasView.java')
-rwxr-xr-xmobileapp/src/smoots/udesign/canvas/CanvasView.java422
1 files changed, 422 insertions, 0 deletions
diff --git a/mobileapp/src/smoots/udesign/canvas/CanvasView.java b/mobileapp/src/smoots/udesign/canvas/CanvasView.java
new file mode 100755
index 0000000..11d6b60
--- /dev/null
+++ b/mobileapp/src/smoots/udesign/canvas/CanvasView.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package smoots.udesign.canvas;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * a View that takes accelerometer input and draws for CanvasActivity
+ */
+public class CanvasView extends SurfaceView implements SurfaceHolder.Callback {
+ public class CanvasThread extends Thread {
+ // ---------------------
+ // CONSTANTS
+ // ---------------------
+ public static final int PIXEL_RADIUS = 10;
+ public static final double TILT_THRESHOLD = 0.5;
+
+ public static final int STATE_PAUSE = 1;
+ public static final int STATE_RUNNING = 2;
+
+ // Bundle key constants
+ private static final String KEY_DX = "mDX";
+ private static final String KEY_DY = "mDY";
+ private static final String KEY_X = "mX";
+ private static final String KEY_Y = "mY";
+ private static final String KEY_COLOR = "mColor";
+
+ // ---------------------
+ // MEMBER FIELDS
+ // ---------------------
+ private Paint mPixelPaint;
+ private int mPixelColor = Color.WHITE;
+
+ // Position
+ private float CENTER_X;
+ private float CENTER_Y;
+ private float mX;
+ private float mY;
+ private boolean justStart = true; // if loop for the 1st time, determine
+ // the center of the canvas.
+ // Velocity
+ private float mDX;
+ private float mDY;
+
+ // Color
+ private int mColor;
+
+ // Canvas size, will be determined when view is started.
+ private int mCanvasHeight = 1;
+ private int mCanvasWidth = 1;
+
+ /** Message handler used by thread to interact with TextView */
+ private Handler mHandler;
+
+ /** Used to figure out elapsed time between frames */
+ private long mLastTime;
+
+ /** The state of the game. One of READY, RUNNING, PAUSE, LOSE, or WIN */
+ private int mMode;
+
+ /** Indicate whether the surface has been created & is ready to draw */
+ private boolean mRun = false;
+
+ /** Handle to the surface manager object we interact with */
+ private SurfaceHolder mSurfaceHolder;
+
+ public CanvasThread(SurfaceHolder surfaceHolder, Context context,
+ Handler handler) {
+ mContext = context;
+
+ // get handles to some important objects
+ this.mSurfaceHolder = surfaceHolder;
+ this.mHandler = handler;
+
+ mPixelPaint = new Paint();
+ mPixelPaint.setAntiAlias(true);
+ mPixelPaint.setStyle(Paint.Style.FILL);
+ mPixelPaint.setColor(Color.WHITE);
+
+ // initial show-up of lander (not yet playing)
+ this.mX = 0;
+ this.mY = 0;
+ this.mDX = 0;
+ this.mDY = 0;
+ this.mColor = Color.WHITE;
+ }
+
+ /**
+ * Start the view. Set the pixel's initial position.
+ */
+ public void doStart() {
+ synchronized (mSurfaceHolder) {
+ // pick the center location for the pixel.
+ this.mX = mCanvasWidth / 2;
+ this.mY = mCanvasHeight / 2;
+
+ this.mLastTime = System.currentTimeMillis() + 100;
+ setState(STATE_RUNNING);
+ }
+ }
+
+ /**
+ * Save canvas state to the provided Bundle.
+ *
+ * @return Bundle with current state
+ */
+ public Bundle saveState(Bundle map) {
+ synchronized (mSurfaceHolder) {
+ if (map != null) {
+ map.putDouble(KEY_X, Double.valueOf(this.mX));
+ map.putDouble(KEY_Y, Double.valueOf(this.mY));
+ map.putDouble(KEY_DX, Double.valueOf(this.mDX));
+ map.putDouble(KEY_DY, Double.valueOf(this.mDY));
+ map.putInt(KEY_COLOR, this.mColor);
+ }
+ }
+ return map;
+ }
+
+ /**
+ * Restores canvas state from the indicated Bundle.
+ *
+ * @param savedState
+ * Bundle with the saved state
+ */
+ public synchronized void restoreState(Bundle savedState) {
+ synchronized (mSurfaceHolder) {
+ setState(STATE_PAUSE);
+
+ this.mX = savedState.getFloat(KEY_X);
+ this.mY = savedState.getFloat(KEY_Y);
+ this.mDX = savedState.getFloat(KEY_DX);
+ this.mDY = savedState.getFloat(KEY_DY);
+ this.mColor = savedState.getInt("KEY_COLOR");
+ }
+ }
+
+ public void run() {
+ while (this.mRun) {
+ Canvas c = null;
+ try {
+ c = mSurfaceHolder.lockCanvas(null);
+ synchronized (mSurfaceHolder) {
+ if (mMode == STATE_RUNNING) {
+ updatePhysics();
+ }
+ doDraw(c);
+ }
+ } finally {
+ if (c != null) {
+ // keep states consistent.
+ mSurfaceHolder.unlockCanvasAndPost(c);
+ }
+ }
+ }
+ }
+
+ /**
+ * Set the thread loop handler.
+ *
+ * @param b whether the thread is running
+ */
+ public void setRunning(boolean b) {
+ this.mRun = b;
+ }
+
+ public void setState(int mode) {
+ synchronized (mSurfaceHolder) {
+ setState(mode, null);
+ }
+ }
+
+ /**
+ * Sets the canvas mode.
+ *
+ * @param mode
+ * one of the STATE constants
+ * @param message
+ * string to add to screen or null
+ */
+ public void setState(int mode, CharSequence message) {
+ /*
+ * This method optionally can cause a text message to be displayed
+ * to the user when the mode changes. Since the View that actually
+ * renders that text is part of the main View hierarchy and not
+ * owned by this thread, we can't touch the state of that View.
+ * Instead we use a Message + Handler to relay commands to the main
+ * thread, which updates the user-text View.
+ */
+ synchronized (mSurfaceHolder) {
+ mMode = mode;
+
+ if (mMode == STATE_RUNNING) {
+ Message msg = mHandler.obtainMessage();
+ Bundle b = new Bundle();
+ b.putString("text", "");
+ b.putInt("viz", View.INVISIBLE);
+ msg.setData(b);
+ mHandler.sendMessage(msg);
+ } else {
+ Resources res = mContext.getResources();
+ CharSequence str = "";
+
+ Message msg = mHandler.obtainMessage();
+ Bundle b = new Bundle();
+ b.putString("text", str.toString());
+ b.putInt("viz", View.VISIBLE);
+ msg.setData(b);
+ mHandler.sendMessage(msg);
+ }
+ }
+ }
+
+ /* Callback invoked when surface dimensions change. */
+ public void setSurfaceSize(int width, int height) {
+ // synchronized to make sure these all change atomically
+ synchronized (mSurfaceHolder) {
+ mCanvasWidth = width;
+ mCanvasHeight = height;
+ }
+ }
+
+ /**
+ * Pauses the animation.
+ */
+ public void pause() {
+ synchronized (mSurfaceHolder) {
+ if (mMode == STATE_RUNNING)
+ setState(STATE_PAUSE);
+ }
+ }
+
+ /**
+ * Resumes from a pause.
+ */
+ public void unpause() {
+ // Move the real time clock to now
+ synchronized (mSurfaceHolder) {
+ mLastTime = System.currentTimeMillis() + 100;
+ }
+ setState(STATE_RUNNING);
+ }
+
+ /**
+ * Draws the pixel to the provided Canvas.
+ */
+ private void doDraw(Canvas canvas) {
+ if (this.justStart) { // initialize pixel position
+ Log.d("Canvas", Integer.toString(canvas.getWidth()) + " by "
+ + Integer.toString(canvas.getHeight()));
+ this.CENTER_X = canvas.getWidth() / 2;
+ this.CENTER_Y = canvas.getHeight() / 2;
+
+ this.mX = this.CENTER_X;
+ this.mY = this.CENTER_Y;
+
+ this.justStart = false;
+ }
+
+ // Draw the black background.
+ this.mPixelPaint.setColor(Color.BLACK);
+ canvas.drawPaint(mPixelPaint);
+
+ // Draw pixel.
+ this.mPixelPaint.setColor(this.mPixelColor);
+ canvas.drawCircle(this.mX, this.mY, PIXEL_RADIUS, this.mPixelPaint);
+ }
+
+ /**
+ * Figures the lander state (x, y, fuel, ...) based on the passage of
+ * realtime. Does not invalidate(). Called at the start of draw().
+ * Detects the end-of-game and sets the UI to the next state.
+ */
+ private void updatePhysics() {
+ long now = System.currentTimeMillis();
+
+ // Do nothing if mLastTime is in the future.
+ // This allows the game-start to delay the start of the physics
+ // by 100ms or whatever.
+ if (mLastTime > now)
+ return;
+
+ double elapsed = (now - mLastTime) / 1000.0;
+
+ /*
+ * // Base accelerations -- 0 for x, gravity for y double ddx = 0.0;
+ * double ddy = elapsed;
+ *
+ * double dxOld = mDX; double dyOld = mDY;
+ *
+ * // figure speeds for the end of the period mDX += ddx; mDY +=
+ * ddy;
+ *
+ * // figure position based on average speed during the period mX +=
+ * elapsed * (mDX + dxOld) / 2; mY += elapsed * (mDY + dyOld) / 2;
+ */
+
+ mLastTime = now;
+ }
+
+ public void updatePixelColor(int color) {
+ this.mPixelColor = color;
+ }
+
+ public void updatePixelVelocity(float x, float y, float z) {
+ this.mX = (float) (this.CENTER_X - x / 10. * this.CENTER_X);
+ this.mY = (float) (this.CENTER_Y + y / 10. * this.CENTER_Y);
+ }
+ }
+
+ /** Handle to application context */
+ private Context mContext;
+
+ /** Pointer to the text view to display "Paused.." etc. */
+ private TextView mStatusText;
+
+ /** The thread that actually draws the animation */
+ private CanvasThread thread;
+
+ public CanvasView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ // register our interest in hearing about changes to our surface
+ SurfaceHolder holder = getHolder();
+ holder.addCallback(this);
+
+ // create thread only; it's started in surfaceCreated()
+ thread = new CanvasThread(holder, context, new Handler() {
+ @Override
+ public void handleMessage(Message m) {
+ mStatusText.setVisibility(m.getData().getInt("viz"));
+ mStatusText.setText(m.getData().getString("text"));
+ }
+ });
+
+ setFocusable(true); // make sure we get key events
+ }
+
+ /**
+ * Fetches the animation thread corresponding to this LunarView.
+ *
+ * @return the animation thread
+ */
+ public CanvasThread getThread() {
+ return thread;
+ }
+
+ /**
+ * Standard window-focus override. Notice focus lost so we can pause on
+ * focus lost. e.g. user switches to take a call.
+ */
+ public void onWindowFocusChanged(boolean hasWindowFocus) {
+ if (!hasWindowFocus)
+ thread.pause();
+ }
+
+ /**
+ * Installs a pointer to the text view used for messages.
+ */
+ public void setTextView(TextView textView) {
+ mStatusText = textView;
+ }
+
+ /* Callback invoked when the surface dimensions change. */
+ public void surfaceChanged(SurfaceHolder holder, int format, int width,
+ int height) {
+ thread.setSurfaceSize(width, height);
+ }
+
+ /*
+ * Callback invoked when the Surface has been created and is ready to be
+ * used.
+ */
+ public void surfaceCreated(SurfaceHolder holder) {
+ // start the thread here so that we don't busy-wait in run()
+ // waiting for the surface to be created
+ thread.setRunning(true);
+ thread.start();
+ }
+
+ /*
+ * Callback invoked when the Surface has been destroyed. Thread needs to stop.
+ */
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ boolean retry = true;
+ thread.setRunning(false);
+ while (retry) {
+ try {
+ thread.join();
+ retry = false;
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+}