Back to Examples
package com.example.flagguessinggamev1;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;

//New Imports:
import java.io.IOException;
import java.io.InputStream;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.content.res.AssetManager;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.Log;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class MainActivity extends Activity {

  // String used when logging error messages using class Log to distinguish
  // this activity's error messages from others that are being written to the log
  private static final String TAG = "FlagQuiz Activity";

  //Number of flags in the game
  private static final int FLAGS_IN_GAME = 10;

  private List fileNameList; // flag file names
  private List gameCountriesList; // countries in current game
  private Set regionsSet; // world regions in current game
  //set vs list: a set is unordered and contains unique elements
  //HashSet uses a hash table for storage and thus the user has no control
  //over where in the set the element will be stored. You can't use and
  //index to access the element. So use ArrayLists here if you want to
  //access elements by their index.
  private String correctAnswer; // correct country for the current flag
  private int totalGuesses; // number of guesses made
  private int correctAnswers; // number of correct guesses
  private SecureRandom random; // used to randomize the game
  //SecureRandom produce cryptographically secure random numbers
  private Handler handler; // used to delay loading next flag
  private Animation shakeAnimation; // animation for incorrect guess
  private TextView questionNumberTextView; // shows current question #
  private ImageView flagImageView; // displays a flag
  private LinearLayout guessLinearLayout; // answer Buttons
  private TextView answerTextView; // displays Correct! or Incorrect!

  //**********************************************************************

  @Override
  protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    fileNameList = new ArrayList();
    gameCountriesList = new ArrayList();
    regionsSet = new HashSet();

    //HashSet creates a collection that uses a hash table for storage.
    regionsSet.add("Asia");
    regionsSet.add("Africa");
    regionsSet.add("North_America");
    regionsSet.add("South_America");
    regionsSet.add("Europe");
    regionsSet.add("Oceania");

    random = new SecureRandom();
    handler = new Handler(); // handles the delay of next flag by 2 secs

    // load the shake animation that's used for incorrect answers
    shakeAnimation = AnimationUtils.loadAnimation(this, R.anim.incorrect_shake);
    shakeAnimation.setRepeatCount(3); // animation repeats 3 times

    // get references to GUI components
    questionNumberTextView = (TextView) findViewById(R.id.questionNumberTextView);
    flagImageView = (ImageView) findViewById(R.id.flagImageView);
    guessLinearLayout = (LinearLayout) findViewById(R.id.buttonsLinearLayout);
    answerTextView = (TextView) findViewById(R.id.answerTextView);

    // set questionNumberTextView's text
    //This will format and put the 'question' string resource which is
    //Question %1$d of %2$d in the textview.
    questionNumberTextView.setText(getResources().getString(R.string.question, 1, FLAGS_IN_GAME));

    // Configure listeners for the 3 guess buttons in the linearlayout:
    for (int btn = 0; btn < 3; btn++) {

      Button button = (Button) guessLinearLayout.getChildAt(btn);
      button.setOnClickListener(guessButtonListener);

    }

    //Start a new game:
    resetGame();

  }

  //**********************************************************************
  // set-up and start the next game - populate the arrays
  public void resetGame() {

    //use AssetManager to get image file names from the assets folder
    //AssetManager: Provides access to an application's raw asset
    AssetManager assets = this.getAssets();
    fileNameList.clear(); // remove elements in the list of image names

    try {

      // loop through each region
      for (String region : regionsSet) {

        // get a list of all flag image files in this region's folder
        String[] paths = assets.list(region);

        for (String path : paths) {

          fileNameList.add(path.replace(".png", ""));

        }

      }

    } catch (IOException exception) {

      //Log the exception for debugging. e() logs error msgs
      Log.e(TAG, "Error loading image file names", exception);

    }

    correctAnswers = 0; // reset the number of correct answers made
    totalGuesses = 0; // reset the total number of guesses the user made
    gameCountriesList.clear(); //remove elements in prior list of countries

    int flagCounter = 1;
    int numberOfFlags = fileNameList.size();

    // add FLAGS_IN_GAME random file names to the gameCountriesList
    while (flagCounter <= FLAGS_IN_GAME) {

      // returns a random index between the range 0-number of flags
      int randomIndex = random.nextInt(numberOfFlags);

      // get the random image file name from fileNameList
      String fileName = fileNameList.get(randomIndex);

      //add a country name to the list only if it has not been added yet
      if(!gameCountriesList.contains(fileName)) {

        gameCountriesList.add(fileName); // add the file to the list
        ++flagCounter;

      }

    }

    loadNextFlag(); // start the game by loading the first flag
  } // end method resetGame

  //**********************************************************************
  // after the user guesses a correct flag, load the next flag and buttons
  private void loadNextFlag() {

    // get file name of the next flag and remove it from the list
    String nextImage = gameCountriesList.remove(0);
    correctAnswer = nextImage; // update the correct answer
    answerTextView.setText(""); // clear answerTextView

    // display current question number
    questionNumberTextView.setText(getResources().getString(R.string.question, (correctAnswers + 1), FLAGS_IN_GAME));

    // extract the region from the next image's name. Remember the file names
    // in gameCounrtyList are formated as: regionName-countryName
    String region = nextImage.substring(0, nextImage.indexOf('-'));

    // use AssetManager to load next image from assets folder
    //'this' means: this activity
    AssetManager assets = this.getAssets();
    try {

      // get an InputStream to the asset representing the next flag
      //ex: Africa/Africa-Algeria.png
      InputStream stream = assets.open(region + "/" + nextImage + ".png");

      // load the asset as a Drawable and display on the flagImageView
      Drawable flag = Drawable.createFromStream(stream, nextImage);
      flagImageView.setImageDrawable(flag);

    } catch (IOException exception) {

      Log.e(TAG, "Error loading " + nextImage, exception);

    }

    Collections.shuffle(fileNameList); // shuffle file names
    //shuffle: Randomly permutes the list elements

    // put the correct answer at the end of fileNameList
    int correct = fileNameList.indexOf(correctAnswer);
    fileNameList.add(fileNameList.remove(correct));

    // add 3 guess Buttons
    // place Buttons in currentTableRow
    for (int btn = 0; btn < guessLinearLayout.getChildCount(); btn++) {

      // get reference to Button to configure
      Button newGuessButton = (Button) guessLinearLayout.getChildAt(btn);
      newGuessButton.setEnabled(true);

      // get country name and set it as newGuessButton's text
      String fileName = fileNameList.get(btn);
      newGuessButton.setText(getCountryName(fileName));

    }

    // randomly replace one Button with the correct answer
    int btn = random.nextInt(3); // pick random button out of the three btns
    String countryName = getCountryName(correctAnswer);
    ((Button) guessLinearLayout.getChildAt(btn)).setText(countryName);

  } // end method loadNextFlag

  //**********************************************************************
  // parses the country flag file name and returns the country name
  //country names are of the following format: North_America-Costa_Rica
  private String getCountryName(String name) {

    String country = name.substring(name.indexOf("-")+1);
    return country.replace('_', ' ');

  }

  //**********************************************************************
  //utility method that disables all buttons when the user gusses the country
  private void disableButtons() {

    for(int btn = 0; btn < guessLinearLayout.getChildCount(); btn++) {

      guessLinearLayout.getChildAt(btn).setEnabled(false);

    }

  }

  //**********************************************************************
  //guessButtonListener is an anonymous inner class object that implements
  //the OnClickListener interface which responds to button click events.
  private OnClickListener guessButtonListener = new OnClickListener() {

    @Override
    public void onClick(View v) {//v is a Button here

      Button guessButton = ((Button) v);
      String guess = guessButton.getText().toString();
      String answer = getCountryName(correctAnswer);
      totalGuesses++; // increment number of guesses the user has made

      if (guess.equals(answer)) {// if the guess is correct
        ++correctAnswers; // increment the number of correct answers
        // display correct answer in green text
        answerTextView.setText(answer + "!");
        answerTextView.setTextColor(getResources().getColor(R.color.correct_answer));

        disableButtons(); // disable all guess Buttons

        // if the user has correctly identified FLAGS_IN_QUIZ flags
        if (correctAnswers == FLAGS_IN_GAME) {

          // DialogFragment to display game stats and start new game
          DialogFragment gameResultsDialog = new DialogFragment() {

            // create an AlertDialog and return it
            @Override
            public Dialog onCreateDialog(Bundle bundle) {

              AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
              builder.setCancelable(false);

              builder.setMessage(getResources().getString(R.string.results,totalGuesses, (1000 / (double) totalGuesses)));

              // "Reset game" Button
              builder.setPositiveButton(R.string.reset_quiz,new DialogInterface.OnClickListener(){

                public void onClick(DialogInterface dialog,int id) {

                  resetGame();

                }

              }); // end call to setPositiveButton

              return builder.create(); // return the AlertDialog

            } // end method onCreateDialog

          }; // end DialogFragment anonymous inner class

          // use FragmentManager to display the DialogFragment
          gameResultsDialog.show(getFragmentManager(), "Game Results");

        } else {

          // load the next flag after a 1-second delay
          handler.postDelayed(new Runnable() {

            //new Rnnable(): anonym inner class that implements the runnable interface
            @Override
            public void run() {

              loadNextFlag();

            }

          }, 2000); // 2000 milliseconds for 2-second delay

        }

      } else {

        flagImageView.startAnimation(shakeAnimation); // play shake

        // display "Incorrect!" in red
        answerTextView.setText(R.string.incorrect_answer);
        answerTextView.setTextColor(getResources().getColor(R.color.incorrect_answer));
        guessButton.setEnabled(false); // disable incorrect answer

      }

    } // end method onClick

  }; // end answerButtonListener

}//End MainActivity
Back to Examples

Startup Discount
Small Business?
Contact us for an Enormous Discount!