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