Ch 5 Challenge solution


#1

Comments are very welcome
** changes are marked by double quotes **

public class QuizActivity extends AppCompatActivity {

private static final String KEY_INDEX = "index";
private static final String KEY_SCORE = "score";
private static final String KEY_ANSWERED = "answered";
**private static final String KEY_CHEATED = "cheater";**

private static final int REQUEST_CODE_CHEAT = 0;

private static final int QUESTION_GRADE = 1;

private Button mTrueButton;
private Button mFalseButton;
private Button mCheatButton;
private Button mNextButton;
private Button mPrevButton;
private TextView mQuestionTextView;

private Question[] mQuestionBank = new Question[]{
    new Question(R.string.question_australia, true),
    new Question(R.string.question_oceans, true),
    new Question(R.string.question_middleeast, false),
    new Question(R.string.question_africa, false),
    new Question(R.string.question_americas, true),
    new Question(R.string.question_asia, true),
};

private int mCurrentIndex = 0;

private boolean[] mQuestionStatus = new boolean[mQuestionBank.length];
**private boolean[] mCheated = new boolean[mQuestionBank.length];**
private int[] mScore = new int[mQuestionBank.length];

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_quiz);

    if (savedInstanceState != null) {

        if (savedInstanceState.containsKey(KEY_INDEX)) {
            mCurrentIndex = savedInstanceState.getInt(KEY_INDEX);
        }

        if (savedInstanceState.containsKey(KEY_ANSWERED)) {
            mQuestionStatus = savedInstanceState.getBooleanArray(KEY_ANSWERED);
        }

        if (savedInstanceState.containsKey(KEY_SCORE)) {
            mScore = savedInstanceState.getIntArray(KEY_SCORE);
        }

        if (savedInstanceState.containsKey(KEY_CHEATED)){
            **mCheated = savedInstanceState.getBooleanArray(KEY_CHEATED);**
        }
    }


    // question text view
    mQuestionTextView = (TextView) findViewById(R.id.question_text_view);

    // True button
    mTrueButton = (Button) findViewById(R.id.true_button);
    mTrueButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            checkAnswer(true);
        }
    });

    // False button
    mFalseButton = (Button) findViewById(R.id.false_button);
    mFalseButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            checkAnswer(false);
        }
    });

    // Cheat button
    mCheatButton = (Button) findViewById(R.id.cheat_button) ;
    mCheatButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            boolean answerIsTrue = mQuestionBank[mCurrentIndex].isAnswerTrue();
            Intent intent =
                    CheatActivity.newIntent(QuizActivity.this, answerIsTrue);
            startActivityForResult(intent, REQUEST_CODE_CHEAT);
        }
    });

    // Next button
    mNextButton = (Button) findViewById(R.id.next_button);
    mNextButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            nextQuestion();
        }
    });

    // Previous button
    mPrevButton = (Button) findViewById(R.id.previous_button);
    mPrevButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            previousQuestion();
        }
    });

    // At app run, display the first question
    updateQuestion();
}


@Override
public void  onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);
    Log.d(TAG, "onSaveInstanceState() called");
    savedInstanceState.putInt(KEY_INDEX, mCurrentIndex);
    savedInstanceState.putBooleanArray(KEY_ANSWERED, mQuestionStatus);
    savedInstanceState.putIntArray(KEY_SCORE, mScore);
    **savedInstanceState.putBooleanArray(KEY_CHEATED, mCheated);**
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode != Activity.RESULT_OK) {
        return;
    }

    if (requestCode == REQUEST_CODE_CHEAT) {
        if (data == null) {
            return;
        }
        **mCheated[mCurrentIndex] = CheatActivity.wasAnswerShown(data);**
    }
}

/*
 * Updates the text view with the question statement
 * corresponding to current index
 */
private void updateQuestion() {
    int question = mQuestionBank[mCurrentIndex].getTextResId();
    mQuestionTextView.setText(question);

    // if question has not been answered already, activate answer buttons
    if (!mQuestionStatus[mCurrentIndex]) {
        activateAnswerButton();
    } else {
        deactivateAnswerButton();
    }
}

/*
 * Display a toast message indicating correctness of user answer
 * @param userPressedTrue A falg indicating whether the user answered True
 */
private void checkAnswer(boolean userPressedTrue) {
    // Mark question as answered
    mQuestionStatus[mCurrentIndex] = true;

    deactivateAnswerButton();

    int toastResId;
    **if (mCheated[mCurrentIndex]) {**
        **toastResId = R.string.judgment_toast;**
        **mScore[mCurrentIndex] = 0;**
    } else {
        boolean isCorrectAnswer = userPressedTrue == mQuestionBank[mCurrentIndex].isAnswerTrue();
        if (isCorrectAnswer) {
            mScore[mCurrentIndex] = QUESTION_GRADE;
            toastResId = R.string.correct_toast;
        } else {
            // when user answered again, report his inccorect answeres(depend on business logic)
            mScore[mCurrentIndex] = 0;
            toastResId = R.string.incorrect_toast;
        }
    }

    Toast toast = Toast.makeText(QuizActivity.this, toastResId,
            Toast.LENGTH_LONG);
    toast.setGravity(Gravity.BOTTOM, 0, 0);
    toast.show();


    if (allAnswered()) {
        DisplayScore();
        reset();
    }
}

