diff --git a/Published/ExaltedDiceDev/.classpath b/Published/ExaltedDiceDev/.classpath
new file mode 100755
index 0000000..207072c
--- /dev/null
+++ b/Published/ExaltedDiceDev/.classpath
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/Published/ExaltedDiceDev/.project b/Published/ExaltedDiceDev/.project
new file mode 100755
index 0000000..9075306
--- /dev/null
+++ b/Published/ExaltedDiceDev/.project
@@ -0,0 +1,33 @@
+
+
+ ExaltedDice
+
+
+
+
+
+ com.android.ide.eclipse.adt.ResourceManagerBuilder
+
+
+
+
+ com.android.ide.eclipse.adt.PreCompilerBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ com.android.ide.eclipse.adt.ApkBuilder
+
+
+
+
+
+ com.android.ide.eclipse.adt.AndroidNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/Published/ExaltedDiceDev/AndroidManifest.xml b/Published/ExaltedDiceDev/AndroidManifest.xml
new file mode 100755
index 0000000..c472203
--- /dev/null
+++ b/Published/ExaltedDiceDev/AndroidManifest.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Published/ExaltedDiceDev/Change Log.txt b/Published/ExaltedDiceDev/Change Log.txt
new file mode 100644
index 0000000..34bf642
--- /dev/null
+++ b/Published/ExaltedDiceDev/Change Log.txt
@@ -0,0 +1,40 @@
+Exalted Dice Change Log
+
+0.0.1
+0.0.2
+0.0.3
+0.0.4
+0.0.5
+
+0.0.6 V6
+-remodeled onClickListeners
+-remodeled onLongClickListeners
+
+0.0.7 V7
+-Got Listview working with 10 item history
+-removed old onClickListener methods
+-removed old onLongClickListeners
+-ads working with internet permisions
+-Menu with exit option
+
+0.0.8 v8
+-cleaned code for efficency
+-Fixed error checking method to check for a string containing no ints.
+-Fixed shake listener problem
+-First release version, full, and ad free
+-due to a G Market problem, package name switched from com.TwentyCodes.android.ExaltedDice to com.TwentyCode.android.ExaltedDice
+
+
+0.0.9 V9
+-compiled under 1.5
+-updated ads
+-added System.gc();
+-added stringbuffer to checkForErrors() and results()
+-added a dynamic rollHistory list array
+-added clear history menu option
+
+0.0.10
+-added rotaion methods
+-reformated the output string
+-added crash report
+-added roll again feature
\ No newline at end of file
diff --git a/Published/ExaltedDiceDev/bin/ExaltedDice.apk b/Published/ExaltedDiceDev/bin/ExaltedDice.apk
new file mode 100644
index 0000000..91f7283
Binary files /dev/null and b/Published/ExaltedDiceDev/bin/ExaltedDice.apk differ
diff --git a/Published/ExaltedDiceDev/bin/classes.dex b/Published/ExaltedDiceDev/bin/classes.dex
new file mode 100644
index 0000000..3b35e1a
Binary files /dev/null and b/Published/ExaltedDiceDev/bin/classes.dex differ
diff --git a/Published/ExaltedDiceDev/bin/resources.ap_ b/Published/ExaltedDiceDev/bin/resources.ap_
new file mode 100644
index 0000000..8956cde
Binary files /dev/null and b/Published/ExaltedDiceDev/bin/resources.ap_ differ
diff --git a/Published/ExaltedDiceDev/default.properties b/Published/ExaltedDiceDev/default.properties
new file mode 100755
index 0000000..a1ef8e9
--- /dev/null
+++ b/Published/ExaltedDiceDev/default.properties
@@ -0,0 +1,13 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Indicates whether an apk should be generated for each density.
+split.density=false
+# Project target.
+target=android-3
diff --git a/Published/ExaltedDiceDev/libs/admob-sdk-android.jar b/Published/ExaltedDiceDev/libs/admob-sdk-android.jar
new file mode 100644
index 0000000..e186671
Binary files /dev/null and b/Published/ExaltedDiceDev/libs/admob-sdk-android.jar differ
diff --git a/Published/ExaltedDiceDev/res/drawable/icon.png b/Published/ExaltedDiceDev/res/drawable/icon.png
new file mode 100644
index 0000000..b101000
Binary files /dev/null and b/Published/ExaltedDiceDev/res/drawable/icon.png differ
diff --git a/Published/ExaltedDiceDev/res/layout/list_row.xml b/Published/ExaltedDiceDev/res/layout/list_row.xml
new file mode 100755
index 0000000..b39b66e
--- /dev/null
+++ b/Published/ExaltedDiceDev/res/layout/list_row.xml
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/Published/ExaltedDiceDev/res/layout/main.xml b/Published/ExaltedDiceDev/res/layout/main.xml
new file mode 100755
index 0000000..cb2fc98
--- /dev/null
+++ b/Published/ExaltedDiceDev/res/layout/main.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Published/ExaltedDiceDev/res/values/array.xml b/Published/ExaltedDiceDev/res/values/array.xml
new file mode 100644
index 0000000..64e6bc4
--- /dev/null
+++ b/Published/ExaltedDiceDev/res/values/array.xml
@@ -0,0 +1,8 @@
+
+
+- Welcome to ExaltedDice!
+- Press the - button to lower your dice count by 1, or long press the - button to lower dice count by 10
- Press the + button to raise dice count by 1 of long press + to raise dice count by 10.
- When you press Roll, Your Results Will Be Displayed Here
+
+
+
+
diff --git a/Published/ExaltedDiceDev/res/values/attrs.xml b/Published/ExaltedDiceDev/res/values/attrs.xml
new file mode 100644
index 0000000..68a68fc
--- /dev/null
+++ b/Published/ExaltedDiceDev/res/values/attrs.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Published/ExaltedDiceDev/res/values/strings.xml b/Published/ExaltedDiceDev/res/values/strings.xml
new file mode 100755
index 0000000..eec08d3
--- /dev/null
+++ b/Published/ExaltedDiceDev/res/values/strings.xml
@@ -0,0 +1,12 @@
+
+
+
+ Exalted Dice
+
+Rolled:
+
+
+
+
+twentycodes@gmail.com
+
diff --git a/Published/ExaltedDiceDev/src/com/TwentyCode/android/ExaltedDice/ExaltedDice.java b/Published/ExaltedDiceDev/src/com/TwentyCode/android/ExaltedDice/ExaltedDice.java
new file mode 100755
index 0000000..be2ce61
--- /dev/null
+++ b/Published/ExaltedDiceDev/src/com/TwentyCode/android/ExaltedDice/ExaltedDice.java
@@ -0,0 +1,734 @@
+package com.TwentyCode.android.ExaltedDice;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.os.Vibrator;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+import android.widget.AdapterView.OnItemClickListener;
+
+public class ExaltedDice extends Activity implements OnClickListener, OnLongClickListener, OnItemClickListener {
+
+ // view variables
+ private TextView dice;
+ private ListView listview;
+
+ // exalted dice variables
+ private int intSuccesses;
+ public int intDice;
+
+ private ArrayList rollHistory = new ArrayList();
+ private ArrayList rolled = new ArrayList();
+
+ /**
+ * tag for LogCat
+ */
+ private static final String tag = "ExaltedDice";
+
+ /**
+ * set view id's
+ */
+ private final int ADD_DICE = R.id.up;
+ private final int SUB_DICE = R.id.down;
+ private final int ROLL_DICE = R.id.roll;
+
+ /**
+ * menu options
+ */
+ private static final int MENU_QUIT = Menu.FIRST;
+ private static final int MENU_CLEAR = Menu.FIRST + 1;
+
+ protected PostMortemReportExceptionHandler mDamageReport = new PostMortemReportExceptionHandler(this);
+
+ /**
+ * adds one dice
+ *
+ * @author ricky barrette 3-27-2010
+ */
+ public void addDiceRolled() {
+ Log.i(tag, " addDiceRolled()");
+
+ // vibrate for 50 milliseconds
+ vibrate(50);
+
+ /**
+ * get string from dice textfield it convert it into int, while checking
+ * for user input errors
+ */
+ intDice = checkForErrors((dice.getText()).toString());
+
+ // add 1 dice
+ intDice = moreDice(intDice, 1);
+
+ // set Dice textfield to finDice
+ dice.setText("" + intDice);
+ System.gc();
+ }
+
+ /**
+ * add 10 dice 3-27-2010
+ *
+ * @author ricky barrette
+ */
+ public void addDiceRolledonLongClick() {
+ Log.i(tag, "addDiceRolledonLongClick()");
+
+ // vibrate for 75 milliseconds
+ vibrate(75);
+
+ /**
+ * get string from dice textfield it convert it into int, while checking
+ * for user input errors
+ */
+ intDice = checkForErrors((dice.getText()).toString());
+
+ // add 10 dice
+ intDice = moreDice(intDice, 10);
+
+ // set Dice textfield to finDice
+ dice.setText("" + intDice);
+ System.gc();
+ }
+
+
+ /**
+ * checks for the following errors:
+ *
+ * checks string if it is blank, if so changes string to "1"
+ *
+ * look at each char in string individually to see if int or not if the char
+ * is an in add it to stringDice, example: a string of "1.2-3" would result
+ * in a stringDice of "123"
+ *
+ * also if there are any zeros preceding an int, they will be removed
+ * example: a string of "000102" would result in a stringDice of "102"
+ *
+ * if there are any typos removed, use toast to inform the user that we
+ * assumed that when they typed "0001.2-3" they meant to type "123"
+ *
+ * limits stringDice to 3 chars (limiting the number of dice to 999) if
+ * stringDice is longer than 3 chars, it is changed to "1" also toast is
+ * displayed to inform user of the 999 dice rule.
+ *
+ * @param String
+ * string
+ * @return int numDice
+ * @author ricky barrette
+ */
+ public int checkForErrors(String string) {
+ Log.i(tag, "checkForErrors()");
+
+ int numDice = 0;
+ char charDice;
+ StringBuffer stringDice = new StringBuffer();
+ boolean errors = false;
+ boolean zeroCheck = true;
+ boolean isNumber = false;
+
+ /**
+ * if textField is left blank, change value to 1
+ */
+ if (string.length() == 0)
+ string += "" + 1;
+
+ /**
+ * look at each char in string individually to see if int or not if the
+ * char is an in add it to stringDice, example: a string of "1.2-3"
+ * would result in a stringDice of "123"
+ *
+ * also if there are any zeros preceding an int, they also will be
+ * removed example: a string of "00-01.02" would result in a stringDice
+ * of "102"
+ */
+ for (int i = 0; i < string.length(); i++) {
+ // get the char
+ charDice = string.charAt(i);
+
+ /**
+ * try to parse the char, to see it it is an int or not.
+ */
+ try {
+
+ /**
+ * we are going to borrow numDice instead of creating another
+ * addressing space
+ */
+
+ numDice = Integer.parseInt(Character.toString(charDice));
+
+ // -------------------------------------------------------------------------------------
+
+ /**
+ * zero check to remove any zeros preceding an int value. true =
+ * zero check on, false = zero check off
+ */
+ if (zeroCheck == true) {
+ if (numDice != 0) {
+ zeroCheck = false;
+ isNumber = true;
+ stringDice.append(numDice);
+ }
+ } else
+ stringDice.append(numDice);
+
+ } catch (NumberFormatException nFE) {
+ errors = true;
+ }
+
+ }
+
+ /**
+ * notify user if there were no ints
+ */
+ if (isNumber == false) {
+ toastLong("You inputed: \" "
+ + string
+ + " \", which contains no numbers, we will roll one dice for you.");
+ stringDice.append(1);
+ /**
+ * prevent error message from displaying
+ */
+ errors = false;
+ }
+
+ /**
+ * notify user if there were typos
+ */
+ if (errors == true)
+ toastLong("You inputed: \" " + string
+ + " \", we are assuming you meant: "
+ + stringDice.toString());
+
+ // -----------------------------------------------------------------------------------------
+
+ /**
+ * limit number to 999
+ */
+
+ if (stringDice.length() > 3) {
+
+ toastLong("Sorry, I can not roll " + stringDice
+ + " dice. Try Rolling Between 1 - 999 dice.");
+
+ /**
+ * set number of dice to 1
+ */
+ numDice = 1;
+
+ } else
+ numDice = Integer.parseInt(stringDice.toString());
+
+ stringDice = null;
+ System.gc();
+ return numDice;
+ }
+
+ /**
+ * clears the rollHistory List array and refreshes the listview
+ *
+ * @author ricky barrette
+ */
+ private void clearHistory() {
+ rollHistory.clear();
+ rolled.clear();
+ listview.setAdapter(new ArrayAdapter(this, R.layout.list_row, rollHistory));
+ }
+
+ /**
+ * Lower Dice Count By what ever lowerBy is, can't go lower than 1
+ *
+ * @param int number
+ * @return int number
+ * @author ricky barrette
+ */
+ public int lessDice(int number, int lowerBy) {
+ Log.i(tag, "lessDice()");
+
+ /**
+ * make sure we are not going to go negative
+ */
+ if (number <= lowerBy)
+ lowerBy = number - 1;
+
+ /**
+ * cant roll less than 1 dice
+ */
+ if (number > 1)
+ number = number - lowerBy;
+
+ System.gc();
+ return number;
+ }
+
+ /**
+ * Raise Dice Count By what ever raiseBy is, can't go higher than 999
+ *
+ * @param int number
+ * @return int number
+ * @author ricky barrette
+ */
+ public int moreDice(int number, int raiseBy) {
+ Log.i(tag, "moreDice()");
+
+ /**
+ * make sure we are not going to go higher than 999
+ */
+ if (number > 989)
+ if (raiseBy > (number - 989))
+ raiseBy = 999 - number;
+
+ /**
+ * Can not roll more than 999 dice
+ */
+ if (number < 999)
+ number = number + raiseBy;
+
+ System.gc();
+ return number;
+ }
+
+ /**
+ * also implemented OnClickListener
+ *
+ * @author ricky barrette 3-27-2010
+ * @author - WWPowers 3-26-2010
+ */
+ @Override
+ public void onClick(View v) {
+
+ if (v.getId() == ADD_DICE)
+ addDiceRolled();
+
+ if (v.getId() == SUB_DICE)
+ subtractDiceRolled();
+
+ if (v.getId() == ROLL_DICE)
+ rollDice();
+
+ }
+
+ /**
+ * Called when the activity is first created. starts gui and sets up buttons
+ *
+ * @author ricky barrette 3-27-2010
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ mDamageReport.run();
+ Thread.setDefaultUncaughtExceptionHandler(mDamageReport);
+
+ super.onCreate(savedInstanceState);
+ Log.i(tag, "onCreate()");
+ setContentView(R.layout.main);
+
+ /**
+ * TextViews
+ */
+ dice = (TextView) findViewById(R.id.dice);
+
+ /**
+ * ListViews
+ */
+ listview = (ListView) findViewById(R.id.list);
+
+ /**
+ * Buttons
+ */
+ Button btAddDice = (Button) findViewById(R.id.up);
+ Button btSubtractDice = (Button) findViewById(R.id.down);
+ Button btRollDice = (Button) findViewById(R.id.roll);
+
+ /**
+ * onClickListeners
+ */
+ btAddDice.setOnClickListener(this);
+ btSubtractDice.setOnClickListener(this);
+ btRollDice.setOnClickListener(this);
+ listview.setOnItemClickListener(this);
+
+ /**
+ * onLongClickListeners
+ */
+ btAddDice.setOnLongClickListener(this);
+ btSubtractDice.setOnLongClickListener(this);
+
+ /**
+ * shake Listener
+ */
+// ShakeListener mShaker = new ShakeListener(this);
+// mShaker.setOnShakeListener(new ShakeListener.OnShakeListener() {
+// public void onShake() {
+// rollDice();
+// }
+// });
+
+ /**
+ * hide keyboard
+ *
+ * works on the emulator
+ */
+ ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(dice.getWindowToken(), 0);
+
+ /**
+ * display hello message
+ */
+ listview.setAdapter(new ArrayAdapter(this, R.layout.list_row, getResources().getStringArray(R.array.hello_msg)));
+
+ System.gc();
+
+ }
+
+ /**
+ * creates a menu with a quit option
+ *
+ * @author WWPowers 3-27-2010
+ */
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add(1, MENU_CLEAR, 0, "Clear Roll History");
+ menu.add(1, MENU_QUIT, 0, "Quit");
+ return true;
+ }
+
+ /**
+ * rolls same amount of dice as previous roll
+ * @author ricky barrette
+ */
+ @Override
+ public void onItemClick(AdapterView> arg0, View arg1, int arg2, long arg3) {
+ if(rolled.size() != 0){
+ dice.setText("" + rolled.get(arg2));
+ rollDice();
+ }
+ }
+
+ /**
+ * also implemented OnLongClickListener
+ *
+ * @author ricky barrette 3-27-2010
+ * @param v
+ */
+ public boolean onLongClick(View v) {
+ if (v.getId() == ADD_DICE) {
+ addDiceRolledonLongClick();
+
+ } else if (v.getId() == SUB_DICE) {
+ subtractDiceRolledonLongClick();
+
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * handles menu selection
+ *
+ * @author WWPowers 3-27-2010
+ * @author ricky barrette 3-27-2010
+ */
+ public boolean onOptionsItemSelected(MenuItem item) {
+
+ switch (item.getItemId()) {
+ case MENU_QUIT:
+ quitDialog();
+ return true;
+ case MENU_CLEAR:
+ clearHistory();
+ return true;
+ }
+ return false;
+
+ }
+
+ /**
+ * pauses ShakeListener
+ */
+ @Override
+ public void onPause() {
+ Log.i(tag, "onPause()");
+ super.onPause();
+// ShakeListener mShaker = new ShakeListener(this);
+// mShaker.pause();
+ System.gc();
+ }
+
+ /**
+ * resorts application state after rotation
+ * @author ricky barrette
+ */
+ @Override
+ public void onRestoreInstanceState(Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ // Restore UI state from the savedInstanceState.
+ // This bundle has also been passed to onCreate.
+ rollHistory = savedInstanceState.getStringArrayList("roll_history");
+ dice.setText(savedInstanceState.getString("dice"));
+ rolled = savedInstanceState.getIntegerArrayList("rolled");
+ listview.setAdapter(new ArrayAdapter(this, R.layout.list_row, rollHistory));
+ }
+
+ /**
+ * resumes ShakeListener
+ */
+ @Override
+ public void onResume() {
+ Log.i(tag, "onResume()");
+ super.onResume();
+// ShakeListener mShaker = new ShakeListener(this);
+// mShaker.resume();
+ }
+
+ /**
+ * saves application state before rotatoin
+ * @author ricky barrette
+ */
+ @Override
+ public void onSaveInstanceState(Bundle savedInstanceState) {
+ // Save UI state changes to the savedInstanceState.
+ // This bundle will be passed to onCreate if the process is
+ // killed and restarted.
+ savedInstanceState.putStringArrayList("roll_history", rollHistory);
+ savedInstanceState.putString("dice", dice.getText().toString());
+ savedInstanceState.putIntegerArrayList("rolled", rolled);
+ super.onSaveInstanceState(savedInstanceState);
+ }
+
+ /**
+ * unregisters ShakeListener
+ *
+ * @author ricky barrette 3-26-2010
+ * @author WWPpwers 3-27-2010
+ */
+ @Override
+ public void onStop() {
+ Log.i(tag, "onStop()");
+ super.onStop();
+ System.gc();
+// ExaltedDice.this.finish();
+ }
+
+ /**
+ * displays a quit dialog
+ *
+ * @author ricky barrette 3-28-2010
+ * @author WWPowers 3-27-2010
+ */
+ public void quitDialog() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setMessage("Are you sure you want to quit?").setCancelable(
+ false).setPositiveButton("Yes",
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ ExaltedDice.this.finish();
+ }
+ }).setNegativeButton("No",
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+ builder.show();
+ }
+
+ /**
+ * returns a custom string containing dice rolls and number of successes
+ *
+ * @param int times
+ * @return String resultsString
+ * @author ricky barrette
+ */
+ public String results(int times) {
+ Log.i(tag, "results()");
+ StringBuffer resultsString = new StringBuffer();
+ resultsString.append("Rolled "+ times +" dice\n");
+
+ /**
+ * roll the dice
+ */
+ int[] roll = rollGen(times);
+
+ /**
+ * add number of successes to resultsString
+ */
+ resultsString.append("Successes: "+ successes(roll) +"\n");
+
+ resultsString.append("Rolled: ");
+ /**
+ * add rolled dice results to resultsString
+ */
+ for (int i = 0; i < roll.length; i++) {
+ resultsString.append(roll[i] + ", ");
+ }
+
+ System.gc();
+ return resultsString.toString();
+ }
+
+ /**
+ * Performs a dice roll
+ *
+ * @author ricky barrette
+ */
+ public void rollDice() {
+ // vibrate for 50 milliseconds
+ vibrate(50);
+
+ /**
+ * get string from dice textfield it convert it into int, while checking
+ * for user input errors
+ */
+ intDice = checkForErrors((dice.getText()).toString());
+
+ // set Dice textfield to finDice
+ dice.setText("" + intDice);
+
+ rolled.add(0, intDice);
+ rollHistory.add(0, results(intDice));
+
+ listview.setAdapter(new ArrayAdapter(this, R.layout.list_row, rollHistory));
+
+ System.gc();
+ }
+
+ /**
+ * generates an array containing 10 sided dice rolls
+ *
+ * @param int times
+ * @return int[] roll
+ * @author ricky barrette
+ */
+ public int[] rollGen(int times) {
+ Log.i(tag, "rollGen()" + times);
+ int[] roll = new int[times];
+ Random random = new Random();
+ for (int i = 0; i < times; i++) {
+ roll[i] = random.nextInt(10) + 1;
+ }
+ System.gc();
+ return roll;
+ }
+
+ /**
+ * subtracts one dice 3-27-2010
+ *
+ * @author ricky barrette
+ */
+ public void subtractDiceRolled() {
+ Log.i(tag, "subtractDice()");
+ ;
+
+ // vibrate for 50 milliseconds
+ vibrate(50);
+
+ /**
+ * get string from dice textfield it convert it into int, while checking
+ * for user input errors
+ */
+ intDice = checkForErrors((dice.getText()).toString());
+
+ // subtract 1 dice
+ intDice = lessDice(intDice, 1);
+
+ // set Dice textfield to finDice
+ dice.setText("" + intDice);
+ System.gc();
+ }
+
+ /**
+ * subtracts 10 dice
+ *
+ * @author ricky barrette
+ */
+ public void subtractDiceRolledonLongClick() {
+ Log.i(tag, "subtractDiceonLongClick()");
+
+ // vibrate for 75 milliseconds
+ vibrate(75);
+
+ /**
+ * get string from dice textfield it convert it into int, while checking
+ * for user input errors
+ */
+ intDice = checkForErrors((dice.getText()).toString());
+
+ // subtract 10 dice
+ intDice = lessDice(intDice, 10);
+
+ // set Dice textfield to finDice
+ dice.setText("" + intDice);
+ System.gc();
+
+ }
+
+ /**
+ * counts each dice roll that is greater than or equal to 7 as a success. 10
+ * gets another success (for a total of 2)
+ *
+ * @param int[] roll
+ * @return int successes
+ * @author ricky barrette
+ */
+ public int successes(int[] roll) {
+ Log.i(tag, "successes()");
+ intSuccesses = 0;
+ for (int i = 0; i < roll.length; i++) {
+ if (roll[i] >= 7)
+ intSuccesses++;
+ if (roll[i] == 10)
+ intSuccesses++;
+ }
+ System.gc();
+ return intSuccesses;
+ }
+
+ /**
+ * displays toast message with a long duration
+ *
+ * @param msg
+ * @author ricky barrette 3-26-2010
+ * @author WWPowers 3-26-2010
+ */
+ public void toastLong(CharSequence msg) {
+ Log.i(tag, "toastLong()");
+ Toast toast = Toast.makeText(this, msg, Toast.LENGTH_LONG);
+ toast.show();
+ }
+
+ /**
+ * starts Vibrator service and then vibrates for x milliseconds
+ *
+ * @param Long
+ * milliseconds
+ * @author ricky barrette
+ */
+ public void vibrate(long milliseconds) {
+ Log.i(tag, "vibrate() for " + milliseconds);
+ /**
+ * start vibrator service
+ */
+ Vibrator vib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
+
+ /**
+ * Vibrate for x milliseconds
+ */
+ vib.vibrate(milliseconds);
+ }
+
+}
\ No newline at end of file
diff --git a/Published/ExaltedDiceDev/src/com/TwentyCode/android/ExaltedDice/PostMortemReportExceptionHandler.java b/Published/ExaltedDiceDev/src/com/TwentyCode/android/ExaltedDice/PostMortemReportExceptionHandler.java
new file mode 100644
index 0000000..1946fa2
--- /dev/null
+++ b/Published/ExaltedDiceDev/src/com/TwentyCode/android/ExaltedDice/PostMortemReportExceptionHandler.java
@@ -0,0 +1,190 @@
+package com.TwentyCode.android.ExaltedDice;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.lang.reflect.Field;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
+
+public class PostMortemReportExceptionHandler implements UncaughtExceptionHandler, Runnable {
+ public static final String ExceptionReportFilename = "postmortem.trace";
+
+ private static final String MSG_SUBJECT_TAG = "Exception Report"; //"app title + this tag" = email subject
+ private static final String MSG_SENDTO = "twentycodes@gmail.com"; //email will be sent to this account
+ //the following may be something you wish to consider localizing
+ private static final String MSG_BODY = "Just click send to help make this application better. "+
+ "No personal information is being sent (you can check by reading the rest of the email).";
+
+ private Thread.UncaughtExceptionHandler mDefaultUEH;
+ private Activity mApp = null;
+
+ /*
+ * Constructor
+ */
+ public PostMortemReportExceptionHandler(Activity aApp) {
+ mDefaultUEH = Thread.getDefaultUncaughtExceptionHandler();
+ mApp = aApp;
+ }
+
+
+ @Override
+ public void uncaughtException(Thread t, Throwable e) {
+ submit(e);
+ //do not forget to pass this exception through up the chain
+ mDefaultUEH.uncaughtException(t,e);
+ }
+
+ public String getDebugReport(Throwable aException) {
+// NumberFormat theFormatter = new DecimalFormat("#0.");
+ //stack trace
+ StackTraceElement[] theStackTrace = aException.getStackTrace();
+
+ StringBuffer report = new StringBuffer();
+
+ report.append("--------- Application ---------\n\n");
+
+ report.append(mApp.getPackageName()+" generated the following exception:\n\n");
+
+ report.append(aException.toString() + "\n\n");
+
+ report.append("-------------------------------\n\n");
+
+ report.append("--------- Stack trace ---------\n\n");
+ for (int i = 0; i < theStackTrace.length; i++) {
+ report.append(" " + theStackTrace[i].toString() + "\n");
+ }
+ report.append("-------------------------------\n\n");
+
+ //app environment
+ PackageManager pm = mApp.getPackageManager();
+ PackageInfo pi;
+ try {
+ pi = pm.getPackageInfo(mApp.getPackageName(), 0);
+ } catch (NameNotFoundException eNnf) {
+ //doubt this will ever run since we want info about our own package
+ pi = new PackageInfo();
+ pi.versionName = "unknown";
+ pi.versionCode = 69;
+ }
+
+ Date theDate = new Date();
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd_HH.mm.ss_zzz");
+ report.append("-------- Environment --------\n");
+ report.append("Time\t="+sdf.format(theDate)+"\n");
+ report.append("Device\t="+Build.FINGERPRINT+"\n");
+ try {
+ Field theMfrField = Build.class.getField("MANUFACTURER");
+ report.append("Make\t="+theMfrField.get(null)+"\n");
+ } catch (SecurityException e) {
+ } catch (NoSuchFieldException e) {
+ } catch (IllegalArgumentException e) {
+ } catch (IllegalAccessException e) {
+ }
+ report.append("Device: " + Build.DEVICE + "\n");
+ report.append("Brand: " + Build.BRAND + "\n");
+ report.append("Model: "+Build.MODEL+"\n");
+ report.append("Product: "+Build.PRODUCT+"\n");
+ report.append("App:\t "+mApp.getPackageName()+", version "+pi.versionName+" (build "+pi.versionCode+")\n");
+ report.append("Locale: "+mApp.getResources().getConfiguration().locale.getDisplayName()+"\n");
+ report.append("-----------------------------\n\n");
+
+ report.append("--------- Firmware ---------\n\n");
+ report.append("SDK: " + Build.VERSION.SDK + "\n");
+ report.append("Release: " + Build.VERSION.RELEASE + "\n");
+ report.append("Incremental: " + Build.VERSION.INCREMENTAL + "\n");
+ report.append("Build Id: " + Build.ID + "\n");
+ report.append("-------------------------------\n\n");
+
+ // If the exception was thrown in a background thread inside
+ // AsyncTask, then the actual exception can be found with getCause
+ report.append("--------- Cause ---------\n\n");
+ Throwable cause = aException.getCause();
+ if (cause != null) {
+ report.append(cause.toString() + "\n\n");
+ theStackTrace = cause.getStackTrace();
+ for (int i = 0; i < theStackTrace.length; i++) {
+ report.append(" " + theStackTrace[i].toString() + "\n");
+ }
+ }
+ report.append("-------------------------------\n\n");
+
+ report.append("END REPORT");
+
+ return report.toString();
+ }
+
+ protected void saveDebugReport(String aReport) {
+ //save report to file
+ try {
+ FileOutputStream theFile = mApp.openFileOutput(ExceptionReportFilename, Context.MODE_PRIVATE);
+ theFile.write(aReport.getBytes());
+ theFile.close();
+ } catch(IOException ioe) {
+ //error during error report needs to be ignored, do not wish to start infinite loop
+ }
+ }
+
+ public void sendDebugReportToAuthor() {
+ String theLine = "";
+ StringBuffer theTrace = new StringBuffer();
+ try {
+ BufferedReader theReader = new BufferedReader(new InputStreamReader(mApp.openFileInput(ExceptionReportFilename)));
+ while ((theLine = theReader.readLine())!=null) {
+ theTrace.append(theLine+"\n");
+ }
+ if (sendDebugReportToAuthor(theTrace.toString())) {
+ mApp.deleteFile(ExceptionReportFilename);
+ }
+ } catch (FileNotFoundException eFnf) {
+ // nothing to do
+ } catch(IOException eIo) {
+ // not going to report
+ }
+ System.gc();
+ }
+
+ public Boolean sendDebugReportToAuthor(String aReport) {
+ if (aReport!=null) {
+ Intent theIntent = new Intent(Intent.ACTION_SEND);
+ String theSubject = mApp.getTitle()+" "+MSG_SUBJECT_TAG;
+ String theBody = "\n"+MSG_BODY+"\n\n"+aReport+"\n\n";
+ theIntent.putExtra(Intent.EXTRA_EMAIL,new String[] {MSG_SENDTO});
+ theIntent.putExtra(Intent.EXTRA_TEXT, theBody);
+ theIntent.putExtra(Intent.EXTRA_SUBJECT, theSubject);
+ theIntent.setType("message/rfc822");
+ Boolean hasSendRecipients = (mApp.getPackageManager().queryIntentActivities(theIntent,0).size()>0);
+ if (hasSendRecipients) {
+ mApp.startActivity(theIntent);
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return true;
+ }
+ }
+
+ @Override
+ public void run() {
+ sendDebugReportToAuthor();
+ }
+
+ public void submit(Throwable e) {
+ String theErrReport = getDebugReport(e);
+ saveDebugReport(theErrReport);
+ //try to send file contents via email (need to do so via the UI thread)
+ mApp.runOnUiThread(this);
+ }
+}
diff --git a/Published/ExaltedDiceDev/src/com/TwentyCode/android/ExaltedDice/ShakeListener.java b/Published/ExaltedDiceDev/src/com/TwentyCode/android/ExaltedDice/ShakeListener.java
new file mode 100644
index 0000000..f2a2615
--- /dev/null
+++ b/Published/ExaltedDiceDev/src/com/TwentyCode/android/ExaltedDice/ShakeListener.java
@@ -0,0 +1,98 @@
+package com.TwentyCode.android.ExaltedDice;
+
+/* The following code was written by Matthew Wiggins
+ * and is released under the APACHE 2.0 license
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+import android.hardware.SensorListener;
+import android.hardware.SensorManager;
+import android.content.Context;
+import java.lang.UnsupportedOperationException;
+
+@SuppressWarnings("deprecation")
+public class ShakeListener implements SensorListener
+{
+ private static final int FORCE_THRESHOLD = 350;
+ private static final int TIME_THRESHOLD = 100;
+ private static final int SHAKE_TIMEOUT = 500;
+ private static final int SHAKE_DURATION = 1000;
+ private static final int SHAKE_COUNT = 3;
+
+ private SensorManager mSensorMgr;
+ private float mLastX=-1.0f, mLastY=-1.0f, mLastZ=-1.0f;
+ private long mLastTime;
+ private OnShakeListener mShakeListener;
+ private Context mContext;
+ private int mShakeCount = 0;
+ private long mLastShake;
+ private long mLastForce;
+
+ public interface OnShakeListener
+ {
+ public void onShake();
+ }
+
+ public ShakeListener(Context context)
+ {
+ mContext = context;
+ resume();
+ }
+
+ public void setOnShakeListener(OnShakeListener listener)
+ {
+ mShakeListener = listener;
+ }
+
+ public void resume() {
+ mSensorMgr = (SensorManager)mContext.getSystemService(Context.SENSOR_SERVICE);
+ if (mSensorMgr == null) {
+ throw new UnsupportedOperationException("Sensors not supported");
+ }
+ boolean supported = mSensorMgr.registerListener(this, SensorManager.SENSOR_ACCELEROMETER, SensorManager.SENSOR_DELAY_GAME);
+ if (!supported) {
+ mSensorMgr.unregisterListener(this, SensorManager.SENSOR_ACCELEROMETER);
+ throw new UnsupportedOperationException("Accelerometer not supported");
+ }
+ }
+
+ public void pause() {
+ if (mSensorMgr != null) {
+ mSensorMgr.unregisterListener(this, SensorManager.SENSOR_ACCELEROMETER);
+ mSensorMgr = null;
+ }
+ }
+
+ public void onAccuracyChanged(int sensor, int accuracy) { }
+
+ public void onSensorChanged(int sensor, float[] values)
+ {
+ if (sensor != SensorManager.SENSOR_ACCELEROMETER) return;
+ long now = System.currentTimeMillis();
+
+ if ((now - mLastForce) > SHAKE_TIMEOUT) {
+ mShakeCount = 0;
+ }
+
+ if ((now - mLastTime) > TIME_THRESHOLD) {
+ long diff = now - mLastTime;
+ float speed = Math.abs(values[SensorManager.DATA_X] + values[SensorManager.DATA_Y] + values[SensorManager.DATA_Z] - mLastX - mLastY - mLastZ) / diff * 10000;
+ if (speed > FORCE_THRESHOLD) {
+ if ((++mShakeCount >= SHAKE_COUNT) && (now - mLastShake > SHAKE_DURATION)) {
+ mLastShake = now;
+ mShakeCount = 0;
+ if (mShakeListener != null) {
+ mShakeListener.onShake();
+ }
+ }
+ mLastForce = now;
+ }
+ mLastTime = now;
+ mLastX = values[SensorManager.DATA_X];
+ mLastY = values[SensorManager.DATA_Y];
+ mLastZ = values[SensorManager.DATA_Z];
+ }
+ }
+
+}