• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.example.android.wearable.quiz;
18 
19 import static com.example.android.wearable.quiz.Constants.ANSWERS;
20 import static com.example.android.wearable.quiz.Constants.CHOSEN_ANSWER_CORRECT;
21 import static com.example.android.wearable.quiz.Constants.CORRECT_ANSWER_INDEX;
22 import static com.example.android.wearable.quiz.Constants.NUM_CORRECT;
23 import static com.example.android.wearable.quiz.Constants.NUM_INCORRECT;
24 import static com.example.android.wearable.quiz.Constants.NUM_SKIPPED;
25 import static com.example.android.wearable.quiz.Constants.QUESTION;
26 import static com.example.android.wearable.quiz.Constants.QUESTION_INDEX;
27 import static com.example.android.wearable.quiz.Constants.QUESTION_WAS_ANSWERED;
28 import static com.example.android.wearable.quiz.Constants.QUESTION_WAS_DELETED;
29 import static com.example.android.wearable.quiz.Constants.QUIZ_ENDED_PATH;
30 import static com.example.android.wearable.quiz.Constants.QUIZ_EXITED_PATH;
31 import static com.example.android.wearable.quiz.Constants.RESET_QUIZ_PATH;
32 
33 import android.app.Activity;
34 import android.graphics.Color;
35 import android.net.Uri;
36 import android.os.Bundle;
37 import android.util.Log;
38 import android.view.LayoutInflater;
39 import android.view.View;
40 import android.widget.Button;
41 import android.widget.EditText;
42 import android.widget.LinearLayout;
43 import android.widget.RadioGroup;
44 import android.widget.TextView;
45 
46 import com.google.android.gms.common.ConnectionResult;
47 import com.google.android.gms.common.api.GoogleApiClient;
48 import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
49 import com.google.android.gms.common.api.ResultCallback;
50 import com.google.android.gms.common.data.FreezableUtils;
51 import com.google.android.gms.wearable.DataApi;
52 import com.google.android.gms.wearable.DataEvent;
53 import com.google.android.gms.wearable.DataEventBuffer;
54 import com.google.android.gms.wearable.DataItem;
55 import com.google.android.gms.wearable.DataItemBuffer;
56 import com.google.android.gms.wearable.DataMap;
57 import com.google.android.gms.wearable.DataMapItem;
58 import com.google.android.gms.wearable.MessageApi;
59 import com.google.android.gms.wearable.MessageEvent;
60 import com.google.android.gms.wearable.Node;
61 import com.google.android.gms.wearable.NodeApi;
62 import com.google.android.gms.wearable.PutDataMapRequest;
63 import com.google.android.gms.wearable.PutDataRequest;
64 import com.google.android.gms.wearable.Wearable;
65 
66 import org.json.JSONArray;
67 import org.json.JSONException;
68 import org.json.JSONObject;
69 
70 import java.io.IOException;
71 import java.util.ArrayList;
72 import java.util.Collections;
73 import java.util.HashMap;
74 import java.util.List;
75 import java.util.Map;
76 import java.util.PriorityQueue;
77 
78 /**
79  * Allows the user to create questions, which will be put as notifications on the watch's stream.
80  * The status of questions will be updated on the phone when the user answers them.
81  */
82 public class MainActivity extends Activity implements DataApi.DataListener,
83         MessageApi.MessageListener, ConnectionCallbacks,
84         GoogleApiClient.OnConnectionFailedListener {
85 
86     private static final String TAG = "ExampleQuizApp";
87     private static final String QUIZ_JSON_FILE = "Quiz.json";
88 
89     // Various UI components.
90     private EditText questionEditText;
91     private EditText choiceAEditText;
92     private EditText choiceBEditText;
93     private EditText choiceCEditText;
94     private EditText choiceDEditText;
95     private RadioGroup choicesRadioGroup;
96     private TextView quizStatus;
97     private LinearLayout quizButtons;
98     private LinearLayout questionsContainer;
99     private Button readQuizFromFileButton;
100     private Button resetQuizButton;
101 
102     private GoogleApiClient mGoogleApiClient;
103     private PriorityQueue<Question> mFutureQuestions;
104     private int mQuestionIndex = 0;
105     private boolean mHasQuestionBeenAsked = false;
106 
107     // Data to display in end report.
108     private int mNumCorrect = 0;
109     private int mNumIncorrect = 0;
110     private int mNumSkipped = 0;
111 
112     private static final Map<Integer, Integer> radioIdToIndex;
113 
114     static {
115         Map<Integer, Integer> temp = new HashMap<Integer, Integer>(4);
temp.put(R.id.choice_a_radio, 0)116         temp.put(R.id.choice_a_radio, 0);
temp.put(R.id.choice_b_radio, 1)117         temp.put(R.id.choice_b_radio, 1);
temp.put(R.id.choice_c_radio, 2)118         temp.put(R.id.choice_c_radio, 2);
temp.put(R.id.choice_d_radio, 3)119         temp.put(R.id.choice_d_radio, 3);
120         radioIdToIndex = Collections.unmodifiableMap(temp);
121     }
122 
123     @Override
onCreate(Bundle savedInstanceState)124     protected void onCreate(Bundle savedInstanceState) {
125         super.onCreate(savedInstanceState);
126         setContentView(R.layout.main);
127 
128         mGoogleApiClient = new GoogleApiClient.Builder(this)
129                 .addApi(Wearable.API)
130                 .addConnectionCallbacks(this)
131                 .addOnConnectionFailedListener(this)
132                 .build();
133         mFutureQuestions = new PriorityQueue<Question>(10);
134 
135         // Find UI components to be used later.
136         questionEditText = (EditText) findViewById(R.id.question_text);
137         choiceAEditText = (EditText) findViewById(R.id.choice_a_text);
138         choiceBEditText = (EditText) findViewById(R.id.choice_b_text);
139         choiceCEditText = (EditText) findViewById(R.id.choice_c_text);
140         choiceDEditText = (EditText) findViewById(R.id.choice_d_text);
141         choicesRadioGroup = (RadioGroup) findViewById(R.id.choices_radio_group);
142         quizStatus = (TextView) findViewById(R.id.quiz_status);
143         quizButtons = (LinearLayout) findViewById(R.id.quiz_buttons);
144         questionsContainer = (LinearLayout) findViewById(R.id.questions_container);
145         readQuizFromFileButton = (Button) findViewById(R.id.read_quiz_from_file_button);
146         resetQuizButton = (Button) findViewById(R.id.reset_quiz_button);
147     }
148 
149     @Override
onStart()150     protected void onStart() {
151         super.onStart();
152         if (!mGoogleApiClient.isConnected()) {
153             mGoogleApiClient.connect();
154         }
155     }
156 
157     @Override
onStop()158     protected void onStop() {
159         Wearable.DataApi.removeListener(mGoogleApiClient, this);
160         Wearable.MessageApi.removeListener(mGoogleApiClient, this);
161 
162         // Tell the wearable to end the quiz (counting unanswered questions as skipped), and then
163         // disconnect mGoogleApiClient.
164         DataMap dataMap = new DataMap();
165         dataMap.putInt(NUM_CORRECT, mNumCorrect);
166         dataMap.putInt(NUM_INCORRECT, mNumIncorrect);
167         if (mHasQuestionBeenAsked) {
168             mNumSkipped += 1;
169         }
170         mNumSkipped += mFutureQuestions.size();
171         dataMap.putInt(NUM_SKIPPED, mNumSkipped);
172         if (mNumCorrect + mNumIncorrect + mNumSkipped > 0) {
173             sendMessageToWearable(QUIZ_EXITED_PATH, dataMap.toByteArray());
174         }
175 
176         clearQuizStatus();
177         super.onStop();
178     }
179 
180     @Override
onConnected(Bundle connectionHint)181     public void onConnected(Bundle connectionHint) {
182         Wearable.DataApi.addListener(mGoogleApiClient, this);
183         Wearable.MessageApi.addListener(mGoogleApiClient, this);
184     }
185 
186     @Override
onConnectionSuspended(int cause)187     public void onConnectionSuspended(int cause) {
188         // Ignore
189     }
190 
191     @Override
onConnectionFailed(ConnectionResult result)192     public void onConnectionFailed(ConnectionResult result) {
193         Log.e(TAG, "Failed to connect to Google Play Services");
194     }
195 
196     @Override
onMessageReceived(MessageEvent messageEvent)197     public void onMessageReceived(MessageEvent messageEvent) {
198         if (messageEvent.getPath().equals(RESET_QUIZ_PATH)) {
199             runOnUiThread(new Runnable() {
200                 @Override
201                 public void run() {
202                     resetQuiz(null);
203                 }
204             });
205         }
206     }
207 
208     /**
209      * Used to ensure questions with smaller indexes come before questions with larger
210      * indexes. For example, question0 should come before question1.
211      */
212     private static class Question implements Comparable<Question> {
213         private String question;
214         private int questionIndex;
215         private String[] answers;
216         private int correctAnswerIndex;
217 
Question(String question, int questionIndex, String[] answers, int correctAnswerIndex)218         public Question(String question, int questionIndex, String[] answers,
219                 int correctAnswerIndex) {
220             this.question = question;
221             this.questionIndex = questionIndex;
222             this.answers = answers;
223             this.correctAnswerIndex = correctAnswerIndex;
224         }
225 
fromJson(JSONObject questionObject, int questionIndex)226         public static Question fromJson(JSONObject questionObject, int questionIndex)
227                 throws JSONException {
228             String question = questionObject.getString(JsonUtils.JSON_FIELD_QUESTION);
229             JSONArray answersJsonArray = questionObject.getJSONArray(JsonUtils.JSON_FIELD_ANSWERS);
230             String[] answers = new String[JsonUtils.NUM_ANSWER_CHOICES];
231             for (int j = 0; j < answersJsonArray.length(); j++) {
232                 answers[j] = answersJsonArray.getString(j);
233             }
234             int correctIndex = questionObject.getInt(JsonUtils.JSON_FIELD_CORRECT_INDEX);
235             return new Question(question, questionIndex, answers, correctIndex);
236         }
237 
238         @Override
compareTo(Question that)239         public int compareTo(Question that) {
240             return this.questionIndex - that.questionIndex;
241         }
242 
toPutDataRequest()243         public PutDataRequest toPutDataRequest() {
244             PutDataMapRequest request = PutDataMapRequest.create("/question/" + questionIndex);
245             DataMap dataMap = request.getDataMap();
246             dataMap.putString(QUESTION, question);
247             dataMap.putInt(QUESTION_INDEX, questionIndex);
248             dataMap.putStringArray(ANSWERS, answers);
249             dataMap.putInt(CORRECT_ANSWER_INDEX, correctAnswerIndex);
250             return request.asPutDataRequest();
251         }
252     }
253 
254     /**
255      * Create a quiz, as defined in Quiz.json, when the user clicks on "Read quiz from file."
256      * @throws IOException
257      */
readQuizFromFile(View view)258     public void readQuizFromFile(View view) throws IOException, JSONException {
259         clearQuizStatus();
260         JSONObject jsonObject = JsonUtils.loadJsonFile(this, QUIZ_JSON_FILE);
261         JSONArray jsonArray = jsonObject.getJSONArray(JsonUtils.JSON_FIELD_QUESTIONS);
262         for (int i = 0; i < jsonArray.length(); i++) {
263             JSONObject questionObject = jsonArray.getJSONObject(i);
264             Question question = Question.fromJson(questionObject, mQuestionIndex++);
265             addQuestionDataItem(question);
266             setNewQuestionStatus(question.question);
267         }
268     }
269 
270     /**
271      * Adds a question (with answer choices) when user clicks on "Add Question."
272      */
addQuestion(View view)273     public void addQuestion(View view) {
274         // Retrieve the question and answers supplied by the user.
275         String question = questionEditText.getText().toString();
276         String[] answers = new String[4];
277         answers[0] = choiceAEditText.getText().toString();
278         answers[1] = choiceBEditText.getText().toString();
279         answers[2] = choiceCEditText.getText().toString();
280         answers[3] = choiceDEditText.getText().toString();
281         int correctAnswerIndex = radioIdToIndex.get(choicesRadioGroup.getCheckedRadioButtonId());
282 
283         addQuestionDataItem(new Question(question, mQuestionIndex++, answers, correctAnswerIndex));
284         setNewQuestionStatus(question);
285 
286         // Clear the edit boxes to let the user input a new question.
287         questionEditText.setText("");
288         choiceAEditText.setText("");
289         choiceBEditText.setText("");
290         choiceCEditText.setText("");
291         choiceDEditText.setText("");
292     }
293 
294     /**
295      * Adds the questions (and answers) to the wearable's stream by creating a Data Item
296      * that will be received on the wearable, which will create corresponding notifications.
297      */
addQuestionDataItem(Question question)298     private void addQuestionDataItem(Question question) {
299         if (!mHasQuestionBeenAsked) {
300             // Ask the question now.
301             Wearable.DataApi.putDataItem(mGoogleApiClient, question.toPutDataRequest());
302             setHasQuestionBeenAsked(true);
303         } else {
304             // Enqueue the question to be asked in the future.
305             mFutureQuestions.add(question);
306         }
307     }
308 
309     /**
310      * Sets the question's status to be the default "unanswered." This will be updated when the
311      * user chooses an answer for the question on the wearable.
312      */
setNewQuestionStatus(String question)313     private void setNewQuestionStatus(String question) {
314         quizStatus.setVisibility(View.VISIBLE);
315         quizButtons.setVisibility(View.VISIBLE);
316         LayoutInflater inflater = LayoutInflater.from(this);
317         View questionStatusElem = inflater.inflate(R.layout.question_status_element, null, false);
318         ((TextView) questionStatusElem.findViewById(R.id.question)).setText(question);
319         ((TextView) questionStatusElem.findViewById(R.id.status))
320                 .setText(R.string.question_unanswered);
321         questionsContainer.addView(questionStatusElem);
322     }
323 
324     @Override
onDataChanged(DataEventBuffer dataEvents)325     public void onDataChanged(DataEventBuffer dataEvents) {
326         final List<DataEvent> events = FreezableUtils.freezeIterable(dataEvents);
327         dataEvents.close();
328         runOnUiThread(new Runnable() {
329             @Override
330             public void run() {
331                 for (DataEvent event : events) {
332                     if (event.getType() == DataEvent.TYPE_CHANGED) {
333                         DataMap dataMap = DataMapItem.fromDataItem(event.getDataItem())
334                                 .getDataMap();
335                         boolean questionWasAnswered = dataMap.getBoolean(QUESTION_WAS_ANSWERED);
336                         boolean questionWasDeleted = dataMap.getBoolean(QUESTION_WAS_DELETED);
337                         if (questionWasAnswered) {
338                             // Update the answered question's status.
339                             int questionIndex = dataMap.getInt(QUESTION_INDEX);
340                             boolean questionCorrect = dataMap.getBoolean(CHOSEN_ANSWER_CORRECT);
341                             updateQuestionStatus(questionIndex, questionCorrect);
342                             askNextQuestionIfExists();
343                         } else if (questionWasDeleted) {
344                             // Update the deleted question's status by marking it as left blank.
345                             int questionIndex = dataMap.getInt(QUESTION_INDEX);
346                             markQuestionLeftBlank(questionIndex);
347                             askNextQuestionIfExists();
348                         }
349                     }
350                 }
351             }
352         });
353     }
354 
355     /**
356      * Updates the given question based on whether it was answered correctly or not.
357      * This involves changing the question's text color and changing the status text for it.
358      */
updateQuestionStatus(int questionIndex, boolean questionCorrect)359     public void updateQuestionStatus(int questionIndex, boolean questionCorrect) {
360         LinearLayout questionStatusElement = (LinearLayout)
361                 questionsContainer.getChildAt(questionIndex);
362         TextView questionText = (TextView) questionStatusElement.findViewById(R.id.question);
363         TextView questionStatus = (TextView) questionStatusElement.findViewById(R.id.status);
364         if (questionCorrect) {
365             questionText.setTextColor(Color.GREEN);
366             questionStatus.setText(R.string.question_correct);
367             mNumCorrect++;
368         } else {
369             questionText.setTextColor(Color.RED);
370             questionStatus.setText(R.string.question_incorrect);
371             mNumIncorrect++;
372         }
373     }
374 
375     /**
376      * Marks a question as "left blank" when its corresponding question notification is deleted.
377      */
markQuestionLeftBlank(int index)378     private void markQuestionLeftBlank(int index) {
379         LinearLayout questionStatusElement = (LinearLayout) questionsContainer.getChildAt(index);
380         if (questionStatusElement != null) {
381             TextView questionText = (TextView) questionStatusElement.findViewById(R.id.question);
382             TextView questionStatus = (TextView) questionStatusElement.findViewById(R.id.status);
383             if (questionStatus.getText().equals(getString(R.string.question_unanswered))) {
384                 questionText.setTextColor(Color.YELLOW);
385                 questionStatus.setText(R.string.question_left_blank);
386                 mNumSkipped++;
387             }
388         }
389     }
390 
391     /**
392      * Asks the next enqueued question if it exists, otherwise ends the quiz.
393      */
askNextQuestionIfExists()394     private void askNextQuestionIfExists() {
395         if (mFutureQuestions.isEmpty()) {
396             // Quiz has been completed - send message to wearable to display end report.
397             DataMap dataMap = new DataMap();
398             dataMap.putInt(NUM_CORRECT, mNumCorrect);
399             dataMap.putInt(NUM_INCORRECT, mNumIncorrect);
400             dataMap.putInt(NUM_SKIPPED, mNumSkipped);
401             sendMessageToWearable(QUIZ_ENDED_PATH, dataMap.toByteArray());
402             setHasQuestionBeenAsked(false);
403         } else {
404             // Ask next question by putting a DataItem that will be received on the wearable.
405             Wearable.DataApi.putDataItem(mGoogleApiClient,
406                     mFutureQuestions.remove().toPutDataRequest());
407             setHasQuestionBeenAsked(true);
408         }
409     }
410 
sendMessageToWearable(final String path, final byte[] data)411     private void sendMessageToWearable(final String path, final byte[] data) {
412         Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).setResultCallback(
413                 new ResultCallback<NodeApi.GetConnectedNodesResult>() {
414             @Override
415             public void onResult(NodeApi.GetConnectedNodesResult nodes) {
416                 for (Node node : nodes.getNodes()) {
417                     Wearable.MessageApi.sendMessage(mGoogleApiClient, node.getId(), path, data);
418                 }
419 
420                 if (path.equals(QUIZ_EXITED_PATH) && mGoogleApiClient.isConnected()) {
421                     mGoogleApiClient.disconnect();
422                 }
423             }
424         });
425     }
426 
427     /**
428      * Resets the current quiz when Reset Quiz is pressed.
429      */
resetQuiz(View view)430     public void resetQuiz(View view) {
431         // Reset quiz status in phone layout.
432         for(int i = 0; i < questionsContainer.getChildCount(); i++) {
433             LinearLayout questionStatusElement = (LinearLayout) questionsContainer.getChildAt(i);
434             TextView questionText = (TextView) questionStatusElement.findViewById(R.id.question);
435             TextView questionStatus = (TextView) questionStatusElement.findViewById(R.id.status);
436             questionText.setTextColor(Color.WHITE);
437             questionStatus.setText(R.string.question_unanswered);
438         }
439         // Reset data items and notifications on wearable.
440         if (mGoogleApiClient.isConnected()) {
441             Wearable.DataApi.getDataItems(mGoogleApiClient)
442                     .setResultCallback(new ResultCallback<DataItemBuffer>() {
443                         @Override
444                         public void onResult(DataItemBuffer result) {
445                             if (result.getStatus().isSuccess()) {
446                                 List<DataItem> dataItemList = FreezableUtils.freezeIterable(result);
447                                 result.close();
448                                 resetDataItems(dataItemList);
449                             } else {
450                                 if (Log.isLoggable(TAG, Log.DEBUG)) {
451                                     Log.d(TAG, "Reset quiz: failed to get Data Items to reset");
452                                 }
453                             }
454                             result.close();
455                         }
456                     });
457         } else {
458             Log.e(TAG, "Failed to reset data items because client is disconnected from "
459                     + "Google Play Services");
460         }
461         setHasQuestionBeenAsked(false);
462         mNumCorrect = 0;
463         mNumIncorrect = 0;
464         mNumSkipped = 0;
465     }
466 
resetDataItems(List<DataItem> dataItemList)467     private void resetDataItems(List<DataItem> dataItemList) {
468         if (mGoogleApiClient.isConnected()) {
469             for (final DataItem dataItem : dataItemList) {
470                 final Uri dataItemUri = dataItem.getUri();
471                 Wearable.DataApi.getDataItem(mGoogleApiClient, dataItemUri)
472                         .setResultCallback(new ResetDataItemCallback());
473             }
474         } else {
475             Log.e(TAG, "Failed to reset data items because client is disconnected from "
476                     + "Google Play Services");
477         }
478     }
479 
480     /**
481      * Callback that marks a DataItem, which represents a question, as unanswered and not deleted.
482      */
483     private class ResetDataItemCallback implements ResultCallback<DataApi.DataItemResult> {
484         @Override
onResult(DataApi.DataItemResult dataItemResult)485         public void onResult(DataApi.DataItemResult dataItemResult) {
486             if (dataItemResult.getStatus().isSuccess()) {
487                 PutDataMapRequest request = PutDataMapRequest.createFromDataMapItem(
488                                 DataMapItem.fromDataItem(dataItemResult.getDataItem()));
489                 DataMap dataMap = request.getDataMap();
490                 dataMap.putBoolean(QUESTION_WAS_ANSWERED, false);
491                 dataMap.putBoolean(QUESTION_WAS_DELETED, false);
492                 if (!mHasQuestionBeenAsked && dataMap.getInt(QUESTION_INDEX) == 0) {
493                     // Ask the first question now.
494                     Wearable.DataApi.putDataItem(mGoogleApiClient, request.asPutDataRequest());
495                     setHasQuestionBeenAsked(true);
496                 } else {
497                     // Enqueue future questions.
498                     mFutureQuestions.add(new Question(dataMap.getString(QUESTION),
499                             dataMap.getInt(QUESTION_INDEX), dataMap.getStringArray(ANSWERS),
500                             dataMap.getInt(CORRECT_ANSWER_INDEX)));
501                 }
502             } else {
503                 Log.e(TAG, "Failed to reset data item " + dataItemResult.getDataItem().getUri());
504             }
505         }
506     }
507 
508     /**
509      * Clears the current quiz when user clicks on "New Quiz."
510      * On this end, this involves clearing the quiz status layout and deleting all DataItems. The
511      * wearable will then remove any outstanding question notifications upon receiving this change.
512      */
newQuiz(View view)513     public void newQuiz(View view) {
514         clearQuizStatus();
515         if (mGoogleApiClient.isConnected()) {
516             Wearable.DataApi.getDataItems(mGoogleApiClient)
517                     .setResultCallback(new ResultCallback<DataItemBuffer>() {
518                         @Override
519                         public void onResult(DataItemBuffer result) {
520                             if (result.getStatus().isSuccess()) {
521                                 List<Uri> dataItemUriList = new ArrayList<Uri>();
522                                 for (final DataItem dataItem : result) {
523                                     dataItemUriList.add(dataItem.getUri());
524                                 }
525                                 result.close();
526                                 deleteDataItems(dataItemUriList);
527                             } else {
528                                 if (Log.isLoggable(TAG, Log.DEBUG)) {
529                                     Log.d(TAG, "Clear quiz: failed to get Data Items for deletion");
530                                 }
531                             }
532                             result.close();
533                         }
534                     });
535         } else {
536             Log.e(TAG, "Failed to delete data items because client is disconnected from "
537                     + "Google Play Services");
538         }
539     }
540 
541     /**
542      * Removes quiz status views (i.e. the views describing the status of each question).
543      */
clearQuizStatus()544     private void clearQuizStatus() {
545         questionsContainer.removeAllViews();
546         quizStatus.setVisibility(View.INVISIBLE);
547         quizButtons.setVisibility(View.INVISIBLE);
548         setHasQuestionBeenAsked(false);
549         mFutureQuestions.clear();
550         mQuestionIndex = 0;
551         mNumCorrect = 0;
552         mNumIncorrect = 0;
553         mNumSkipped = 0;
554     }
555 
deleteDataItems(List<Uri> dataItemUriList)556     private void deleteDataItems(List<Uri> dataItemUriList) {
557         if (mGoogleApiClient.isConnected()) {
558             for (final Uri dataItemUri : dataItemUriList) {
559                 Wearable.DataApi.deleteDataItems(mGoogleApiClient, dataItemUri)
560                         .setResultCallback(new ResultCallback<DataApi.DeleteDataItemsResult>() {
561                             @Override
562                             public void onResult(DataApi.DeleteDataItemsResult deleteResult) {
563                                 if (Log.isLoggable(TAG, Log.DEBUG)) {
564                                     if (deleteResult.getStatus().isSuccess()) {
565                                         Log.d(TAG, "Successfully deleted data item " + dataItemUri);
566                                     } else {
567                                         Log.d(TAG, "Failed to delete data item " + dataItemUri);
568                                     }
569                                 }
570                             }
571                         });
572             }
573         } else {
574             Log.e(TAG, "Failed to delete data items because client is disconnected from "
575                     + "Google Play Services");
576         }
577     }
578 
setHasQuestionBeenAsked(boolean b)579     private void setHasQuestionBeenAsked(boolean b) {
580         mHasQuestionBeenAsked = b;
581         // Only let user click on Reset or Read from file if they have answered all the questions.
582         readQuizFromFileButton.setEnabled(!mHasQuestionBeenAsked);
583         resetQuizButton.setEnabled(!mHasQuestionBeenAsked);
584     }
585 }
586