package com.charlesmadere.android.classygames; import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Resources; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; import com.actionbarsherlock.app.SherlockFragment; import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.charlesmadere.android.classygames.models.Game; import com.charlesmadere.android.classygames.models.Person; import com.charlesmadere.android.classygames.models.games.GenericBoard; import com.charlesmadere.android.classygames.models.games.GenericPiece; import com.charlesmadere.android.classygames.models.games.Position; import com.charlesmadere.android.classygames.server.*; import com.charlesmadere.android.classygames.utilities.Utilities; import com.charlesmadere.android.classygames.views.BoardView; import com.charlesmadere.android.classygames.views.PositionView; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; public abstract class GenericGameFragment extends SherlockFragment { private final static String LOG_TAG = Utilities.LOG_TAG + " - GenericGameFragment"; private final static String PREFERENCES_NAME = "GenericGameFragment_Preferences"; private final static String KEY_GAME_ID = "KEY_GAME_ID"; private final static String KEY_WHICH_GAME = "KEY_WHICH_GAME"; private final static String KEY_PERSON = "KEY_PERSON"; private final static String BUNDLE_BOARD_JSON = "BUNDLE_BOARD_JSON"; /** * This game's Game object. This contains a whole bunch of necessary data * such as the ID of the game as well as the Person object that the current * Android user is playing against. <strong>DO NOT MODIFY THIS OBJECT ONCE * IT HAS BEEN SET.</strong> */ protected Game game; /** * JSONObject downloaded from the server that represents the board. */ private JSONObject boardJSON; /** * The actual logical representation of the board. */ protected GenericBoard board; /** * Holds a handle to the currently running (if it's currently running) * AsyncGetGame AsyncTask. This could be null. */ private AsyncGetGame asyncGetGame; /** * Holds a handle to a currently running (if it's currently running) * ServerApi object. */ private ServerApi serverApiTask; /** * Callback interface for the ServerApi class. */ private ServerApi.Listeners serverApiListeners; /** * The position on the game board that the user just now selected. */ private PositionView positionSelectedCurrent; /** * The position on the game board that the user selected last time. */ private PositionView positionSelectedPrevious; /** * The BoardView layout element as seen on the device's screen. */ private BoardView boardView; /** * Views that will be shown when downloading the game's data from the * Classy Games server. */ private LinearLayout loading; private TextView loadingText; /** * Object that allows us to run any of the methods that are defined in the * Listeners interface. */ private Listeners listeners; /** * A bunch of listener methods for this Fragment. */ public interface Listeners { /** * This is fired during this Fragment's onCreateOptionsMenu() method. * Checks to see if the current device is considered by Android to be * small. This be basically every phone. * * @return * Returns true if the current device is small. */ public boolean isDeviceSmall(); /** * This is fired in the event that an error was detected with some of * the data needed to instantiate a game. */ public void onGetGameDataError(); /** * This is fired if the AsyncGetGame AsyncTask gets cancelled. */ public void onGetGameCancelled(); /** * This is fired when a move (or new game) is finished being sent to * the server. */ public void onServerApiTaskFinished(); } protected static Bundle prepareArguments(final String gameId, final byte whichGame, final Person person) { final Bundle arguments = new Bundle(); arguments.putString(KEY_GAME_ID, gameId); arguments.putByte(KEY_WHICH_GAME, whichGame); arguments.putSerializable(KEY_PERSON, person); return arguments; } @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); } @Override public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { return inflater.inflate(getGameView(), container, false); } @Override public void onActivityCreated(final Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); final Bundle arguments = getArguments(); if (arguments == null || arguments.isEmpty()) // Check the arguments given to this Fragment. This Fragment requires // information regarding the game that it is going to load. If no data // is found, then this Fragment has encountered an error and must // terminate itself. { listeners.onGetGameDataError(); } else { // Grabs data that was given to this Fragment. This data will then // be checked for validity. final String gameId = arguments.getString(KEY_GAME_ID); final byte whichGame = arguments.getByte(KEY_WHICH_GAME); final Person person = (Person) arguments.getSerializable(KEY_PERSON); if (Game.isWhichGameValid(whichGame) && person.isValid()) // Check the data for validity. Note that we are not checking the // gameId String for validity. This is because it is possible for a // game to not have an ID. Brand new games do not have a game ID. { serverApiListeners = new ServerApi.Listeners() { @Override public void onCancel() { serverApiTask = null; } @Override public void onComplete(final String serverResponse) { serverApiTask = null; listeners.onServerApiTaskFinished(); } @Override public void onDismiss() { serverApiTask = null; } }; final View view = getView(); boardView = (BoardView) view.findViewById(R.id.generic_game_fragment_board); loading = (LinearLayout) view.findViewById(R.id.generic_game_fragment_loading); loadingText = (TextView) view.findViewById(R.id.generic_game_fragment_loading_textview); boardView.setAllPositionViewOnClickListeners(new View.OnClickListener() { @Override public void onClick(final View v) { if (positionSelectedCurrent == null) { positionSelectedCurrent = (PositionView) v; onBoardClick(positionSelectedCurrent); } else { positionSelectedPrevious = positionSelectedCurrent; positionSelectedCurrent = (PositionView) v; if (positionSelectedPrevious == positionSelectedCurrent) // The player has clicked the same position on // the board twice in a row. This is the // deselect action. { clearSelectedPositions(); } else { onBoardClick(positionSelectedPrevious, positionSelectedCurrent); } } } }); if (Game.isIdValid(gameId)) // Check to see if we were given a valid game ID. We will only // have a valid game ID if we are trying to recreate an already // existing game. A brand new game will not have a game ID (and // will therefore fail this if statement). { game = new Game(person, whichGame, gameId); if (savedInstanceState != null && savedInstanceState.containsKey(BUNDLE_BOARD_JSON)) { try { boardJSON = new JSONObject(savedInstanceState.getString(BUNDLE_BOARD_JSON)); loadPieceResources(); resumeOldBoard(); flush(); } catch (final JSONException e) { getGame(); } } else { getGame(); } } else // We were not given a valid game ID. That means that we are // going to instantiate a brand new game. { game = new Game(person); try { loadPieceResources(); initNewBoard(); flush(); } catch (final JSONException e) { listeners.onGetGameDataError(); } } } else { listeners.onGetGameDataError(); } } } @Override public void onAttach(final Activity activity) // This makes sure that the Activity containing this Fragment has // implemented the callback interface. If the callback interface has not // been implemented, an exception is thrown. { super.onAttach(activity); listeners = (Listeners) activity; } @Override public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { // Attempt to remove menu items from other fragments that may be // visible, as when a game is showing on screen they either make no // sense or could lead to unpredictable results. menu.removeItem(R.id.game_fragment_activity_menu_settings); menu.removeItem(R.id.games_list_fragment_menu_refresh); if (listeners.isDeviceSmall()) { // TODO // uncomment this for 2.0! // menu.removeItem(R.id.game_fragment_activity_menu_my_stats); menu.removeItem(R.id.game_fragment_activity_menu_new_game); } inflater.inflate(R.menu.generic_game_fragment, menu); // Code below enables / disables the send move and undo move Action Bar // buttons as necessary. if (asyncGetGame == null) { final MenuItem sendMoveMenuItem = menu.findItem(R.id.generic_game_fragment_menu_send_move); final MenuItem undoMoveMenuItem = menu.findItem(R.id.generic_game_fragment_menu_undo_move); if (board == null) { sendMoveMenuItem.setEnabled(false); undoMoveMenuItem.setEnabled(false); } else { final boolean hasMoveBeenMade = board.hasMoveBeenMade(); sendMoveMenuItem.setEnabled(hasMoveBeenMade); undoMoveMenuItem.setEnabled(hasMoveBeenMade); } } // Here we only allow the Skip Move or Forfeit Game Action Bar buttons // to be shown if the game we're displaying in this Fragment has a game // ID. final Bundle arguments = getArguments(); final String gameId = arguments.getString(KEY_GAME_ID); if (!Utilities.validString(gameId) || !Game.isIdValid(gameId)) { menu.removeItem(R.id.generic_game_fragment_menu_skip_move); menu.removeItem(R.id.generic_game_fragment_menu_forfeit_game); } // load any menu items as added by the classes that extend this one createOptionsMenu(menu, inflater); super.onCreateOptionsMenu(menu, inflater); } @Override public void onDestroyView() { cancelRunningAnyAsyncTask(); super.onDestroyView(); } @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case R.id.generic_game_fragment_menu_forfeit_game: forfeitGame(); break; case R.id.generic_game_fragment_menu_send_move: sendMove(); break; case R.id.generic_game_fragment_menu_skip_move: skipMove(); break; case R.id.generic_game_fragment_menu_undo_move: undoMove(); break; default: // If we hit this point then that means that the options item that // was selected is not any of the above choices. That means that it // was probably a menu item created by one of the classes that // extend this one. So this will check that class's menu items. return optionsItemSelected(item); } return true; } @Override public void onSaveInstanceState(final Bundle outState) { if (Game.isIdValid(game.getId()) && boardJSON != null) { final String boardJSONString = boardJSON.toString(); if (Utilities.validString(boardJSONString)) { outState.putString(BUNDLE_BOARD_JSON, boardJSONString); } } super.onSaveInstanceState(outState); } /** * Attempts to cancel the currently running AsyncGetGame AsyncTask. * * @return * Returns true if the AsyncTask was cancelled. */ private boolean cancelRunningAsyncGetGame() { boolean cancelled = false; if (asyncGetGame != null) { asyncGetGame.cancel(true); cancelled = true; } return cancelled; } /** * Attempts to cancel the currently running ServerApiTask. * * @return * Returns true if the ServerApiTask was cancelled. */ private boolean cancelRunningServerApiTask() { boolean cancelled = false; if (serverApiTask != null) { serverApiTask.cancel(); cancelled = true; } return cancelled; } /** * Cancels the currently running AsyncTask (if any). */ private void cancelRunningAnyAsyncTask() { if (!cancelRunningAsyncGetGame()) { cancelRunningServerApiTask(); } } /** * Clears both selected positions variables. (They are both set to null.) * The background image on both of them is also reset. */ protected void clearSelectedPositions() { if (positionSelectedPrevious != null) { positionSelectedPrevious.unselect(); positionSelectedPrevious = null; } if (positionSelectedCurrent != null) { positionSelectedCurrent.unselect(); positionSelectedCurrent = null; } } /** * Renders all of the game's pieces on the board by first clearing all of * the existing pieces from it and then placing all of the current pieces. */ protected void flush() { // clear all pieces from the board for (byte x = 0; x < board.getLengthHorizontal(); ++x) { for (byte y = 0; y < board.getLengthVertical(); ++y) { final PositionView positionView = boardView.getPosition(x, y); positionView.setImageDrawable(null); } } // place all pieces back onto the board for (byte x = 0; x < board.getLengthHorizontal(); ++x) { for (byte y = 0; y < board.getLengthVertical(); ++y) { final Position position = board.getPosition(x, y); if (position.hasPiece()) { final GenericPiece piece = position.getPiece(); final PositionView positionView = boardView.getPosition(x, y); // Let each GenericGameFragment class that extends from // this one handle the rest of the flush from here. flush(piece, positionView); } } } } /** * Forfeits this game by asking the user if they're sure that they want to * through a dialog box. */ private void forfeitGame() { if (Utilities.validString(game.getId()) && !isAnAsyncTaskRunning()) { serverApiTask = new ServerApiForfeitGame(getSherlockActivity(), serverApiListeners, game); serverApiTask.execute(); } } /** * If the AsyncGetGame AsyncTask is not already running, then this will * execute it. */ private void getGame() { if (asyncGetGame == null) { asyncGetGame = new AsyncGetGame(); asyncGetGame.execute(); } } /** * @return * Returns true if either the AsyncGetGame AsyncTask is running or if a * ServerApi is running. */ private boolean isAnAsyncTaskRunning() { return asyncGetGame != null || serverApiTask != null; } /** * Loads in the images to be used for the game pieces as shown on the game * board. Checks user's preferences to see which image files to load. */ private void loadPieceResources() { final String blue = getString(R.string.blue); final String green = getString(R.string.green); final String orange = getString(R.string.orange); final String pink = getString(R.string.pink); final String defaultOpponentsColor = getDefaultOpponentsPieceColor(); final String defaultPlayersColor = getDefaultPlayersPieceColor(); final int opponentsColorKey = getSettingsKeyForOpponentsPieceColor(); final int playersColorKey = getSettingsKeyForPlayersPieceColor(); final String opponentsColorKeyString = getString(opponentsColorKey); final String playersColorKeyString = getString(playersColorKey); final SharedPreferences sPreferences = Utilities.getPreferences(getSherlockActivity()); // Read in the colors that the player has selected to use for their // pieces. If the user has not set a color, the playerColor and // opponentColor Strings will both be set to the game's default color. String opponentsColor = sPreferences.getString(opponentsColorKeyString, defaultOpponentsColor); String playersColor = sPreferences.getString(playersColorKeyString, defaultPlayersColor); boolean recheckColorSettings; do { recheckColorSettings = false; if (opponentsColor.equalsIgnoreCase(playersColor)) // Check to see if the color that the player has set for their own // color is the same as the one that they set for the opponent's color. // This if statement will validate as true if that is the case. { opponentsColor = defaultOpponentsColor; playersColor = defaultPlayersColor; // Change the value as saved in the user's preferences to the // default colors. This fixes the conflicting color issue. sPreferences.edit() .putString(opponentsColorKeyString, defaultOpponentsColor) .putString(playersColorKeyString, defaultPlayersColor) .commit(); } // The code below will load BitmapDrawables for game pieces into // memory. This is done so that later when we draw these game pieces // onto the board, that draw process can be done very quickly as all of // the picture data will have already been loaded. final Resources res = getResources(); if (opponentsColor.equalsIgnoreCase(blue)) { loadBluePieceResources(res, false); } else if (opponentsColor.equalsIgnoreCase(green)) { loadGreenPieceResources(res, false); } else if (opponentsColor.equalsIgnoreCase(orange)) { loadOrangePieceResources(res, false); } else if (opponentsColor.equalsIgnoreCase(pink)) { loadPinkPieceResources(res, false); } else { // If we've gotten to this point then that means that the user // setting for the opponent's piece color is corrupted or // malformed or something. So let's clear that setting back to // the default and load in the opponent's default piece colors. opponentsColor = ""; playersColor = ""; recheckColorSettings = true; } if (playersColor.equalsIgnoreCase(blue)) { loadBluePieceResources(res, true); } else if (playersColor.equalsIgnoreCase(green)) { loadGreenPieceResources(res, true); } else if (playersColor.equalsIgnoreCase(orange)) { loadOrangePieceResources(res, true); } else if (playersColor.equalsIgnoreCase(pink)) { loadPinkPieceResources(res, true); } else { // If we've gotten to this point then that means that the user // setting for the player's piece color is corrupted or // malformed or something. So let's clear that setting back to // the default and load in the player's default piece colors. opponentsColor = ""; playersColor = ""; recheckColorSettings = true; } } while (recheckColorSettings); } public boolean onBackPressed() { if (isAnAsyncTaskRunning()) { cancelRunningAnyAsyncTask(); return true; } else { return false; } } /** * Reads in a JSON response String as received from the web server and * pulls the needed information out of it. If there is an error during this * process, null is returned. * * @param serverResponse * The JSON response String as received from the web server. This method * <strong>does</strong> check to see if this passed in String is either * null or empty. In that case, the method will immediately log that error * and then return null. * * @return * Returns a JSONObject containing only the necessary game information. * But, if there is an error in the parsing process, this method will log * some stuff and then return null. */ private JSONObject parseServerResponse(final String serverResponse) { JSONObject parsedServerResponse = null; if (Utilities.validString(serverResponse)) { try { final JSONObject jsonData = new JSONObject(serverResponse); final JSONObject jsonResult = jsonData.getJSONObject(Server.POST_DATA_RESULT); try { final String successMessage = jsonResult.getString(Server.POST_DATA_SUCCESS); Log.i(LOG_TAG, "Server returned success message: " + successMessage); parsedServerResponse = new JSONObject(successMessage); } catch (final JSONException e) { try { final String errorMessage = jsonResult.getString(Server.POST_DATA_ERROR); Log.e(LOG_TAG, "Server returned error message: " + errorMessage); } catch (final JSONException e1) { Log.e(LOG_TAG, "Server response is nothing much."); } } } catch (final JSONException e) { Log.e(LOG_TAG, "Server response is massively malformed."); } } else { Log.e(LOG_TAG, "Either null or empty String was attempted to be parsed!"); } return parsedServerResponse; } /** * This method will initialize the game board as if this is an in progress * game. This <strong>resumes</strong> an old game. Do not use this for a * brand new game. */ private void resumeOldBoard() { if (boardJSON == null) { Log.e(LOG_TAG, "Tried to build the board from a null JSONObject!"); listeners.onGetGameDataError(); } else { try { resumeOldBoard(boardJSON); } catch (final JSONException e) { Log.e(LOG_TAG, "resumeOldBoard(): boardJSON is massively malformed.", e); listeners.onGetGameDataError(); } } } /** * If the AsyncSendMove AsyncTask is not already running, then this will * execute it. */ private void sendMove() { if (!isAnAsyncTaskRunning()) { final boolean askUserToExecute = Utilities.checkIfSettingIsEnabled(getSherlockActivity(), R.string.settings_key_ask_before_sending_move, true); serverApiTask = new ServerApiSendMove(getSherlockActivity(), serverApiListeners, game, board); serverApiTask.execute(askUserToExecute); } } /** * Skips the user's turn by asking the user if they're sure that they want * to using a dialog box. */ private void skipMove() { if (Utilities.validString(game.getId()) && !isAnAsyncTaskRunning()) { serverApiTask = new ServerApiSkipMove(getSherlockActivity(), serverApiListeners, game); serverApiTask.execute(); } } /** * Undoes the user's last move on the board. Unlocks the board, allowing * the user to make a different move on the board. */ private void undoMove() { if (board.isBoardLocked() || board.hasMoveBeenMade()) { clearSelectedPositions(); try { board.reset(); } catch (final JSONException e) { listeners.onGetGameDataError(); } flush(); getSherlockActivity().supportInvalidateOptionsMenu(); } } /** * An AsyncTask that will download the current state of the game board from * the server. */ private final class AsyncGetGame extends AsyncTask<Void, Void, String> { private SherlockFragmentActivity fragmentActivity; private AsyncGetGame() { fragmentActivity = getSherlockActivity(); } @Override protected String doInBackground(final Void... params) { String serverResponse = null; if (!isCancelled()) { final SharedPreferences sPreferences = fragmentActivity.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE); final String boardJSON = sPreferences.getString(game.getId(), null); if (Utilities.validString(boardJSON)) { serverResponse = boardJSON; } else if (Utilities.checkForNetworkConnectivity(fragmentActivity)) { final ApiData data = new ApiData() .addKeyValuePair(Server.POST_DATA_ID, game.getId()); try { serverResponse = Server.postToServerGetGame(data); // store the just now downloaded instance of the board sPreferences.edit() .putString(game.getId(), serverResponse) .commit(); } catch (final IOException e) { Log.e(LOG_TAG, "IOException error in AsyncGetGame - doInBackground()!", e); } } } return serverResponse; } private void cancelled() { setRunningState(false); listeners.onGetGameCancelled(); } @Override protected void onCancelled() { cancelled(); } @Override protected void onCancelled(final String serverResponse) { cancelled(); } @Override protected void onPostExecute(final String serverResponse) { boardJSON = parseServerResponse(serverResponse); loading.setVisibility(View.GONE); boardView.setVisibility(View.VISIBLE); loadPieceResources(); resumeOldBoard(); flush(); setRunningState(false); } @Override protected void onPreExecute() { setRunningState(true); boardView.setVisibility(View.GONE); loading.setVisibility(View.VISIBLE); loadingText.setText(getString(getLoadingText(), game.getPerson().getName())); } /** * Use this method to reset the options menu. This should only be used when * an AsyncTask is running (or has just finished). * * @param isRunning * True if the AsyncTask is just starting to run, false if it's just * finished. */ private void setRunningState(final boolean isRunning) { if (!isRunning) { asyncGetGame = null; } fragmentActivity.supportInvalidateOptionsMenu(); } } /** * Clears all saved Board data that was retrieved from the Classy Games * server. * * @param context * The Context of the Activity or Fragment that you're calling this method * from. */ public static void clearCachedBoards(final Context context) { context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE).edit().clear().commit(); } /** * This method is run at the end of the Android onCreateOptionsMenu method. * Use this method to add menu items to this Fragment's menu. * * @param menu * The Menu object as given by Android. * * @param inflater * The MenuInflater object as given by Android. Use this to inflate a menu * XML file. */ protected abstract void createOptionsMenu(final Menu menu, final MenuInflater inflater); /** * This method is run at the end of the Android onOptionsItemSelected * method if the selected MenuItem was not already found. Use this to check * to see which MenuItem was selected by the user. * * @param item * The selected MenuItem as given by Android. * * @return * Returns true if the selected MenuItem was found. Returns * super.onOptionsItemSelected(item) if the MenuItem was not found. */ protected abstract boolean optionsItemSelected(final MenuItem item); /** * A Game specific implementation that looks at the given PositionView and * Position parameter and draws a piece on that position if / as necessary. * This method will only be run for positions on the board that have a * piece in them. * * @param piece * The GenericPiece object that is located at this position on the board. * * @param positionView * The current BoardView's PositionView object in the flush() loop. */ protected abstract void flush(final GenericPiece piece, final PositionView positionView); /** * @return * Returns the actual String for the players's default piece color. */ protected abstract String getDefaultPlayersPieceColor(); /** * @return * Returns the actual String for the opponent's default piece color. */ protected abstract String getDefaultOpponentsPieceColor(); /** * @return * Returns the int value for the XML layout to use. */ protected abstract int getGameView(); /** * @return * Returns the int value for the XML String to use as the text to display * as a loading message when the AsyncGetGame AsyncTask is running. */ protected abstract int getLoadingText(); /** * @return * Returns the int string ID for the player's settings key. */ protected abstract int getSettingsKeyForPlayersPieceColor(); /** * @return * Returns the int string ID for the opponent's settings key. */ protected abstract int getSettingsKeyForOpponentsPieceColor(); /** * Initialize the game board as if it's a <strong>brand new game</strong>. * * @throws JSONException * This should never happen. But still, I guess it still possibly could. So * definitely prepare for that situation in some way. If this Exception is * thrown then it can be assumed that the game we were trying to initialize * is corrupt. A corrupt game should <b>never, ever</b> be played. So this * should trigger the GenericGameFragment to destroy itself to prevent * some sort of malformity from hitting the Classy Games server. */ protected abstract void initNewBoard() throws JSONException; /** * Loads in the images used for the game pieces as shown on the game board. * * @param res * A handle to the results of a call to the getResources() method. * * @param isPlayersColor * This value will be true if this color is what should be loaded for the * player's pieces. This value will be false if this color is what should * be loaded for the opponent's pieces. */ protected abstract void loadBluePieceResources(final Resources res, final boolean isPlayersColor); /** * Loads in the images used for the game pieces as shown on the game board. * * @param res * A handle to the results of a call to the getResources() method. * * @param isPlayersColor * This value will be true if this color is what should be loaded for the * player's pieces. This value will be false if this color is what should * be loaded for the opponent's pieces. */ protected abstract void loadGreenPieceResources(final Resources res, final boolean isPlayersColor); /** * Loads in the images used for the game pieces as shown on the game board. * * @param res * A handle to the results of a call to the getResources() method. * * @param isPlayersColor * This value will be true if this color is what should be loaded for the * player's pieces. This value will be false if this color is what should * be loaded for the opponent's pieces. */ protected abstract void loadOrangePieceResources(final Resources res, final boolean isPlayersColor); /** * Loads in the images used for the game pieces as shown on the game board. * * @param res * A handle to the results of a call to the getResources() method. * * @param isPlayersColor * This value will be true if this color is what should be loaded for the * player's pieces. This value will be false if this color is what should * be loaded for the opponent's pieces. */ protected abstract void loadPinkPieceResources(final Resources res, final boolean isPlayersColor); /** * Checks to see which position on the board was clicked and then moves * pieces and / or performs actions accordingly. This method will only be * called if there is no previous position on the board that the user * clicked on. * * @param positionCurrent * The PositionView object that was just now clicked on. */ protected abstract void onBoardClick(final PositionView positionCurrent); /** * Checks to see which position on the board was clicked and then moves * pieces and / or performs actions accordingly. * * @param positionPrevious * The PositionView object that was previously clicked on. * * @param positionCurrent * The PositionView object that was just now clicked on. */ protected abstract void onBoardClick(final PositionView positionPrevious, final PositionView positionCurrent); /** * Creates a Board object out of the given JSON String. * * @param boardJSON * The JSONObject that represents the game board as was received from the * Classy Games server. */ protected abstract void resumeOldBoard(final JSONObject boardJSON) throws JSONException; }