• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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.android.cts.verifier;
18 
19 import static com.android.cts.verifier.TestListActivity.sCurrentDisplayMode;
20 import static com.android.cts.verifier.TestListAdapter.setTestNameSuffix;
21 
22 import android.app.ActionBar;
23 import android.app.AlertDialog;
24 import android.app.Dialog;
25 import android.content.ContentResolver;
26 import android.content.ContentValues;
27 import android.content.Context;
28 import android.content.DialogInterface;
29 import android.content.DialogInterface.OnCancelListener;
30 import android.content.pm.PackageManager;
31 import android.database.Cursor;
32 import android.os.Bundle;
33 import android.os.PowerManager;
34 import android.os.PowerManager.WakeLock;
35 import android.view.LayoutInflater;
36 import android.view.MenuItem;
37 import android.view.View;
38 import android.view.View.OnClickListener;
39 import android.widget.ImageButton;
40 import android.widget.Toast;
41 
42 import com.android.compatibility.common.util.ReportLog;
43 
44 import java.util.List;
45 import java.util.stream.Collectors;
46 import java.util.stream.IntStream;
47 
48 /**
49  * {@link Activity}s to handle clicks to the pass and fail buttons of the pass fail buttons layout.
50  *
51  * <ol>
52  *     <li>Include the pass fail buttons layout in your layout:
53  *         <pre><include layout="@layout/pass_fail_buttons" /></pre>
54  *     </li>
55  *     <li>Extend one of the activities and call setPassFailButtonClickListeners after
56  *         setting your content view.</li>
57  *     <li>Make sure to call setResult(RESULT_CANCEL) in your Activity initially.</li>
58  *     <li>Optionally call setInfoTextResources to add an info button that will show a
59  *         dialog with instructional text.</li>
60  * </ol>
61  */
62 public class PassFailButtons {
63     private static final String INFO_TAG = "CtsVerifierInstructions";
64 
65     // Need different IDs for these alerts or else the first one created
66     // will just be reused, with the old title/message.
67     private static final int INFO_DIALOG_ID = 1337;
68     private static final int REPORTLOG_DIALOG_ID = 1338;
69 
70     private static final String INFO_DIALOG_VIEW_ID = "infoDialogViewId";
71     private static final String INFO_DIALOG_TITLE_ID = "infoDialogTitleId";
72     private static final String INFO_DIALOG_MESSAGE_ID = "infoDialogMessageId";
73 
74     // ReportLog file for CTS-Verifier. The "stream" name gets mapped to the test class name.
75     public static final String GENERAL_TESTS_REPORT_LOG_NAME = "CtsVerifierGeneralTestCases";
76     public static final String AUDIO_TESTS_REPORT_LOG_NAME = "CtsVerifierAudioTestCases";
77 
78     private static final String SECTION_UNDEFINED = "undefined_section_name";
79 
80     // Interface mostly for making documentation and refactoring easier...
81     public interface PassFailActivity {
82 
83         /**
84          * Hooks up the pass and fail buttons to click listeners that will record the test results.
85          * <p>
86          * Call from {@link Activity#onCreate} after {@link Activity #setContentView(int)}.
87          */
setPassFailButtonClickListeners()88         void setPassFailButtonClickListeners();
89 
90         /**
91          * Adds an initial informational dialog that appears when entering the test activity for
92          * the first time. Also enables the visibility of an "Info" button between the "Pass" and
93          * "Fail" buttons that can be clicked to show the information dialog again.
94          * <p>
95          * Call from {@link Activity#onCreate} after {@link Activity #setContentView(int)}.
96          *
97          * @param titleId for the text shown in the dialog title area
98          * @param messageId for the text shown in the dialog's body area
99          */
setInfoResources(int titleId, int messageId, int viewId)100         void setInfoResources(int titleId, int messageId, int viewId);
101 
getPassButton()102         View getPassButton();
103 
104         /**
105          * Returns a unique identifier for the test.  Usually, this is just the class name.
106          */
getTestId()107         String getTestId();
108 
109         /** @return null or details about the test run. */
getTestDetails()110         String getTestDetails();
111 
112         /**
113          * Set the result of the test and finish the activity.
114          *
115          * @param passed Whether or not the test passed.
116          */
setTestResultAndFinish(boolean passed)117         void setTestResultAndFinish(boolean passed);
118 
119         /**
120          * @return true if the test module will write a ReportLog entry
121          *
122          * Note that in order to obtain a non-null CtsVerifierReportLog object from
123          * the getReportLog() method, the activity must override this method to return true
124          * and should implement the getReportFileName(), getReportSectionName() and
125          * recordTestResults() methods.
126          *
127          * If this method returns true and the user did not setup up CtsVerifier correctly
128          * with respect to accessing local data on the DUT;
129          * <code>
130          * adb shell appops set com.android.cts.verifier android:read_device_identifiers allow
131          * adb shell appops set com.android.cts.verifier MANAGE_EXTERNAL_STORAGE 0
132          * </code>
133          * a warning dialog will be displayed when invoking that test.
134          */
requiresReportLog()135         public boolean requiresReportLog();
136 
137         /**
138          * @return The name of the file to store the (suite of) ReportLog information.
139          *
140          * If a test uses the CtsVerifierReportLog, it should implement this method to provide
141          * a file name for the (JSON) report log data. This does not need to be unique to the
142          * test, perhaps specific to a set of related tests.
143          */
getReportFileName()144         public String getReportFileName();
145 
146         /**
147          * @return A unique name to serve as a section header in the CtsVerifierReportLog file.
148          * Tests need to conform to the underscore_delineated_name standard for use with
149          * the protobuff/json ReportLog parsing in Google3
150          *
151          * If the test implements this method, it should also implement the requiresReportLog()
152          * method to return true and the getReportFileName() and recordTestResults() methods.
153          */
getReportSectionName()154         public String getReportSectionName();
155 
156         /**
157          * Test subclasses can override this to record their CtsVerifierReportLogs.
158          * This is called when the test is exited.
159          *
160          * NOTE: If the test gathers reportLog data, the test class should implement
161          * the requiresReportLog() to return true, and implement the getReportFileName() and
162          * getReportSectionName() methods.
163          */
recordTestResults()164         void recordTestResults();
165 
166         /**
167          * @return A {@link ReportLog} that is used to record test metric data or null.
168          *
169          * If a test calls this method it must implement the requiresReportLog() to return true,
170          * and implement the getReportFileName() and getReportSectionName() methods, otherwise
171          * this method will return null.
172          */
getReportLog()173         CtsVerifierReportLog getReportLog();
174 
175         /**
176          * @return A {@link TestResultHistoryCollection} that is used to record test execution time.
177          */
getHistoryCollection()178         TestResultHistoryCollection getHistoryCollection();
179     }   /* class PassFailButtons.PassFailActivity */
180 
181     public static class Activity extends android.app.Activity implements PassFailActivity {
182         private WakeLock mWakeLock;
183         private CtsVerifierReportLog mReportLog;
184         private final TestResultHistoryCollection mHistoryCollection;
185 
186         protected boolean mRequireReportLogToPass;
187 
Activity()188         public Activity() {
189             this.mHistoryCollection = new TestResultHistoryCollection();
190             if (requiresReportLog()) {
191                 // if the subclass reports a report filename, they need a ReportLog object
192                 newReportLog();
193             }
194         }
195 
196         @Override
onResume()197         protected void onResume() {
198             super.onResume();
199             if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
200                 mWakeLock = ((PowerManager) getSystemService(Context.POWER_SERVICE))
201                         .newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "PassFailButtons");
202                 mWakeLock.acquire();
203             }
204 
205             if (mReportLog != null && !mReportLog.isOpen()) {
206                 showReportLogWarningDialog(this);
207             }
208         }
209 
210         @Override
onPause()211         protected void onPause() {
212             super.onPause();
213             if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
214                 mWakeLock.release();
215             }
216         }
217 
218         @Override
setPassFailButtonClickListeners()219         public void setPassFailButtonClickListeners() {
220             setPassFailClickListeners(this);
221         }
222 
223         @Override
setInfoResources(int titleId, int messageId, int viewId)224         public void setInfoResources(int titleId, int messageId, int viewId) {
225             setInfo(this, titleId, messageId, viewId);
226         }
227 
228         @Override
getPassButton()229         public View getPassButton() {
230             return getPassButtonView(this);
231         }
232 
233         @Override
onCreateDialog(int id, Bundle args)234         public Dialog onCreateDialog(int id, Bundle args) {
235             return createDialog(this, id, args);
236         }
237 
238         @Override
getTestId()239         public String getTestId() {
240             return setTestNameSuffix(sCurrentDisplayMode, getClass().getName());
241         }
242 
243         @Override
getTestDetails()244         public String getTestDetails() {
245             return null;
246         }
247 
248         @Override
setTestResultAndFinish(boolean passed)249         public void setTestResultAndFinish(boolean passed) {
250             PassFailButtons.setTestResultAndFinishHelper(
251                     this, getTestId(), getTestDetails(), passed, getReportLog(),
252                     getHistoryCollection());
253         }
254 
newReportLog()255         protected CtsVerifierReportLog newReportLog() {
256             return mReportLog = new CtsVerifierReportLog(
257                     getReportFileName(), getReportSectionName());
258         }
259 
260         @Override
requiresReportLog()261         public boolean requiresReportLog() {
262             return false;
263         }
264 
265         @Override
getReportLog()266         public CtsVerifierReportLog getReportLog() {
267             return mReportLog;
268         }
269 
270         /**
271          * A mechanism to block tests from passing if no ReportLog data has been collected.
272          * @return true if the ReportLog is open OR if the test does not require that.
273          */
isReportLogOkToPass()274         public boolean isReportLogOkToPass() {
275             return !mRequireReportLogToPass || (mReportLog != null & mReportLog.isOpen());
276         }
277 
278         /**
279          * @return The name of the file to store the (suite of) ReportLog information.
280          */
281         @Override
getReportFileName()282         public String getReportFileName() { return GENERAL_TESTS_REPORT_LOG_NAME; }
283 
284         @Override
getReportSectionName()285         public String getReportSectionName() {
286             return setTestNameSuffix(sCurrentDisplayMode, SECTION_UNDEFINED);
287         }
288 
289         @Override
getHistoryCollection()290         public TestResultHistoryCollection getHistoryCollection() { return mHistoryCollection; }
291 
292         @Override
onCreate(Bundle savedInstanceState)293         protected void onCreate(Bundle savedInstanceState) {
294             super.onCreate(savedInstanceState);
295             ActionBar actBar = getActionBar();
296             if (actBar != null) {
297                 actBar.setDisplayHomeAsUpEnabled(true);
298             }
299         }
300 
301         @Override
onOptionsItemSelected(MenuItem item)302         public boolean onOptionsItemSelected(MenuItem item) {
303             if (item.getItemId() == android.R.id.home) {
304                 onBackPressed();
305                 return true;
306             }
307             return super.onOptionsItemSelected(item);
308         }
309 
310         @Override
recordTestResults()311         public void recordTestResults() {
312             // default - NOP
313         }
314     }   /* class PassFailButtons.Activity */
315 
316     public static class ListActivity extends android.app.ListActivity implements PassFailActivity {
317 
318         private final CtsVerifierReportLog mReportLog;
319         private final TestResultHistoryCollection mHistoryCollection;
320 
ListActivity()321         public ListActivity() {
322             mHistoryCollection = new TestResultHistoryCollection();
323             mReportLog = null;
324         }
325 
326         @Override
setPassFailButtonClickListeners()327         public void setPassFailButtonClickListeners() {
328             setPassFailClickListeners(this);
329         }
330 
331         @Override
setInfoResources(int titleId, int messageId, int viewId)332         public void setInfoResources(int titleId, int messageId, int viewId) {
333             setInfo(this, titleId, messageId, viewId);
334         }
335 
336         @Override
getPassButton()337         public View getPassButton() {
338             return getPassButtonView(this);
339         }
340 
341         @Override
onCreateDialog(int id, Bundle args)342         public Dialog onCreateDialog(int id, Bundle args) {
343             return createDialog(this, id, args);
344         }
345 
346         @Override
getTestId()347         public String getTestId() {
348             return setTestNameSuffix(sCurrentDisplayMode, getClass().getName());
349         }
350 
351         @Override
getTestDetails()352         public String getTestDetails() {
353             return null;
354         }
355 
356         @Override
setTestResultAndFinish(boolean passed)357         public void setTestResultAndFinish(boolean passed) {
358             PassFailButtons.setTestResultAndFinishHelper(
359                     this, getTestId(), getTestDetails(), passed, getReportLog(),
360                     getHistoryCollection());
361         }
362 
363         @Override
requiresReportLog()364         public boolean requiresReportLog() {
365             return false;
366         }
367 
368         @Override
getReportLog()369         public CtsVerifierReportLog getReportLog() {
370             return mReportLog;
371         }
372 
373         /**
374          * @return The name of the file to store the (suite of) ReportLog information.
375          */
376         @Override
getReportFileName()377         public String getReportFileName() { return GENERAL_TESTS_REPORT_LOG_NAME; }
378 
379         @Override
getReportSectionName()380         public String getReportSectionName() {
381             return setTestNameSuffix(sCurrentDisplayMode, SECTION_UNDEFINED);
382         }
383 
384         @Override
getHistoryCollection()385         public TestResultHistoryCollection getHistoryCollection() { return mHistoryCollection; }
386 
387         @Override
onCreate(Bundle savedInstanceState)388         protected void onCreate(Bundle savedInstanceState) {
389             super.onCreate(savedInstanceState);
390             ActionBar actBar = getActionBar();
391             if (actBar != null) {
392                 actBar.setDisplayHomeAsUpEnabled(true);
393             }
394         }
395 
396         @Override
onOptionsItemSelected(MenuItem item)397         public boolean onOptionsItemSelected(MenuItem item) {
398             if (item.getItemId() == android.R.id.home) {
399                 onBackPressed();
400                 return true;
401             }
402             return super.onOptionsItemSelected(item);
403         }
404 
405         @Override
recordTestResults()406         public void recordTestResults() {
407             // default - NOP
408         }
409     } // class PassFailButtons.ListActivity
410 
411     public static class TestListActivity extends AbstractTestListActivity
412             implements PassFailActivity {
413 
414         private final CtsVerifierReportLog mReportLog;
415 
TestListActivity()416         public TestListActivity() {
417             // TODO(b/186555602): temporary hack^H^H^H^H workaround to fix crash
418             // This DOES NOT in fact fix that bug.
419             // if (true) this.mReportLog = new CtsVerifierReportLog(b/186555602, "42"); else
420 
421             this.mReportLog = new CtsVerifierReportLog(getReportFileName(), getReportSectionName());
422         }
423 
424         @Override
setPassFailButtonClickListeners()425         public void setPassFailButtonClickListeners() {
426             setPassFailClickListeners(this);
427         }
428 
429         @Override
setInfoResources(int titleId, int messageId, int viewId)430         public void setInfoResources(int titleId, int messageId, int viewId) {
431             setInfo(this, titleId, messageId, viewId);
432         }
433 
434         @Override
getPassButton()435         public View getPassButton() {
436             return getPassButtonView(this);
437         }
438 
439         @Override
onCreateDialog(int id, Bundle args)440         public Dialog onCreateDialog(int id, Bundle args) {
441             return createDialog(this, id, args);
442         }
443 
444         @Override
getTestId()445         public String getTestId() {
446             return setTestNameSuffix(sCurrentDisplayMode, getClass().getName());
447         }
448 
449         @Override
getTestDetails()450         public String getTestDetails() {
451             return null;
452         }
453 
454         @Override
setTestResultAndFinish(boolean passed)455         public void setTestResultAndFinish(boolean passed) {
456             PassFailButtons.setTestResultAndFinishHelper(
457                     this, getTestId(), getTestDetails(), passed, getReportLog(),
458                     getHistoryCollection());
459         }
460 
461         @Override
requiresReportLog()462         public boolean requiresReportLog() {
463             return false;
464         }
465 
466         @Override
getReportLog()467         public CtsVerifierReportLog getReportLog() {
468             return mReportLog;
469         }
470 
471         /**
472          * @return The name of the file to store the (suite of) ReportLog information.
473          */
474         @Override
getReportFileName()475         public String getReportFileName() { return GENERAL_TESTS_REPORT_LOG_NAME; }
476 
477         @Override
getReportSectionName()478         public String getReportSectionName() {
479             return setTestNameSuffix(sCurrentDisplayMode, SECTION_UNDEFINED);
480         }
481 
482 
483         /**
484          * Get existing test history to aggregate.
485          */
486         @Override
getHistoryCollection()487         public TestResultHistoryCollection getHistoryCollection() {
488             List<TestResultHistoryCollection> histories =
489                 IntStream.range(0, mAdapter.getCount())
490                 .mapToObj(mAdapter::getHistoryCollection)
491                 .collect(Collectors.toList());
492             TestResultHistoryCollection historyCollection = new TestResultHistoryCollection();
493             historyCollection.merge(getTestId(), histories);
494             return historyCollection;
495         }
496 
updatePassButton()497         public void updatePassButton() {
498             getPassButton().setEnabled(mAdapter.allTestsPassed());
499         }
500 
501         @Override
onCreate(Bundle savedInstanceState)502         protected void onCreate(Bundle savedInstanceState) {
503             super.onCreate(savedInstanceState);
504             ActionBar actBar = getActionBar();
505             if (actBar != null) {
506                 actBar.setDisplayHomeAsUpEnabled(true);
507             }
508         }
509 
510         @Override
onOptionsItemSelected(MenuItem item)511         public boolean onOptionsItemSelected(MenuItem item) {
512             if (item.getItemId() == android.R.id.home) {
513                 onBackPressed();
514                 return true;
515             }
516             return super.onOptionsItemSelected(item);
517         }
518 
519         @Override
recordTestResults()520         public void recordTestResults() {
521             // default - NOP
522         }
523     } // class PassFailButtons.TestListActivity
524 
525     protected static <T extends android.app.Activity & PassFailActivity>
setPassFailClickListeners(final T activity)526             void setPassFailClickListeners(final T activity) {
527         View.OnClickListener clickListener = new View.OnClickListener() {
528             @Override
529             public void onClick(View target) {
530                 setTestResultAndFinish(activity, activity.getTestId(), activity.getTestDetails(),
531                         activity.getReportLog(), activity.getHistoryCollection(), target);
532             }
533         };
534 
535         View passButton = activity.findViewById(R.id.pass_button);
536         passButton.setOnClickListener(clickListener);
537         passButton.setOnLongClickListener(new View.OnLongClickListener() {
538             @Override
539             public boolean onLongClick(View view) {
540                 Toast.makeText(activity, R.string.pass_button_text, Toast.LENGTH_SHORT).show();
541                 return true;
542             }
543         });
544 
545         View failButton = activity.findViewById(R.id.fail_button);
546         failButton.setOnClickListener(clickListener);
547         failButton.setOnLongClickListener(new View.OnLongClickListener() {
548             @Override
549             public boolean onLongClick(View view) {
550                 Toast.makeText(activity, R.string.fail_button_text, Toast.LENGTH_SHORT).show();
551                 return true;
552             }
553         });
554     } // class PassFailButtons.<T extends android.app.Activity & PassFailActivity>
555 
setInfo(final android.app.Activity activity, final int titleId, final int messageId, final int viewId)556     protected static void setInfo(final android.app.Activity activity, final int titleId,
557             final int messageId, final int viewId) {
558         // Show the middle "info" button and make it show the info dialog when clicked.
559         View infoButton = activity.findViewById(R.id.info_button);
560         infoButton.setVisibility(View.VISIBLE);
561         infoButton.setOnClickListener(new OnClickListener() {
562             @Override
563             public void onClick(View view) {
564                 showInfoDialog(activity, titleId, messageId, viewId);
565             }
566         });
567         infoButton.setOnLongClickListener(new View.OnLongClickListener() {
568             @Override
569             public boolean onLongClick(View view) {
570                 Toast.makeText(activity, R.string.info_button_text, Toast.LENGTH_SHORT).show();
571                 return true;
572             }
573         });
574 
575         // Show the info dialog if the user has never seen it before.
576         if (!hasSeenInfoDialog(activity)) {
577             showInfoDialog(activity, titleId, messageId, viewId);
578         }
579     }
580 
hasSeenInfoDialog(android.app.Activity activity)581     protected static boolean hasSeenInfoDialog(android.app.Activity activity) {
582         ContentResolver resolver = activity.getContentResolver();
583         Cursor cursor = null;
584         try {
585             cursor = resolver.query(TestResultsProvider.getTestNameUri(activity),
586                     new String[] {TestResultsProvider.COLUMN_TEST_INFO_SEEN}, null, null, null);
587             return cursor.moveToFirst() && cursor.getInt(0) > 0;
588         } finally {
589             if (cursor != null) {
590                 cursor.close();
591             }
592         }
593     }
594 
showInfoDialog(final android.app.Activity activity, int titleId, int messageId, int viewId)595     protected static void showInfoDialog(final android.app.Activity activity, int titleId,
596             int messageId, int viewId) {
597         Bundle args = new Bundle();
598         args.putInt(INFO_DIALOG_TITLE_ID, titleId);
599         args.putInt(INFO_DIALOG_MESSAGE_ID, messageId);
600         args.putInt(INFO_DIALOG_VIEW_ID, viewId);
601         activity.showDialog(INFO_DIALOG_ID, args);
602     }
603 
showReportLogWarningDialog(final android.app.Activity activity)604     protected static void showReportLogWarningDialog(final android.app.Activity activity) {
605         Bundle args = new Bundle();
606         args.putInt(INFO_DIALOG_TITLE_ID, R.string.reportlog_warning_title);
607         args.putInt(INFO_DIALOG_MESSAGE_ID, R.string.reportlog_warning_body);
608         args.putInt(INFO_DIALOG_VIEW_ID, -1);
609         activity.showDialog(REPORTLOG_DIALOG_ID, args);
610     }
611 
createDialog(final android.app.Activity activity, int id, Bundle args)612     protected static Dialog createDialog(final android.app.Activity activity, int id, Bundle args) {
613         switch (id) {
614             case INFO_DIALOG_ID:
615             case REPORTLOG_DIALOG_ID:
616                 return createInfoDialog(activity, id, args);
617             default:
618                 throw new IllegalArgumentException("Bad dialog id: " + id);
619         }
620     }
621 
createInfoDialog(final android.app.Activity activity, int id, Bundle args)622     protected static Dialog createInfoDialog(final android.app.Activity activity, int id,
623             Bundle args) {
624         int viewId = args.getInt(INFO_DIALOG_VIEW_ID);
625         int titleId = args.getInt(INFO_DIALOG_TITLE_ID);
626         int messageId = args.getInt(INFO_DIALOG_MESSAGE_ID);
627 
628         AlertDialog.Builder builder = new AlertDialog.Builder(activity).setIcon(
629                 android.R.drawable.ic_dialog_info).setTitle(titleId);
630         if (viewId > 0) {
631             LayoutInflater inflater = (LayoutInflater) activity
632                     .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
633             builder.setView(inflater.inflate(viewId, null));
634         } else {
635             builder.setMessage(messageId);
636         }
637         builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
638             @Override
639             public void onClick(DialogInterface dialog, int which) {
640                 markSeenInfoDialog(activity);
641             }
642         }).setOnCancelListener(new OnCancelListener() {
643             @Override
644             public void onCancel(DialogInterface dialog) {
645                 markSeenInfoDialog(activity);
646             }
647         });
648         return builder.create();
649     }
650 
markSeenInfoDialog(android.app.Activity activity)651     protected static void markSeenInfoDialog(android.app.Activity activity) {
652         ContentResolver resolver = activity.getContentResolver();
653         ContentValues values = new ContentValues(2);
654         String activityName = setTestNameSuffix(sCurrentDisplayMode, activity.getClass().getName());
655         values.put(TestResultsProvider.COLUMN_TEST_NAME, activityName);
656         values.put(TestResultsProvider.COLUMN_TEST_INFO_SEEN, 1);
657         int numUpdated = resolver.update(
658                 TestResultsProvider.getTestNameUri(activity), values, null, null);
659         if (numUpdated == 0) {
660             resolver.insert(TestResultsProvider.getResultContentUri(activity), values);
661         }
662     }
663 
664     /** Set the test result corresponding to the button clicked and finish the activity. */
setTestResultAndFinish(android.app.Activity activity, String testId, String testDetails, ReportLog reportLog, TestResultHistoryCollection historyCollection, View target)665     protected static void setTestResultAndFinish(android.app.Activity activity, String testId,
666             String testDetails, ReportLog reportLog, TestResultHistoryCollection historyCollection,
667             View target) {
668 
669         boolean passed;
670         if (target.getId() == R.id.pass_button) {
671             passed = true;
672         } else if (target.getId() == R.id.fail_button) {
673             passed = false;
674         } else {
675             throw new IllegalArgumentException("Unknown id: " + target.getId());
676         }
677 
678         // Let test classes record their CTSVerifierReportLogs
679         ((PassFailActivity) activity).recordTestResults();
680 
681         setTestResultAndFinishHelper(activity, testId, testDetails, passed, reportLog, historyCollection);
682     }
683 
684     /** Set the test result and finish the activity. */
setTestResultAndFinishHelper(android.app.Activity activity, String testId, String testDetails, boolean passed, ReportLog reportLog, TestResultHistoryCollection historyCollection)685     protected static void setTestResultAndFinishHelper(android.app.Activity activity, String testId,
686             String testDetails, boolean passed, ReportLog reportLog,
687             TestResultHistoryCollection historyCollection) {
688         if (passed) {
689             TestResult.setPassedResult(activity, testId, testDetails, reportLog, historyCollection);
690         } else {
691             TestResult.setFailedResult(activity, testId, testDetails, reportLog, historyCollection);
692         }
693 
694         // We store results here straight into the content provider so it can be fetched by the
695         // CTSInteractive host
696         TestResultsProvider.setTestResult(
697                 activity, testId, passed ? 1 : 2, testDetails, reportLog, historyCollection,
698                 null);
699 
700         activity.finish();
701     }
702 
getPassButtonView(android.app.Activity activity)703     protected static ImageButton getPassButtonView(android.app.Activity activity) {
704         return (ImageButton) activity.findViewById(R.id.pass_button);
705     }
706 
707 } // class PassFailButtons
708