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 
showNonSdkAccessibilityWarningDialog( final android.app.Activity activity)315         protected static void showNonSdkAccessibilityWarningDialog(
316                 final android.app.Activity activity) {
317             Bundle args = new Bundle();
318             args.putInt(INFO_DIALOG_TITLE_ID, R.string.nonsdk_interfaces_warning_title);
319             args.putInt(INFO_DIALOG_MESSAGE_ID, R.string.nonsdk_interfaces_warning_body);
320             args.putInt(INFO_DIALOG_VIEW_ID, -1);
321             activity.showDialog(REPORTLOG_DIALOG_ID, args);
322         }
323     }   /* class PassFailButtons.Activity */
324 
325     public static class ListActivity extends android.app.ListActivity implements PassFailActivity {
326 
327         private final CtsVerifierReportLog mReportLog;
328         private final TestResultHistoryCollection mHistoryCollection;
329 
ListActivity()330         public ListActivity() {
331             mHistoryCollection = new TestResultHistoryCollection();
332             mReportLog = null;
333         }
334 
335         @Override
setPassFailButtonClickListeners()336         public void setPassFailButtonClickListeners() {
337             setPassFailClickListeners(this);
338         }
339 
340         @Override
setInfoResources(int titleId, int messageId, int viewId)341         public void setInfoResources(int titleId, int messageId, int viewId) {
342             setInfo(this, titleId, messageId, viewId);
343         }
344 
345         @Override
getPassButton()346         public View getPassButton() {
347             return getPassButtonView(this);
348         }
349 
350         @Override
onCreateDialog(int id, Bundle args)351         public Dialog onCreateDialog(int id, Bundle args) {
352             return createDialog(this, id, args);
353         }
354 
355         @Override
getTestId()356         public String getTestId() {
357             return setTestNameSuffix(sCurrentDisplayMode, getClass().getName());
358         }
359 
360         @Override
getTestDetails()361         public String getTestDetails() {
362             return null;
363         }
364 
365         @Override
setTestResultAndFinish(boolean passed)366         public void setTestResultAndFinish(boolean passed) {
367             PassFailButtons.setTestResultAndFinishHelper(
368                     this, getTestId(), getTestDetails(), passed, getReportLog(),
369                     getHistoryCollection());
370         }
371 
372         @Override
requiresReportLog()373         public boolean requiresReportLog() {
374             return false;
375         }
376 
377         @Override
getReportLog()378         public CtsVerifierReportLog getReportLog() {
379             return mReportLog;
380         }
381 
382         /**
383          * @return The name of the file to store the (suite of) ReportLog information.
384          */
385         @Override
getReportFileName()386         public String getReportFileName() { return GENERAL_TESTS_REPORT_LOG_NAME; }
387 
388         @Override
getReportSectionName()389         public String getReportSectionName() {
390             return setTestNameSuffix(sCurrentDisplayMode, SECTION_UNDEFINED);
391         }
392 
393         @Override
getHistoryCollection()394         public TestResultHistoryCollection getHistoryCollection() { return mHistoryCollection; }
395 
396         @Override
onCreate(Bundle savedInstanceState)397         protected void onCreate(Bundle savedInstanceState) {
398             super.onCreate(savedInstanceState);
399             ActionBar actBar = getActionBar();
400             if (actBar != null) {
401                 actBar.setDisplayHomeAsUpEnabled(true);
402             }
403         }
404 
405         @Override
onOptionsItemSelected(MenuItem item)406         public boolean onOptionsItemSelected(MenuItem item) {
407             if (item.getItemId() == android.R.id.home) {
408                 onBackPressed();
409                 return true;
410             }
411             return super.onOptionsItemSelected(item);
412         }
413 
414         @Override
recordTestResults()415         public void recordTestResults() {
416             // default - NOP
417         }
418     } // class PassFailButtons.ListActivity
419 
420     public static class TestListActivity extends AbstractTestListActivity
421             implements PassFailActivity {
422 
423         private final CtsVerifierReportLog mReportLog;
424 
TestListActivity()425         public TestListActivity() {
426             // TODO(b/186555602): temporary hack^H^H^H^H workaround to fix crash
427             // This DOES NOT in fact fix that bug.
428             // if (true) this.mReportLog = new CtsVerifierReportLog(b/186555602, "42"); else
429 
430             this.mReportLog = new CtsVerifierReportLog(getReportFileName(), getReportSectionName());
431         }
432 
433         @Override
setPassFailButtonClickListeners()434         public void setPassFailButtonClickListeners() {
435             setPassFailClickListeners(this);
436         }
437 
438         @Override
setInfoResources(int titleId, int messageId, int viewId)439         public void setInfoResources(int titleId, int messageId, int viewId) {
440             setInfo(this, titleId, messageId, viewId);
441         }
442 
443         @Override
getPassButton()444         public View getPassButton() {
445             return getPassButtonView(this);
446         }
447 
448         @Override
onCreateDialog(int id, Bundle args)449         public Dialog onCreateDialog(int id, Bundle args) {
450             return createDialog(this, id, args);
451         }
452 
453         @Override
getTestId()454         public String getTestId() {
455             return setTestNameSuffix(sCurrentDisplayMode, getClass().getName());
456         }
457 
458         @Override
getTestDetails()459         public String getTestDetails() {
460             return null;
461         }
462 
463         @Override
setTestResultAndFinish(boolean passed)464         public void setTestResultAndFinish(boolean passed) {
465             PassFailButtons.setTestResultAndFinishHelper(
466                     this, getTestId(), getTestDetails(), passed, getReportLog(),
467                     getHistoryCollection());
468         }
469 
470         @Override
requiresReportLog()471         public boolean requiresReportLog() {
472             return false;
473         }
474 
475         @Override
getReportLog()476         public CtsVerifierReportLog getReportLog() {
477             return mReportLog;
478         }
479 
480         /**
481          * @return The name of the file to store the (suite of) ReportLog information.
482          */
483         @Override
getReportFileName()484         public String getReportFileName() { return GENERAL_TESTS_REPORT_LOG_NAME; }
485 
486         @Override
getReportSectionName()487         public String getReportSectionName() {
488             return setTestNameSuffix(sCurrentDisplayMode, SECTION_UNDEFINED);
489         }
490 
491 
492         /**
493          * Get existing test history to aggregate.
494          */
495         @Override
getHistoryCollection()496         public TestResultHistoryCollection getHistoryCollection() {
497             List<TestResultHistoryCollection> histories =
498                 IntStream.range(0, mAdapter.getCount())
499                 .mapToObj(mAdapter::getHistoryCollection)
500                 .collect(Collectors.toList());
501             TestResultHistoryCollection historyCollection = new TestResultHistoryCollection();
502             historyCollection.merge(getTestId(), histories);
503             return historyCollection;
504         }
505 
updatePassButton()506         public void updatePassButton() {
507             getPassButton().setEnabled(mAdapter.allTestsPassed());
508         }
509 
510         @Override
onCreate(Bundle savedInstanceState)511         protected void onCreate(Bundle savedInstanceState) {
512             super.onCreate(savedInstanceState);
513             ActionBar actBar = getActionBar();
514             if (actBar != null) {
515                 actBar.setDisplayHomeAsUpEnabled(true);
516             }
517         }
518 
519         @Override
onOptionsItemSelected(MenuItem item)520         public boolean onOptionsItemSelected(MenuItem item) {
521             if (item.getItemId() == android.R.id.home) {
522                 onBackPressed();
523                 return true;
524             }
525             return super.onOptionsItemSelected(item);
526         }
527 
528         @Override
recordTestResults()529         public void recordTestResults() {
530             // default - NOP
531         }
532     } // class PassFailButtons.TestListActivity
533 
534     protected static <T extends android.app.Activity & PassFailActivity>
setPassFailClickListeners(final T activity)535             void setPassFailClickListeners(final T activity) {
536         View.OnClickListener clickListener = new View.OnClickListener() {
537             @Override
538             public void onClick(View target) {
539                 setTestResultAndFinish(activity, activity.getTestId(), activity.getTestDetails(),
540                         activity.getReportLog(), activity.getHistoryCollection(), target);
541             }
542         };
543 
544         View passButton = activity.findViewById(R.id.pass_button);
545         passButton.setOnClickListener(clickListener);
546         passButton.setOnLongClickListener(new View.OnLongClickListener() {
547             @Override
548             public boolean onLongClick(View view) {
549                 Toast.makeText(activity, R.string.pass_button_text, Toast.LENGTH_SHORT).show();
550                 return true;
551             }
552         });
553 
554         View failButton = activity.findViewById(R.id.fail_button);
555         failButton.setOnClickListener(clickListener);
556         failButton.setOnLongClickListener(new View.OnLongClickListener() {
557             @Override
558             public boolean onLongClick(View view) {
559                 Toast.makeText(activity, R.string.fail_button_text, Toast.LENGTH_SHORT).show();
560                 return true;
561             }
562         });
563     } // class PassFailButtons.<T extends android.app.Activity & PassFailActivity>
564 
setInfo(final android.app.Activity activity, final int titleId, final int messageId, final int viewId)565     protected static void setInfo(final android.app.Activity activity, final int titleId,
566             final int messageId, final int viewId) {
567         // Show the middle "info" button and make it show the info dialog when clicked.
568         View infoButton = activity.findViewById(R.id.info_button);
569         infoButton.setVisibility(View.VISIBLE);
570         infoButton.setOnClickListener(new OnClickListener() {
571             @Override
572             public void onClick(View view) {
573                 showInfoDialog(activity, titleId, messageId, viewId);
574             }
575         });
576         infoButton.setOnLongClickListener(new View.OnLongClickListener() {
577             @Override
578             public boolean onLongClick(View view) {
579                 Toast.makeText(activity, R.string.info_button_text, Toast.LENGTH_SHORT).show();
580                 return true;
581             }
582         });
583 
584         // Show the info dialog if the user has never seen it before.
585         if (!hasSeenInfoDialog(activity)) {
586             showInfoDialog(activity, titleId, messageId, viewId);
587         }
588     }
589 
hasSeenInfoDialog(android.app.Activity activity)590     protected static boolean hasSeenInfoDialog(android.app.Activity activity) {
591         ContentResolver resolver = activity.getContentResolver();
592         Cursor cursor = null;
593         try {
594             cursor = resolver.query(TestResultsProvider.getTestNameUri(activity),
595                     new String[] {TestResultsProvider.COLUMN_TEST_INFO_SEEN}, null, null, null);
596             return cursor.moveToFirst() && cursor.getInt(0) > 0;
597         } finally {
598             if (cursor != null) {
599                 cursor.close();
600             }
601         }
602     }
603 
showInfoDialog(final android.app.Activity activity, int titleId, int messageId, int viewId)604     protected static void showInfoDialog(final android.app.Activity activity, int titleId,
605             int messageId, int viewId) {
606         Bundle args = new Bundle();
607         args.putInt(INFO_DIALOG_TITLE_ID, titleId);
608         args.putInt(INFO_DIALOG_MESSAGE_ID, messageId);
609         args.putInt(INFO_DIALOG_VIEW_ID, viewId);
610         activity.showDialog(INFO_DIALOG_ID, args);
611     }
612 
showReportLogWarningDialog(final android.app.Activity activity)613     protected static void showReportLogWarningDialog(final android.app.Activity activity) {
614         Bundle args = new Bundle();
615         args.putInt(INFO_DIALOG_TITLE_ID, R.string.reportlog_warning_title);
616         args.putInt(INFO_DIALOG_MESSAGE_ID, R.string.reportlog_warning_body);
617         args.putInt(INFO_DIALOG_VIEW_ID, -1);
618         activity.showDialog(REPORTLOG_DIALOG_ID, args);
619     }
620 
createDialog(final android.app.Activity activity, int id, Bundle args)621     protected static Dialog createDialog(final android.app.Activity activity, int id, Bundle args) {
622         switch (id) {
623             case INFO_DIALOG_ID:
624             case REPORTLOG_DIALOG_ID:
625                 return createInfoDialog(activity, id, args);
626             default:
627                 throw new IllegalArgumentException("Bad dialog id: " + id);
628         }
629     }
630 
createInfoDialog(final android.app.Activity activity, int id, Bundle args)631     protected static Dialog createInfoDialog(final android.app.Activity activity, int id,
632             Bundle args) {
633         int viewId = args.getInt(INFO_DIALOG_VIEW_ID);
634         int titleId = args.getInt(INFO_DIALOG_TITLE_ID);
635         int messageId = args.getInt(INFO_DIALOG_MESSAGE_ID);
636 
637         AlertDialog.Builder builder = new AlertDialog.Builder(activity).setIcon(
638                 android.R.drawable.ic_dialog_info).setTitle(titleId);
639         if (viewId > 0) {
640             LayoutInflater inflater = (LayoutInflater) activity
641                     .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
642             builder.setView(inflater.inflate(viewId, null));
643         } else {
644             builder.setMessage(messageId);
645         }
646         builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
647             @Override
648             public void onClick(DialogInterface dialog, int which) {
649                 markSeenInfoDialog(activity);
650             }
651         }).setOnCancelListener(new OnCancelListener() {
652             @Override
653             public void onCancel(DialogInterface dialog) {
654                 markSeenInfoDialog(activity);
655             }
656         });
657         return builder.create();
658     }
659 
markSeenInfoDialog(android.app.Activity activity)660     protected static void markSeenInfoDialog(android.app.Activity activity) {
661         ContentResolver resolver = activity.getContentResolver();
662         ContentValues values = new ContentValues(2);
663         String activityName = setTestNameSuffix(sCurrentDisplayMode, activity.getClass().getName());
664         values.put(TestResultsProvider.COLUMN_TEST_NAME, activityName);
665         values.put(TestResultsProvider.COLUMN_TEST_INFO_SEEN, 1);
666         int numUpdated = resolver.update(
667                 TestResultsProvider.getTestNameUri(activity), values, null, null);
668         if (numUpdated == 0) {
669             resolver.insert(TestResultsProvider.getResultContentUri(activity), values);
670         }
671     }
672 
673     /** 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)674     protected static void setTestResultAndFinish(android.app.Activity activity, String testId,
675             String testDetails, ReportLog reportLog, TestResultHistoryCollection historyCollection,
676             View target) {
677 
678         boolean passed;
679         if (target.getId() == R.id.pass_button) {
680             passed = true;
681         } else if (target.getId() == R.id.fail_button) {
682             passed = false;
683         } else {
684             throw new IllegalArgumentException("Unknown id: " + target.getId());
685         }
686 
687         // Let test classes record their CTSVerifierReportLogs
688         ((PassFailActivity) activity).recordTestResults();
689 
690         setTestResultAndFinishHelper(activity, testId, testDetails, passed, reportLog, historyCollection);
691     }
692 
693     /** Set the test result and finish the activity. */
setTestResultAndFinishHelper(android.app.Activity activity, String testId, String testDetails, boolean passed, ReportLog reportLog, TestResultHistoryCollection historyCollection)694     protected static void setTestResultAndFinishHelper(android.app.Activity activity, String testId,
695             String testDetails, boolean passed, ReportLog reportLog,
696             TestResultHistoryCollection historyCollection) {
697         if (passed) {
698             TestResult.setPassedResult(activity, testId, testDetails, reportLog, historyCollection);
699         } else {
700             TestResult.setFailedResult(activity, testId, testDetails, reportLog, historyCollection);
701         }
702 
703         // We store results here straight into the content provider so it can be fetched by the
704         // CTSInteractive host
705         TestResultsProvider.setTestResult(
706                 activity, testId, passed ? 1 : 2, testDetails, reportLog, historyCollection,
707                 null);
708 
709         activity.finish();
710     }
711 
getPassButtonView(android.app.Activity activity)712     protected static ImageButton getPassButtonView(android.app.Activity activity) {
713         return (ImageButton) activity.findViewById(R.id.pass_button);
714     }
715 
716 } // class PassFailButtons
717