/*
 * Checks whether the user has answered all the questions
 * @return true if the user has answered all questions
 */
private boolean allAnswered() {
    for (boolean status : mQuestionStatus) {
        if (!status) {
            return false;
        }
    }
    return true;
}

/*
 * Reset score and answered questions
 */
private void reset() {

    // set all questions unanswered
    for (int i = 0; i < mQuestionStatus.length ; i++) {
        mQuestionStatus[i] = false;
    }

    **// reset cheating record**
    **for (int i = 0; i < mCheated.length ; i++) {**
        **mCheated[i] = false;**
    **}**

    // set all scores to zero
    for (int i = 0; i < mScore.length ; i++) {
        mScore[i] = 0;
    }
}

/*
 * Displays the score
 */
private void DisplayScore() {
    Toast.makeText(this,
            "Score: " + getScore() + "%",
            Toast.LENGTH_LONG).show();
}

/*
 * Gets the score as a percentage
 * @return The score as a double 
 */
private double getScore() {
    double score = 0;
    for (int i = 0; i < mScore.length ; i++) {
        score += mScore[i];
    }
    return  (score / mQuestionBank.length) * 100;
}

/*
 * Proceeds to next question
 */
private  void nextQuestion() {
    // keep looping forward in the questions
    mCurrentIndex = (mCurrentIndex + 1) % mQuestionBank.length;
    updateQuestion();
}

/*
 * Returns to previous question
 */
private  void previousQuestion() {
    // keep looping backward in the questions
    if(mCurrentIndex == 0) {
        mCurrentIndex = mQuestionBank.length - 1;
    }  else {
        mCurrentIndex = mCurrentIndex - 1;
    }
    updateQuestion();
}

/*
 * Deactivates True and False buttons
 */
private void deactivateAnswerButton() {
    mTrueButton.setEnabled(false);
    mFalseButton.setEnabled(false);
}

/*
 * Activates True and False buttons
 */
private void activateAnswerButton() {
    mTrueButton.setEnabled(true);
    mFalseButton.setEnabled(true);
}
}

public class CheatActivity extends AppCompatActivity {

private static final String EXTRA_ANSWER_IS_TRUE =
        "com.bignerdranch.android.geoquiz.answer_is_true";
private static final String EXTRA_ANSWER_SHOWN =
        "com.bignerdranch.android.geoquiz.answer_shown";

private static final String KEY_ANSWER_SHOWN = "answer is shown";

private boolean mAnswerIsTrue;
**private boolean mAnswerIsShown;**
private TextView mAnswerTextView;
private Button mShowAnswerButton;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_cheat);

    mAnswerIsTrue = getIntent().getBooleanExtra(EXTRA_ANSWER_IS_TRUE, false);

    **if (savedInstanceState != null) {**
        **if (savedInstanceState.containsKey(KEY_ANSWER_SHOWN)) {**
            **mAnswerIsShown = savedInstanceState.getBoolean(KEY_ANSWER_SHOWN);**
        **}**
    **}**

    // Answer TextView
    mAnswerTextView = (TextView) findViewById(R.id.answer_text_view);

    // Show answer Button
    mShowAnswerButton = (Button) findViewById(R.id.show_answer_button);
    mShowAnswerButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            showAnswer();
            **mAnswerIsShown = true;**
            setAnswerShownResult(mAnswerIsShown);
            **mShowAnswerButton.setEnabled(false);**
        }
    });

    **if(mAnswerIsShown) {**
        **showAnswer();**
        **mShowAnswerButton.setEnabled(false);**
        **setAnswerShownResult(mAnswerIsShown);**
    **}**
}

@Override
public void  onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);
    **savedInstanceState.putBoolean(KEY_ANSWER_SHOWN, mAnswerIsShown);**
}

/*
 * Display the answer
 */
private void showAnswer() {
    if(mAnswerIsTrue) {
        mAnswerTextView.setText(R.string.true_button);
    } else {
        mAnswerTextView.setText(R.string.false_button);
    }
}

/*
 * Creates new intent to create a new CheatActivity object and pass information to it
 * @param packageContext The package of CheatActivity clss
 * @param answerIsTrue A flag that indicates if the current question statement is true
 * @return The intent
 */
public static Intent newIntent(Context packageContext, boolean answerIsTrue) {
    Intent intent = new Intent(packageContext, CheatActivity.class);
    intent.putExtra(EXTRA_ANSWER_IS_TRUE, answerIsTrue);
    return intent;
}

/*
 * Determines whether the answer was shawn
 * @param result The intent resulting when CheatActivity return to its launcher
 * @return A flag indicating whether the answer was shown
 */
public static boolean wasAnswerShown(Intent result) {
    return result.getBooleanExtra(EXTRA_ANSWER_SHOWN, false);
}

/*
 * Infrom parent Activity whether the user has seen the answer
 * @param isAnswerShown A flag to indicate whether the user has seen the answer
 */
private void setAnswerShownResult(boolean isAnswerShown) {
    Intent data = new Intent();
    data.putExtra(EXTRA_ANSWER_SHOWN, isAnswerShown);
    setResult(RESULT_OK, data);
}

}