package stetson.CTF; import java.util.ArrayList; import stetson.CTF.Join.GameItem; import stetson.CTF.Join.GamesList; import stetson.CTF.utils.Connections; import stetson.CTF.utils.CurrentUser; import android.app.Activity; import android.app.ProgressDialog; import android.content.Context; import android.content.Intent; import android.location.LocationManager; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; public class JoinCTF extends Activity { // Constants: To be used across entire application public static final String TAG = "StetsonCTF"; public static final String SERVER_URL = "http://ctf.no.de"; // Constants: GPS Update Frequency public static final int GPS_UPDATE_FREQUENCY_GAME = 3000; public static final int GPS_UPDATE_FREQUENCY_INTRO = 10000; public static final int GPS_UPDATE_FREQUENCY_BACKGROUND = 60000; // Constants: GPS Update Threshold public static final int GPS_UPDATE_DISTANCE_GAME = 0; public static final int GPS_UPDATE_DISTANCE_INTRO = 1; public static final int GPS_UPDATE_DISTANCE_BACKGROUND = 10; // Data Members public static boolean firstStart = true; private GamesList myGamesList; /** * Called when the activity is first created. * @param saved instance state */ public void onCreate(Bundle savedInstanceState) { Log.i(TAG, "Starting activity..."); // Restore a saved instance of the application super.onCreate(savedInstanceState); new Thread(new Runnable() { public void run() { if(JoinCTF.firstStart) { Intent titleScreen = new Intent(getBaseContext(), IntroCTF.class); startActivityForResult(titleScreen,RESULT_CANCELED); JoinCTF.firstStart = false; } } }).start(); // Move back to the game selection panel setContentView(R.layout.join); // Startup list view myGamesList = new GamesList(this); // Grab a list of games on start up buildGamesList(); // Build listeners buildListeners(); Log.i(TAG, "Activity ready!"); } /** * This method receives callback from IntroCTF to indicate that the user has hit the back button * */ protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_CANCELED) { finish(); } } /** * Start GPS and rebuild games list. */ public void onResume() { super.onResume(); // Start GPS CurrentUser.userLocation((LocationManager) this.getSystemService(Context.LOCATION_SERVICE), GPS_UPDATE_FREQUENCY_INTRO); } /** * Slow down GPS updates a lot when the application is in the background. */ public void onPause() { super.onPause(); // Stop GPS CurrentUser.stopLocation((LocationManager) this.getSystemService(Context.LOCATION_SERVICE)); } /** * The activity has ended, stop all GPS updates. */ public void onDestroy() { super.onDestroy(); // Stop GPS CurrentUser.stopLocation((LocationManager) this.getSystemService(Context.LOCATION_SERVICE)); firstStart = true; CurrentUser.setName(""); } /** * Connects the view components to listeners */ private void buildListeners() { Log.i(TAG, "Prepare listeners."); // Create a new game final Button newGameButton = (Button) findViewById(R.id.newgame_button); newGameButton.setOnClickListener(new OnClickListener() { public void onClick(View view) { // Create the new game :) joinGame(CurrentUser.getName(), ""); } }); // refresh list of games when user clicks final Button refreshButton = (Button) findViewById(R.id.refresh_button); refreshButton.setOnClickListener(new OnClickListener() { public void onClick(View view) { buildGamesList(); } }); } /** * Retrieves and displays a new games list */ private void buildGamesList() { Log.i(TAG, "(UI) Building games list."); new TaskGenerateGamesList().execute(); } /** * Joins or creates a new game. If game is empty, then a new game will be created. * @param name * @param game */ protected void joinGame(String name, String game) { Log.i(TAG, "(UI) joinGame(" + name + ", " + game + ")"); CurrentUser.setGameId(game); new TaskJoinGame().execute(name); } /** * The AsyncTask used for generating a new list of games. * (Generics: Params, Progress, Result) */ private class TaskGenerateGamesList extends AsyncTask<Void, String, ArrayList<GameItem>> { protected static final long GPS_CHECK_PAUSE = 500; /** * Run before execution on the UI thread. * Remove all children from group view and post a loading message. */ protected void onPreExecute() { myGamesList.clearList(); myGamesList.updateList(); } /** * Run after execution on the UI thread. * Clears the gameGroup view and adds a list of games to it. */ protected void onPostExecute(final ArrayList<GameItem> response) { myGamesList.clearList(); myGamesList.setErrorText(""); // If there is a problem, or no games, display an error if(response == null) { myGamesList.setErrorText(getString(R.string.no_games_error)); } else if(response.isEmpty()) { myGamesList.setErrorText(getString(R.string.no_games)); // If there are games, add them to the list :) } else { for(int i = 0; i < response.size(); i++) { myGamesList.addGame(response.get(i)); } myGamesList.updateList(); } } /** * Runs every time publicProgress() is called. * Clears the gamesGroup view and adds a message with the progress text. */ protected void onProgressUpdate(String... progress) { myGamesList.setErrorText(progress[0]); } /** * Run as the work on another thread. */ protected ArrayList<GameItem> doInBackground(Void... params) { this.publishProgress(JoinCTF.this.getString(R.string.loading_location)); while(!CurrentUser.hasLocation()) { try { Thread.sleep(GPS_CHECK_PAUSE); } catch (InterruptedException e) { Log.e(TAG, "Can't sleep :(", e); } } this.publishProgress(JoinCTF.this.getString(R.string.loading_games)); return Connections.getGames(); } } /** * The AsyncTask used for creating and joining a game. * (Generics: Params, Progress, Result) */ private class TaskJoinGame extends AsyncTask<String, Void, String> { private final static String GOOD_RESPONSE = "OK"; private Context mContext = JoinCTF.this; private ProgressDialog dialog; /** * Run before execution on the UI thread. */ protected void onPreExecute() { dialog = ProgressDialog.show(mContext, "Joining Game", "Please wait...", true); } /** * Run after execution on the UI thread. * If the response string is equal to GOOD_RESPONSE then the game activity * is started. If not, a toast showing the error message is sent. */ protected void onPostExecute(final String response) { dialog.hide(); if(response.equals(GOOD_RESPONSE) && GameCTF.hasStarted == false) { Intent i = new Intent(mContext, GameCTF.class); startActivity(i); } else { Toast.makeText(mContext, response, Toast.LENGTH_LONG).show(); } } /** * Run as the work on another thread. */ protected String doInBackground(final String... params) { return Connections.joinOrCreate(params[0]); } } /** * Public join game call to be used from GamesList.java ONLY! * @param gameName */ public void joinGame(String gameName) { CurrentUser.setGameId(gameName); joinGame(CurrentUser.getName(), gameName); } }