Files
exalted_dice/ExaltedDice/src/com/TwentyCode/android/ExaltedDice/ExaltedDice.java
Ricky Barrette c2ef86ea54 Fixed java.lang.IllegalStateException thrown by
RollHistortDatabaseAdapter

RollHistortDatabaseAdapter only updates the roll count in
notifyDataSetChanged()

re-added roll thread

added boolean isRolling to prevent multiple rolls at the same time
Change-Id: I47fea7af989d0b2239ad8c5082649022836a2263
Signed-off-by: Ricky Barrette <rickbarrette@gmail.com>
2012-02-10 00:42:54 -05:00

512 lines
14 KiB
Java
Executable File

package com.TwentyCode.android.ExaltedDice;
import java.util.Random;
import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.DatabaseUtils;
import android.os.Bundle;
import android.os.Vibrator;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.NumberPicker;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.TwentyCodes.android.exception.ExceptionHandler;
public class ExaltedDice extends Activity implements OnClickListener, OnItemClickListener, DatabaseListener {
private static final int MENU_QUIT = Menu.FIRST;
private static final int MENU_CLEAR = Menu.FIRST + 1;
private static final String TAG = "ExaltedDice";
public static final String KEY_GAME_NAME = "game_name";
public static final String KEY_GAME_ID = "game_id";
private static final int DELETE = 0;
private static final int SETTINGS = Menu.FIRST + 2;
private String[] mDiceValues;
private ListView mListView;
private NumberPicker mNumberPicker;
private NumberPicker mDPicker;
private Database mDb;
private String mGameName;
private long mGameId;
private RollHistoryDatabaseAdapter mListAdapter;
private SharedPreferences mSettings;
private String[] mModValues;
private NumberPicker mModPicker;
private ProgressBar mRollProgress;
private View mRollButton;
private boolean isRolling = false;
/**
* Applies the presets from the provided roll
* @param id of the roll
* @author ricky barrette
*/
private void applyRollPresets(long id) {
ContentValues roll = mDb.getGameHistoryInfo(mGameName, (int) (id));
try{
mNumberPicker.setValue(roll.getAsInteger(Database.KEY_NUMBER));
mDPicker.setValue(parseD(roll.getAsString(Database.KEY_D_TYPE)));
mModPicker.setValue(parseMod(roll.getAsString(Database.KEY_MOD).replace("'", "")));
} catch(NullPointerException e){
mModPicker.setValue(parseMod("+0"));
}
}
/**
* also implemented OnClickListener
*
* @author ricky barrette 3-27-2010
* @author - WWPowers 3-26-2010
*/
@Override
public void onClick(View v){
switch(v.getId()){
case R.id.roll_button:
rollDice();
break;
}
}
/**
* (non-Javadoc)
* @see android.app.Activity#onContextItemSelected(android.view.MenuItem)
*/
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
switch(item.getItemId()){
case DELETE:
mDb.deleteRoll(mGameId, info.id+1);
break;
}
return super.onContextItemSelected(item);
}
/**
* 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) {
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(this));
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate()");
setContentView(R.layout.main);
/*
* The following is for api 11 and up
*/
if(Integer.valueOf(android.os.Build.VERSION.SDK) > 11){
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
}
Intent i = this.getIntent();
if(i != null)
if(i.hasExtra(KEY_GAME_NAME)){
mGameName = i.getStringExtra(KEY_GAME_NAME);
mGameId = i.getLongExtra(KEY_GAME_ID, -1);
this.setTitle(mGameName);
}
mSettings = getSharedPreferences(Settings.SETTINGS, Context.MODE_WORLD_WRITEABLE);
mDiceValues = getResources().getStringArray(R.array.dice_types);
mModValues = getResources().getStringArray(R.array.mods);
mListView = (ListView) findViewById(R.id.list);
mListView.setOnItemClickListener(this);
mListView.setStackFromBottom(true);
mDPicker = (NumberPicker) findViewById(R.id.d_Picker);
mDPicker.setMinValue(0);
mDPicker.setMaxValue(mDiceValues.length -1);
mDPicker.setDisplayedValues(mDiceValues);
mDPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
mNumberPicker = (NumberPicker) findViewById(R.id.number_Picker);
mNumberPicker.setMaxValue(999);
mNumberPicker.setMinValue(1);
mNumberPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
mModPicker = (NumberPicker) findViewById(R.id.mod_Picker);
mModPicker.setMinValue(0);
mModPicker.setMaxValue(mModValues.length -1);
mModPicker.setDisplayedValues(mModValues);
mModPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
mRollProgress = (ProgressBar) findViewById(R.id.roll_progress);
mRollButton = findViewById(R.id.roll_button);
mRollButton.setOnClickListener(this);
}
/**
* (non-Javadoc)
* @see android.app.Activity#onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo)
*/
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
menu.add(0, DELETE, Menu.FIRST, R.string.delete);
super.onCreateContextMenu(menu, v, menuInfo);
}
/**
* creates a menu with a quit option
*
* @author WWPowers 3-27-2010
*/
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(1, MENU_CLEAR, 0, R.string.clear_history).setIcon(android.R.drawable.ic_menu_close_clear_cancel);
menu.add(1, SETTINGS, 0, R.string.settings).setIcon(android.R.drawable.ic_menu_preferences);;
menu.add(1, MENU_QUIT, 0, R.string.quit).setIcon(android.R.drawable.ic_menu_revert);
return true;
}
/**
* rolls same amount of dice as previous roll
* @author ricky barrette
*/
@Override
public void onItemClick(AdapterView<?> arg0, View v, int position, long id) {
applyRollPresets(id + 1);
if(mSettings.getBoolean(Settings.KEY_ROLL_AGAIN, true))
rollDice();
}
/**
* handles menu selection
*
* @author WWPowers 3-27-2010
* @author ricky barrette 3-27-2010
*/
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Intent intent = new Intent(this, GameListActivity.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
return true;
case MENU_QUIT:
quitDialog();
return true;
case MENU_CLEAR:
mDb.clearHistory(mGameId);
return true;
case SETTINGS:
startActivity(new Intent(this, Settings.class).putExtras(getIntent().getExtras()));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/**
* (non-Javadoc)
* @see android.app.Activity#onPause()
*/
@Override
protected void onStop() {
mDb.close();
super.onStop();
}
/**
* resorts application state after rotation
* @author ricky barrette
*/
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mDPicker.setValue(savedInstanceState.getInt("d"));
mNumberPicker.setValue(savedInstanceState.getInt("number"));
mModPicker.setValue(savedInstanceState.getInt("mod"));
}
/**
* (non-Javadoc)
* @see android.app.Activity#onResume()
*/
@Override
protected void onResume() {
refresh();
applyRollPresets(mDb.getGameRollCount(mGameId));
if(mSettings.getBoolean(Settings.KEY_ROLL_MOD, true)){
mModPicker.setVisibility(View.VISIBLE);
} else {
mModPicker.setVisibility(View.GONE);
mModPicker.setValue(parseMod("+0"));
}
super.onResume();
}
/**
* (non-Javadoc)
* @see android.app.Activity#onStart()
*/
@Override
protected void onStart() {
mDb = new Database(this, this);
mListAdapter = new RollHistoryDatabaseAdapter(mGameId, mDb, this);
mListView.setAdapter(mListAdapter);
super.onStart();
}
/**
* saves application state before rotation
* @author ricky barrette
*/
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putInt("d", mDPicker.getValue());
savedInstanceState.putInt("number", mNumberPicker.getValue());
savedInstanceState.putInt("mod", mModPicker.getValue());
super.onSaveInstanceState(savedInstanceState);
}
/**
* Parses the string d type to the appropriate value
* @param d type
* @return value for d picker
* @author ricky barrette
*/
private int parseD(String d) {
for(int i = 0; i < mDiceValues.length; i++)
if (mDiceValues[i].equalsIgnoreCase(d))
return i;
return 0;
}
/**
* Parses the string mod to the appropriate value
* @param mod
* @return value for d picker
* @author ricky barrette
*/
private int parseMod(String mod) {
for(int i = 0; i < mModValues.length; i++)
if (mModValues[i].equalsIgnoreCase(mod))
return i;
return 0;
}
/**
* 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(R.string.do_you_want_to_quit).setCancelable(
false).setPositiveButton(android.R.string.yes,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
ExaltedDice.this.finish();
}
}).setNegativeButton(android.R.string.no,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
builder.show();
}
/**
* Refreshes the list view
* @author ricky barrette
*/
public void refresh(){
mListAdapter.notifyDataSetChanged();
mListView.setSelection(mDb.getGameRollCount(mGameId));
}
/**
* returns a custom string containing dice rolls and number of successes
*
* @param int times
* @return String resultsString
* @author ricky barrette
*/
public ContentValues results(int times) {
Log.i(TAG, "results()");
ContentValues rolled = new ContentValues();
StringBuffer resultsString = new StringBuffer();
StringBuffer rolls = new StringBuffer();
long total = 0;
int[] roll = rollGen(times);
for (int item : roll) {
rolls.append(item + ", ");
total = total + item;
}
resultsString.append(getString(R.string.total)+ total);
if(mSettings.getBoolean(Settings.KEY_ROLL_MOD, true))
resultsString.append(getString(R.string.total_plus_mod)+ (total + Integer.parseInt(mModValues[mModPicker.getValue()].replace("+", ""))));
if(mSettings.getBoolean(Settings.KEY_CALC_SUCCESSES, true))
resultsString.append(getString(R.string.sucesses)+ successes(roll));
rolled.put(Database.KEY_LOG, resultsString.toString());
rolled.put(Database.KEY_ROLLED, getString(R.string.rolls)+ rolls.toString());
return rolled;
}
/**
* Performs a dice roll and logs it's information in the database
*
* @author ricky barrette
*/
public void rollDice() {
if(!isRolling){
isRolling = true;
mListAdapter.notifyDataSetInvalidated();
mRollButton.setEnabled(false);
mRollProgress.setVisibility(View.VISIBLE);
new Thread( new Runnable() {
@Override
public void run(){
// vibrate for 50 milliseconds
vibrate(50);
int rollId = mDb.getGameRollCount(mGameId) +1;
ContentValues roll = new ContentValues();
roll.put(Database.KEY_D_TYPE, mDiceValues[mDPicker.getValue()]);
roll.put(Database.KEY_NUMBER, mNumberPicker.getValue());
roll.putAll(results(mNumberPicker.getValue()));
roll.put(Database.KEY_MOD, DatabaseUtils.sqlEscapeString(mModValues[mModPicker.getValue()]));
mDb.updateGame(mGameId, mGameName, roll, rollId);
}
}).start();
}
}
/**
* generates an array containing 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(Integer.parseInt(mDiceValues[mDPicker.getValue()].substring(1))) + 1;
}
return roll;
}
/**
* 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()");
int intSuccesses = 0;
for (int i = 0; i < roll.length; i++) {
if (roll[i] >= 7)
intSuccesses++;
if(mSettings.getBoolean(Settings.KEY_TENS_COUNT_TWICE, true))
if (roll[i] == 10)
intSuccesses++;
}
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) {
Toast.makeText(this, msg, Toast.LENGTH_LONG).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);
Vibrator vib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
vib.vibrate(milliseconds);
}
@Override
public void onDatabaseUpgradeComplete() {
// do nothing
}
@Override
public void onDeletionComplete() {
this.runOnUiThread(new Runnable(){
@Override
public void run(){
refresh();
}
});
}
@Override
public void onRestoreComplete() {
// do nothing
}
@Override
public void onDatabaseUpgrade() {
//do nothing
}
@Override
public void onDatabaseInsertComplete() {
isRolling = false;
this.runOnUiThread(new Runnable(){
@Override
public void run(){
mRollProgress.setVisibility(View.GONE);
mRollButton.setEnabled(true);
refresh();
}
});
}
}