package de.nisble.droidsweeper.gui; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; import android.os.Build; import android.os.Bundle; import android.os.Vibrator; import android.text.format.DateFormat; import android.util.DisplayMetrics; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import de.nisble.droidsweeper.R; import static de.nisble.droidsweeper.config.Constants.*; import de.nisble.droidsweeper.config.GameConfig; import de.nisble.droidsweeper.config.Level; import de.nisble.droidsweeper.config.ApplicationConfig; import de.nisble.droidsweeper.game.Game; import de.nisble.droidsweeper.game.GameObserver; import de.nisble.droidsweeper.game.database.DSDBAdapter; import de.nisble.droidsweeper.game.replay.Player; import de.nisble.droidsweeper.game.replay.PlayerObserver; import de.nisble.droidsweeper.game.replay.Replay; import de.nisble.droidsweeper.gui.grid.FieldDrawables; import de.nisble.droidsweeper.gui.grid.FieldView; import de.nisble.droidsweeper.gui.grid.GameGridView; import de.nisble.droidsweeper.utilities.LogDog; /** Main-Activity * @author Moritz Nisblé moritz.nisble@gmx.de */ public class DroidSweeperActivity extends Activity { private static final String CLASSNAME = DroidSweeperActivity.class.getSimpleName(); private Button mBtNewGame; private GameGridView mGameGrid; private TextView mTimeLabel; private TextView mBombCounter; private Vibrator mVibrator; private Dialog mWinDialog; private static final int WIN_DIALOG = 0; private static final int REPLAY_DIALOG = 1; private static final int REPLAY_AGAIN_DIALOG = 2; private static final int FIRSTSTART_DIALOG = 3; // Replay player private Player mPlayer = new Player(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mBtNewGame = (Button) findViewById(R.id.btNewGame); mBtNewGame.setText(R.string.newGame); mBtNewGame.setOnClickListener(onNewGameClicked); mGameGrid = (GameGridView) findViewById(R.id.gameGrid); mGameGrid.setFieldClickListener(mFieldClickListener); mTimeLabel = (TextView) findViewById(R.id.tvTime); mBombCounter = (TextView) findViewById(R.id.tvBombs); FieldDrawables.loadGrayback(this); mVibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE); // Open database DSDBAdapter.INSTANCE.open(this); // Load config from disk GameConfig c = ApplicationConfig.INSTANCE.init(this).load(); LogDog.i(CLASSNAME, "ApplicationConfig loaded: " + ApplicationConfig.INSTANCE.toString()); Game.INSTANCE.addObserver(mGameObserver); if (ApplicationConfig.INSTANCE.isShowInstructions() == true) showDialog(FIRSTSTART_DIALOG); mPlayer.addObserver(mReplayObserver); // Start game with the GameConfig loaded from persistent memory Game.INSTANCE.start(c); } @Override protected void onResume() { mPlayer.resume(); Game.INSTANCE.resume(); super.onResume(); } @Override protected void onPause() { mPlayer.pause(); Game.INSTANCE.pause(); ApplicationConfig.INSTANCE.store(Game.INSTANCE.getGameConfig()); super.onPause(); } @Override protected void onDestroy() { DSDBAdapter.INSTANCE.close(); super.onDestroy(); } @Override public void onConfigurationChanged(Configuration newConfig) { invalidateOptionsMenu(); if (Game.INSTANCE.isOrientationChangeable() && !mPlayer.isPlaying()) { Game.INSTANCE.start(); } super.onConfigurationChanged(newConfig); } @Override public boolean onCreateOptionsMenu(Menu menu) { /* TODO: Implement a Button in the menu to reshow the first startup * message! */ MenuInflater mi = getMenuInflater(); mi.inflate(R.menu.mainmenu, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onPrepareOptionsMenu(Menu menu) { /* WORAROUND für http://code.google.com/p/android/issues/detail?id=20493 */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { DisplayMetrics dm = getResources().getDisplayMetrics(); int screenWidthDIP = (int) Math.round(((double) dm.widthPixels) / dm.density); boolean reallyWide = screenWidthDIP > 450; int menuItemState = reallyWide ? MenuItem.SHOW_AS_ACTION_ALWAYS : (MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW); int size = menu.size(); for (int i = 0; i < size; i++) { menu.getItem(i).setShowAsAction(menuItemState); } } return super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { Intent intent; switch (item.getItemId()) { case R.id.mm_settings: intent = new Intent(getApplicationContext(), SettingsActivity.class); // TODO: Make Constant from string literal intent.putExtra("GameConfig", Game.INSTANCE.getGameConfig()); startActivityForResult(intent, INTENTREQUEST_SETTINGS); break; case R.id.mm_highscores: intent = new Intent(getApplicationContext(), HighScoreActivity.class); startActivityForResult(intent, INTENTREQUEST_HIGHSCORELIST); break; } return super.onOptionsItemSelected(item); } /* Callback that is passed to GameGridView.update() to connect the field * views to the native library. */ private GameGridView.FieldWidgetConnector mGameConnector = new GameGridView.FieldWidgetConnector() { @Override public void connect(FieldView field) { try { Game.INSTANCE.setFieldListener(field); } catch (Exception e) { LogDog.e(CLASSNAME, e.getMessage(), e); } } }; /* Callback that is passed to GameGridView.update() to connect the field * views to the replay player. */ private GameGridView.FieldWidgetConnector mReplayConnector = new GameGridView.FieldWidgetConnector() { @Override public void connect(FieldView field) { try { mPlayer.setFieldListener(field); } catch (Exception e) { LogDog.e(CLASSNAME, e.getMessage(), e); } } }; private final GameObserver mGameObserver = new GameObserver() { @Override public void onBuildGrid(GameConfig config) { mGameGrid.hideOverlay(); mGameGrid.update(config, mGameConnector); } @Override public void onTimeUpdate(long milliseconds) { mTimeLabel.setText(DateFormat.format("mm:ss", milliseconds).toString()); } @Override public void onRemainingBombsChanged(int bombCount) { mBombCounter.setText(String.valueOf(bombCount)); } @Override public void onWon(long milliseconds, boolean highscore) { if (Game.INSTANCE.getGameConfig().LEVEL != Level.CUSTOM) { if (highscore) { showDialog(WIN_DIALOG); } else { mGameGrid.showOverlay(getString(R.string.wonMsg) + "\n" + getString(R.string.badTimeMsg)); if (ApplicationConfig.INSTANCE.isReplayOnLost()) { // Load the current game into the player mPlayer.load(Game.INSTANCE.getReplay()); showDialog(REPLAY_DIALOG); } } } else { mGameGrid.showOverlay(getString(R.string.wonMsg) + "\n" + getString(R.string.customGameMsg)); } } @Override public boolean onLost(long milliseconds) { mGameGrid.showOverlay(getString(R.string.lostMsg)); if (ApplicationConfig.INSTANCE.isReplayOnLost()) { // Load the current game into the player mPlayer.load(Game.INSTANCE.getReplay()); showDialog(REPLAY_DIALOG); } // Return true to reveal all fields return true; } }; private final PlayerObserver mReplayObserver = new PlayerObserver() { @Override public void onBuildGrid(GameConfig config) { mGameGrid.hideOverlay(); mGameGrid.update(config, mReplayConnector); } @Override public void onTimeUpdate(long milliseconds) { mTimeLabel.setText(DateFormat.format("mm:ss", milliseconds).toString()); } @Override public void onRemainingBombsChanged(int bombCount) { mBombCounter.setText(String.valueOf(bombCount)); } @Override public void onReplayEnded() { showDialog(REPLAY_AGAIN_DIALOG); } }; @Override protected Dialog onCreateDialog(int id) { Dialog dialog; AlertDialog.Builder builder; switch (id) { case WIN_DIALOG: /* TODO: Use a normal Dialog! */ mWinDialog = new Dialog(this); mWinDialog.setContentView(R.layout.layout_name_dialog); mWinDialog.setTitle(getString(R.string.congratulations)); mWinDialog.setCanceledOnTouchOutside(false); Button b = (Button) mWinDialog.findViewById(R.id.bt_nameDialog_OK); b.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { EditText name = (EditText) mWinDialog.findViewById(R.id.editText_nameDialog_name); if (name.getText().length() >= 3) { Replay replay = Game.INSTANCE.getReplay(); replay.setName(name.getText().toString()); try { DSDBAdapter.INSTANCE.insertTime(replay); } catch (Exception e) { LogDog.e(CLASSNAME, e.getMessage(), e); } mWinDialog.dismiss(); // Load the game into the player mPlayer.load(replay); showDialog(REPLAY_DIALOG); } else { Toast.makeText(getApplicationContext(), R.string.hint_short_name, Toast.LENGTH_SHORT).show(); name.requestFocus(); } } }); dialog = mWinDialog; break; case REPLAY_DIALOG: case REPLAY_AGAIN_DIALOG: builder = new AlertDialog.Builder(this); builder.setMessage((REPLAY_DIALOG == id) ? getString(R.string.playReplay) : getString(R.string.playAgain)); builder.setCancelable(false); builder.setPositiveButton(getString(R.string.Yes), onReplayYESButtonClicked); builder.setNegativeButton(getString(R.string.No), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); dialog = builder.create(); break; case FIRSTSTART_DIALOG: builder = new AlertDialog.Builder(this); builder.setMessage(getString(R.string.firstStartMsg)); builder.setCancelable(false); builder.setPositiveButton(getString(R.string.OK), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); dialog = builder.create(); break; default: dialog = null; break; } return dialog; } /* This is called before onResume! * @see android.app.Activity#onActivityResult(int, int, * android.content.Intent) */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { /* Result from SettingsActivity */ case INTENTREQUEST_SETTINGS: switch (resultCode) { /* Configuration changed */ case INTENTRESULT_CHANGE_GAMECONFIG: /* Stop a maybe currently paused game */ Game.INSTANCE.stop(); mPlayer.stop(); /* Get the new GameConfig from the Intent */ GameConfig newConfig = data.getParcelableExtra("GameConfig"); if (newConfig != null) { ApplicationConfig.INSTANCE.store(newConfig); Game.INSTANCE.start(newConfig); } else LogDog.e(CLASSNAME, "Unable to unpack GameConfig from intent"); break; /* Nothing changed */ case RESULT_CANCELED: break; default: LogDog.e(CLASSNAME, "Got unknown intent result code from SettingsActivity! Code:" + resultCode); break; } break; /* Result from HighScoreListActivity */ case INTENTREQUEST_HIGHSCORELIST: switch (resultCode) { /* Replay selected for play */ case INTENTRESULT_PLAY_REPLAY: /* Stop a maybe currently paused game */ Game.INSTANCE.stop(); mPlayer.stop(); /* Get the GameID (RowID from DB) from the Intent */ long gameID = data.getLongExtra("GAMEID", -1); if (-1 != gameID) { try { /* Let the player load the Replay from the DB */ mPlayer.load(gameID); mPlayer.play(); } catch (Exception e) { LogDog.e(CLASSNAME, e.getMessage(), e); } } else { LogDog.e(CLASSNAME, "Invalid GameID " + gameID); } break; /* Nothing selected */ case RESULT_CANCELED: break; default: LogDog.e(CLASSNAME, "Got unknown intent result code from HighScoreActivity! Code:" + resultCode); break; } break; } } private final GameGridView.FieldClickListener mFieldClickListener = new GameGridView.FieldClickListener() { @Override public void onClick(FieldView field) { Game.INSTANCE.revealField(field.getPosition()); } @Override public boolean onLongClick(FieldView field) { // TODO: Make vibration (and time) configurable // TODO: Mark with double click mVibrator.vibrate(100); Game.INSTANCE.cycleMark(field.getPosition()); return true; } }; private final OnClickListener onNewGameClicked = new OnClickListener() { @Override public void onClick(View v) { mPlayer.stop(); Game.INSTANCE.start(); } }; private final DialogInterface.OnClickListener onReplayYESButtonClicked = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mPlayer.play(); } }; }