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