diff --git a/Makefile b/Makefile
index 3070ed2..6849f43 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,8 @@
install: bin/PenaltyTimer-debug.apk
adb install -r $<
+
+clean:
+ ant clean
-bin/PenaltyTimer-debug.apk:
+bin/PenaltyTimer-debug.apk: src/org/woozle/penaltytimer/* res/*/*
ant debug
diff --git a/res/layout/main.xml b/res/layout/main.xml
index b34013a..6b7bf81 100644
--- a/res/layout/main.xml
+++ b/res/layout/main.xml
@@ -1,29 +1,20 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:keepScreenOn="true">
+
+
+
+
+
+
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index fd06781..1156eb3 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1,5 +1,5 @@
- PenaltyTimer
+ WFTDA penalty timer
Boom
diff --git a/src/org/woozle/penaltytimer/JammerButton.java b/src/org/woozle/penaltytimer/JammerButton.java
new file mode 100644
index 0000000..3c3bffb
--- /dev/null
+++ b/src/org/woozle/penaltytimer/JammerButton.java
@@ -0,0 +1,61 @@
+package org.woozle.penaltytimer;
+
+import android.content.Context;
+import android.view.View;
+import android.view.View.*;
+
+public class JammerButton extends TimerButton
+ implements OnClickListener, OnLongClickListener
+{
+ public boolean penalized = false;
+ private JammerButton peer;
+
+ public JammerButton(Context context) {
+ super(context);
+ }
+
+ public String str(long remain, boolean tenths) {
+ return bstr(remain, tenths) + " J";
+ }
+
+ public void setOther(JammerButton other) {
+ peer = other;
+ }
+
+ public void expireHook() {
+ penalized = true;
+ }
+
+ public void onClick(View v) {
+ if (! paused) {
+ long orem = peer.remaining();
+
+ if ((! running) && (! penalized) && (orem > 0)) {
+ orem -= 60000;
+ if (orem < 0) {
+ set(-orem);
+ start();
+ peer.set(0);
+ peer.stop();
+ peer.penalized = true;
+ } else {
+ peer.set(orem);
+ }
+ } else {
+ super.onClick(v);
+ }
+ }
+ }
+
+ public void pause() {
+ super.pause();
+ penalized = false;
+ }
+
+ public void pulse(long now) {
+ if ((! running) && (! peer.running)) {
+ penalized = false;
+ }
+ super.pulse(now);
+ }
+}
diff --git a/src/org/woozle/penaltytimer/PenaltyTimer.java b/src/org/woozle/penaltytimer/PenaltyTimer.java
index c43324f..43d041d 100644
--- a/src/org/woozle/penaltytimer/PenaltyTimer.java
+++ b/src/org/woozle/penaltytimer/PenaltyTimer.java
@@ -3,18 +3,127 @@ package org.woozle.penaltytimer;
import android.app.Activity;
import android.view.View;
import android.widget.Toast;
-import android.os.Bundle;
+import android.widget.*;
+import android.os.*;
+import java.lang.Math;
+import java.util.*;
+
public class PenaltyTimer extends Activity
{
+ private Handler mHandler = new Handler();
+ private JammerButton[] jbs = new JammerButton[2];
+ private TimerButton[] tbs = new TimerButton[8];
+
+ private Runnable pulse = new Runnable() {
+ public void run() {
+ long now = SystemClock.uptimeMillis();
+ pulse(now);
+
+ mHandler.postAtTime(this, now + 100);
+ }
+ };
+
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
+ Persistence p = (Persistence)getLastNonConfigurationInstance();
+ TableLayout tl;
+ View top;
+
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
+ tl = (TableLayout)findViewById(R.id.mainTable);
+ top = findViewById(R.id.main);
+
+ for (int i = 0; i < 4; i += 1) {
+ TableRow tr = new TableRow(this);
+
+ tl.addView(tr, i);
+
+ for (int j = 0; j < 2; j += 1) {
+ TimerButton b;
+ TextView v;
+
+ if (i == 0) {
+ JammerButton jb = new JammerButton(this);
+
+ if (p != null) {
+ jb.penalized = p.penalized[j];
+ }
+ jbs[j] = jb;
+ b = jb;
+ } else {
+ b = new TimerButton(this);
+ }
+
+ if (p != null) {
+ b.set(p.remain[i*2 + j]);
+ if (p.paused) {
+ b.pause();
+ } else {
+ b.resume();
+ }
+ }
+
+ v = b.getButton();
+ tr.addView(v);
+
+ tbs[i*2 + j] = b;
+ }
+ }
+
+ jbs[0].setOther(jbs[1]);
+ jbs[1].setOther(jbs[0]);
+
+ mHandler.postAtTime(pulse, 100);
}
- public void onButtonClicked(View v) {
- Toast.makeText(this, "Button clicked", Toast.LENGTH_SHORT).show();
+ class Persistence {
+ public long[] remain = new long[8];
+ public boolean paused = false;
+ public boolean[] penalized = new boolean[2];
+ }
+
+
+ public Object onRetainNonConfigurationInstance() {
+ Persistence p = new Persistence();
+ int i;
+
+ for (i = 0; i < 8; i += 1) {
+ TimerButton b = tbs[i];
+
+ if (b.paused) {
+ p.paused = true;
+ }
+ p.remain[i] = b.remaining();
+ if (i < 2) {
+ JammerButton j = (JammerButton)b;
+
+ p.penalized[i] = j.penalized;
+ }
+ }
+
+ return p;
+ }
+
+ private void pulse(long now) {
+ for (int i = 0; i < 8; i += 1) {
+ tbs[i].pulse(now);
+ }
+ }
+
+
+ public void pauseButton(View v) {
+ for (int i = 0; i < 8; i += 1) {
+ tbs[i].pause();
+ }
+ }
+
+ public void resumeButton(View v) {
+ for (int i = 0; i < 8; i += 1) {
+ tbs[i].resume();
+ }
}
}
+
diff --git a/src/org/woozle/penaltytimer/TimerButton.java b/src/org/woozle/penaltytimer/TimerButton.java
new file mode 100644
index 0000000..b0cebea
--- /dev/null
+++ b/src/org/woozle/penaltytimer/TimerButton.java
@@ -0,0 +1,154 @@
+package org.woozle.penaltytimer;
+
+import android.content.Context;
+import android.widget.*;
+import android.view.View;
+import android.view.View.*;
+import android.view.Gravity;
+import android.graphics.Color;
+import android.os.SystemClock;
+import java.util.*;
+
+public class TimerButton
+ implements OnClickListener, OnLongClickListener
+{
+ Button b;
+ Timer updateTimer;
+ long startTime = 0;
+ long duration = 0;
+ public boolean running = false;
+ public boolean paused = false;
+ long now;
+
+ static int releaseColor = Color.rgb(0, 127, 0);
+ static int standColor = Color.rgb(127, 127, 0);
+ static int normalColor = Color.BLACK;
+ static int pauseColor = Color.GRAY;
+
+ public TimerButton(Context context) {
+ b = new Button(context);
+
+ b.setText("--:--");
+ b.setTextSize(24);
+ b.setGravity(Gravity.CENTER);
+ updateTimer = new Timer();
+ b.setOnClickListener(this);
+ b.setOnLongClickListener(this);
+ }
+
+ public long remaining() {
+ if (running) {
+ return duration - (now - startTime);
+ } else {
+ return duration;
+ }
+ }
+
+ public String bstr(long remain, boolean tenths) {
+ long min = Math.abs(remain / 60000);
+ long sec = Math.abs(remain / 1000) % 60;
+ String ret;
+
+ // Has the timer run out?
+ if (remain <= 0) {
+ return "--:--";
+ }
+
+
+ ret = min + ":";
+ if (sec < 10) {
+ ret += "0";
+ }
+ ret += sec;
+ if (tenths) {
+ ret += ".";
+ ret += Math.abs(remain / 100) % 10;
+ }
+
+ return ret;
+ }
+
+ public String str(long remain, boolean tenths) {
+ return bstr(remain, tenths) + " B";
+ }
+
+ public void set(long t) {
+ startTime = now;
+ duration = t;
+ }
+
+ public void start() {
+ if (! running) {
+ startTime = now;
+ }
+ running = true;
+ }
+
+ public void stop() {
+ if (running) {
+ duration = remaining();
+ }
+ running = false;
+ }
+
+ public TextView getButton() {
+ return b;
+ }
+
+ public void expireHook() {
+ }
+
+ public void update() {
+ long r = remaining();
+
+ if ((duration > 0) && (r <= 0)) {
+ duration = 0;
+ running = false;
+ expireHook();
+ }
+
+ if (paused) {
+ b.setTextColor(pauseColor);
+ } else if (r <= 0) {
+ b.setTextColor(releaseColor);
+ } else if (r < 10000) {
+ b.setTextColor(standColor);
+ } else {
+ b.setTextColor(normalColor);
+ }
+ b.setText(str(r, true));
+ }
+
+ public void pulse(long now) {
+ this.now = now;
+ update();
+ }
+
+ public void onClick(View v) {
+ if (paused) {
+ return;
+ }
+ set((remaining() + 60000) % (60 * 8 * 1000));
+ start();
+ }
+
+ public boolean onLongClick(View v) {
+ set(0);
+ stop();
+ expireHook();
+ return true;
+ }
+
+ public void pause() {
+ paused = true;
+ stop();
+ }
+
+ public void resume() {
+ paused = false;
+ if (remaining() > 0) {
+ start();
+ }
+ }
+}
+