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