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.ReportExporter.LOGS_DIRECTORY; 20 import static com.android.cts.verifier.TestListActivity.sCurrentDisplayMode; 21 import static com.android.cts.verifier.TestListActivity.sInitialLaunch; 22 23 import android.content.ContentResolver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.database.ContentObserver; 27 import android.database.Cursor; 28 import android.os.AsyncTask; 29 import android.os.Environment; 30 import android.os.Handler; 31 import android.view.LayoutInflater; 32 import android.view.View; 33 import android.view.ViewGroup; 34 import android.widget.BaseAdapter; 35 import android.widget.ListView; 36 import android.widget.TextView; 37 38 import com.android.compatibility.common.util.ReportLog; 39 import com.android.compatibility.common.util.TestScreenshotsMetadata; 40 import com.android.cts.verifier.TestListActivity.DisplayMode; 41 42 import java.io.ByteArrayInputStream; 43 import java.io.File; 44 import java.io.IOException; 45 import java.io.ObjectInputStream; 46 import java.util.ArrayList; 47 import java.util.HashMap; 48 import java.util.List; 49 import java.util.Map; 50 import java.util.concurrent.atomic.AtomicBoolean; 51 52 /** 53 * {@link BaseAdapter} that handles loading, refreshing, and setting test 54 * results. What tests are shown can be customized by overriding 55 * {@link #getRows()}. See {@link ArrayTestListAdapter} and 56 * {@link ManifestTestListAdapter} for examples. 57 */ 58 public abstract class TestListAdapter extends BaseAdapter { 59 60 /** Activities implementing {@link Intent#ACTION_MAIN} and this will appear in the list. */ 61 public static final String CATEGORY_MANUAL_TEST = "android.cts.intent.category.MANUAL_TEST"; 62 63 /** View type for a category of tests like "Sensors" or "Features" */ 64 private static final int CATEGORY_HEADER_VIEW_TYPE = 0; 65 66 /** View type for an actual test like the Accelerometer test. */ 67 private static final int TEST_VIEW_TYPE = 1; 68 69 /** Padding around the text views and icons. */ 70 private static final int PADDING = 10; 71 72 private final Context mContext; 73 74 /** Immutable data of tests like the test's title and launch intent. */ 75 private final List<TestListItem> mRows = new ArrayList<TestListItem>(); 76 77 /** Mutable test results that will change as each test activity finishes. */ 78 private final Map<String, Integer> mTestResults = new HashMap<String, Integer>(); 79 80 /** Map from test name to test details. */ 81 private final Map<String, String> mTestDetails = new HashMap<String, String>(); 82 83 /** Map from test name to {@link ReportLog}. */ 84 private final Map<String, ReportLog> mReportLogs = new HashMap<String, ReportLog>(); 85 86 /** Map from test name to {@link TestResultHistoryCollection}. */ 87 private final Map<String, TestResultHistoryCollection> mHistories = new HashMap<>(); 88 89 /** Map from test name to {@link TestScreenshotsMetadata}. */ 90 private final Map<String, TestScreenshotsMetadata> mScreenshotsMetadata = new HashMap<>(); 91 92 /** Flag to identify whether the mHistories has been loaded. */ 93 private final AtomicBoolean mHasLoadedResultHistory = new AtomicBoolean(false); 94 95 private final LayoutInflater mLayoutInflater; 96 97 /** Map from display mode to the list of {@link TestListItem}. 98 * Records the TestListItem from main view only, including unfolded mode and folded mode 99 * respectively. */ 100 protected Map<String, List<TestListItem>> mDisplayModesTests = new HashMap<>(); 101 102 /** {@link ListView} row that is either a test category header or a test. */ 103 public static class TestListItem { 104 105 /** Title shown in the {@link ListView}. */ 106 final String title; 107 108 /** Test name with class and test ID to uniquely identify the test. Null for categories. */ 109 String testName; 110 111 /** Intent used to launch the activity from the list. Null for categories. */ 112 final Intent intent; 113 114 /** Features necessary to run this test. */ 115 final String[] requiredFeatures; 116 117 /** Configs necessary to run this test. */ 118 final String[] requiredConfigs; 119 120 /** Intent actions necessary to run this test. */ 121 final String[] requiredActions; 122 123 /** Features such that, if any present, the test gets excluded from being shown. */ 124 final String[] excludedFeatures; 125 126 /** If any of of the features are present the test is meaningful to run. */ 127 final String[] applicableFeatures; 128 129 /** Configs display mode to run this test. */ 130 final String displayMode; 131 132 // TODO: refactor to use a Builder approach instead 133 newTest(Context context, int titleResId, String testName, Intent intent, String[] requiredFeatures, String[] excludedFeatures, String[] applicableFeatures)134 public static TestListItem newTest(Context context, int titleResId, String testName, 135 Intent intent, String[] requiredFeatures, String[] excludedFeatures, 136 String[] applicableFeatures) { 137 return newTest(context.getString(titleResId), testName, intent, requiredFeatures, 138 excludedFeatures, applicableFeatures); 139 } 140 newTest(Context context, int titleResId, String testName, Intent intent, String[] requiredFeatures, String[] excludedFeatures)141 public static TestListItem newTest(Context context, int titleResId, String testName, 142 Intent intent, String[] requiredFeatures, String[] excludedFeatures) { 143 return newTest(context.getString(titleResId), testName, intent, requiredFeatures, 144 excludedFeatures, /* applicableFeatures= */ null); 145 } 146 newTest(Context context, int titleResId, String testName, Intent intent, String[] requiredFeatures)147 public static TestListItem newTest(Context context, int titleResId, String testName, 148 Intent intent, String[] requiredFeatures) { 149 return newTest(context.getString(titleResId), testName, intent, requiredFeatures, 150 /* excludedFeatures= */ null, /* applicableFeatures= */ null); 151 } 152 newTest(String title, String testName, Intent intent, String[] requiredFeatures, String[] requiredConfigs, String[] requiredActions, String[] excludedFeatures, String[] applicableFeatures, String displayMode)153 public static TestListItem newTest(String title, String testName, Intent intent, 154 String[] requiredFeatures, String[] requiredConfigs, String[] requiredActions, 155 String[] excludedFeatures, String[] applicableFeatures, String displayMode) { 156 return new TestListItem(title, testName, intent, requiredFeatures, requiredConfigs, 157 requiredActions, excludedFeatures, applicableFeatures, displayMode); 158 } 159 newTest(String title, String testName, Intent intent, String[] requiredFeatures, String[] requiredConfigs, String[] excludedFeatures, String[] applicableFeatures)160 public static TestListItem newTest(String title, String testName, Intent intent, 161 String[] requiredFeatures, String[] requiredConfigs, String[] excludedFeatures, 162 String[] applicableFeatures) { 163 return new TestListItem(title, testName, intent, requiredFeatures, requiredConfigs, 164 /* requiredActions = */ null, excludedFeatures, applicableFeatures, 165 /* displayMode= */ null); 166 } 167 newTest(String title, String testName, Intent intent, String[] requiredFeatures, String[] excludedFeatures, String[] applicableFeatures)168 public static TestListItem newTest(String title, String testName, Intent intent, 169 String[] requiredFeatures, String[] excludedFeatures, String[] applicableFeatures) { 170 return new TestListItem(title, testName, intent, requiredFeatures, 171 /* requiredConfigs= */ null, /* requiredActions = */ null, excludedFeatures, 172 applicableFeatures, /* displayMode= */ null); 173 } 174 newTest(String title, String testName, Intent intent, String[] requiredFeatures, String[] excludedFeatures)175 public static TestListItem newTest(String title, String testName, Intent intent, 176 String[] requiredFeatures, String[] excludedFeatures) { 177 return new TestListItem(title, testName, intent, requiredFeatures, 178 /* requiredConfigs= */ null, /* requiredActions = */ null, excludedFeatures, 179 /* applicableFeatures= */ null, /* displayMode= */ null); 180 } 181 newTest(String title, String testName, Intent intent, String[] requiredFeatures)182 public static TestListItem newTest(String title, String testName, Intent intent, 183 String[] requiredFeatures) { 184 return new TestListItem(title, testName, intent, requiredFeatures, 185 /* requiredConfigs= */ null, /* requiredActions = */ null, 186 /* excludedFeatures= */ null, /* applicableFeatures= */ null, 187 /* displayMode= */ null); 188 } 189 newCategory(Context context, int titleResId)190 public static TestListItem newCategory(Context context, int titleResId) { 191 return newCategory(context.getString(titleResId)); 192 } 193 newCategory(String title)194 public static TestListItem newCategory(String title) { 195 return new TestListItem(title, /* testName= */ null, /* intent= */ null, 196 /* requiredFeatures= */ null, /* requiredConfigs= */ null, 197 /* requiredActions = */ null, /* excludedFeatures= */ null, 198 /* applicableFeatures= */ null, /* displayMode= */ null); 199 } 200 TestListItem(String title, String testName, Intent intent, String[] requiredFeatures, String[] excludedFeatures, String[] applicableFeatures)201 protected TestListItem(String title, String testName, Intent intent, 202 String[] requiredFeatures, String[] excludedFeatures, String[] applicableFeatures) { 203 this(title, testName, intent, requiredFeatures, /* requiredConfigs= */ null, 204 /* requiredActions = */ null, excludedFeatures, applicableFeatures, 205 /* displayMode= */ null); 206 } 207 TestListItem(String title, String testName, Intent intent, String[] requiredFeatures, String[] requiredConfigs, String[] requiredActions, String[] excludedFeatures, String[] applicableFeatures, String displayMode)208 protected TestListItem(String title, String testName, Intent intent, 209 String[] requiredFeatures, String[] requiredConfigs, String[] requiredActions, 210 String[] excludedFeatures, String[] applicableFeatures, String displayMode) { 211 this.title = title; 212 if (!sInitialLaunch) { 213 testName = setTestNameSuffix(sCurrentDisplayMode, testName); 214 } 215 this.testName = testName; 216 this.intent = intent; 217 this.requiredActions = requiredActions; 218 this.requiredFeatures = requiredFeatures; 219 this.requiredConfigs = requiredConfigs; 220 this.excludedFeatures = excludedFeatures; 221 this.applicableFeatures = applicableFeatures; 222 this.displayMode = displayMode; 223 } 224 isTest()225 boolean isTest() { 226 return intent != null; 227 } 228 } 229 TestListAdapter(Context context)230 public TestListAdapter(Context context) { 231 this.mContext = context; 232 this.mLayoutInflater = 233 (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 234 235 TestResultContentObserver observer = new TestResultContentObserver(); 236 ContentResolver resolver = context.getContentResolver(); 237 resolver.registerContentObserver(TestResultsProvider.getResultContentUri(context), true, observer); 238 } 239 loadTestResults()240 public void loadTestResults() { 241 new RefreshTestResultsTask(false).execute(); 242 } 243 clearTestResults()244 public void clearTestResults() { 245 new ClearTestResultsTask().execute(); 246 } 247 setTestResult(TestResult testResult)248 public void setTestResult(TestResult testResult) { 249 String name = testResult.getName(); 250 251 // Append existing history 252 TestResultHistoryCollection histories = testResult.getHistoryCollection(); 253 histories.merge(null, mHistories.get(name)); 254 255 new SetTestResultTask(name, testResult.getResult(), 256 testResult.getDetails(), testResult.getReportLog(), histories, 257 mScreenshotsMetadata.get(name)).execute(); 258 } 259 260 class RefreshTestResultsTask extends AsyncTask<Void, Void, RefreshResult> { 261 262 private boolean mIsFromMainView; 263 RefreshTestResultsTask(boolean isFromMainView)264 RefreshTestResultsTask(boolean isFromMainView) { 265 mIsFromMainView = isFromMainView; 266 } 267 268 @Override doInBackground(Void... params)269 protected RefreshResult doInBackground(Void... params) { 270 List<TestListItem> rows = getRows(); 271 // When initial launch, needs to fetch tests in the unfolded/folded mode 272 // to be stored in mDisplayModesTests as the basis for the future switch. 273 if (sInitialLaunch) { 274 sInitialLaunch = false; 275 } 276 277 if (mIsFromMainView) { 278 rows = mDisplayModesTests.get(sCurrentDisplayMode); 279 } 280 281 return getRefreshResults(rows); 282 } 283 284 @Override onPostExecute(RefreshResult result)285 protected void onPostExecute(RefreshResult result) { 286 super.onPostExecute(result); 287 mRows.clear(); 288 mRows.addAll(result.mItems); 289 mTestResults.clear(); 290 mTestResults.putAll(result.mResults); 291 mTestDetails.clear(); 292 mTestDetails.putAll(result.mDetails); 293 mReportLogs.clear(); 294 mReportLogs.putAll(result.mReportLogs); 295 mHistories.clear(); 296 mHistories.putAll(result.mHistories); 297 mScreenshotsMetadata.clear(); 298 mScreenshotsMetadata.putAll(result.mScreenshotsMetadata); 299 mHasLoadedResultHistory.set(true); 300 notifyDataSetChanged(); 301 } 302 } 303 304 static class RefreshResult { 305 List<TestListItem> mItems; 306 Map<String, Integer> mResults; 307 Map<String, String> mDetails; 308 Map<String, ReportLog> mReportLogs; 309 Map<String, TestResultHistoryCollection> mHistories; 310 Map<String, TestScreenshotsMetadata> mScreenshotsMetadata; 311 RefreshResult( List<TestListItem> items, Map<String, Integer> results, Map<String, String> details, Map<String, ReportLog> reportLogs, Map<String, TestResultHistoryCollection> histories, Map<String, TestScreenshotsMetadata> screenshotsMetadata)312 RefreshResult( 313 List<TestListItem> items, 314 Map<String, Integer> results, 315 Map<String, String> details, 316 Map<String, ReportLog> reportLogs, 317 Map<String, TestResultHistoryCollection> histories, 318 Map<String, TestScreenshotsMetadata> screenshotsMetadata) { 319 mItems = items; 320 mResults = results; 321 mDetails = details; 322 mReportLogs = reportLogs; 323 mHistories = histories; 324 mScreenshotsMetadata = screenshotsMetadata; 325 } 326 } 327 getRows()328 protected abstract List<TestListItem> getRows(); 329 330 static final String[] REFRESH_PROJECTION = { 331 TestResultsProvider._ID, 332 TestResultsProvider.COLUMN_TEST_NAME, 333 TestResultsProvider.COLUMN_TEST_RESULT, 334 TestResultsProvider.COLUMN_TEST_DETAILS, 335 TestResultsProvider.COLUMN_TEST_METRICS, 336 TestResultsProvider.COLUMN_TEST_RESULT_HISTORY, 337 TestResultsProvider.COLUMN_TEST_SCREENSHOTS_METADATA, 338 }; 339 getRefreshResults(List<TestListItem> items)340 RefreshResult getRefreshResults(List<TestListItem> items) { 341 Map<String, Integer> results = new HashMap<String, Integer>(); 342 Map<String, String> details = new HashMap<String, String>(); 343 Map<String, ReportLog> reportLogs = new HashMap<String, ReportLog>(); 344 Map<String, TestResultHistoryCollection> histories = new HashMap<>(); 345 Map<String, TestScreenshotsMetadata> screenshotsMetadata = new HashMap<>(); 346 ContentResolver resolver = mContext.getContentResolver(); 347 Cursor cursor = null; 348 try { 349 cursor = resolver.query(TestResultsProvider.getResultContentUri(mContext), REFRESH_PROJECTION, 350 null, null, null); 351 if (cursor.moveToFirst()) { 352 do { 353 String testName = cursor.getString(1); 354 int testResult = cursor.getInt(2); 355 String testDetails = cursor.getString(3); 356 ReportLog reportLog = (ReportLog) deserialize(cursor.getBlob(4)); 357 TestResultHistoryCollection historyCollection = 358 (TestResultHistoryCollection) deserialize(cursor.getBlob(5)); 359 TestScreenshotsMetadata screenshots = 360 (TestScreenshotsMetadata) deserialize(cursor.getBlob(6)); 361 results.put(testName, testResult); 362 details.put(testName, testDetails); 363 reportLogs.put(testName, reportLog); 364 histories.put(testName, historyCollection); 365 screenshotsMetadata.put(testName, screenshots); 366 } while (cursor.moveToNext()); 367 } 368 } finally { 369 if (cursor != null) { 370 cursor.close(); 371 } 372 } 373 return new RefreshResult( 374 items, results, details, reportLogs, histories, screenshotsMetadata); 375 } 376 377 class ClearTestResultsTask extends AsyncTask<Void, Void, Void> { 378 deleteDirectory(File file)379 private void deleteDirectory(File file) { 380 for (File subfile : file.listFiles()) { 381 if (subfile.isDirectory()) { 382 deleteDirectory(subfile); 383 } 384 subfile.delete(); 385 } 386 } 387 388 @Override doInBackground(Void... params)389 protected Void doInBackground(Void... params) { 390 ContentResolver resolver = mContext.getContentResolver(); 391 resolver.delete(TestResultsProvider.getResultContentUri(mContext), "1", null); 392 393 // Apart from deleting metadata from content resolver database, need to delete 394 // files generated in LOGS_DIRECTORY. For example screenshots. 395 File resFolder = new File( 396 Environment.getExternalStorageDirectory().getAbsolutePath() 397 + File.separator + LOGS_DIRECTORY); 398 deleteDirectory(resFolder); 399 400 return null; 401 } 402 } 403 404 class SetTestResultTask extends AsyncTask<Void, Void, Void> { 405 406 private final String mTestName; 407 private final int mResult; 408 private final String mDetails; 409 private final ReportLog mReportLog; 410 private final TestResultHistoryCollection mHistoryCollection; 411 private final TestScreenshotsMetadata mScreenshotsMetadata; 412 SetTestResultTask( String testName, int result, String details, ReportLog reportLog, TestResultHistoryCollection historyCollection, TestScreenshotsMetadata screenshotsMetadata)413 SetTestResultTask( 414 String testName, 415 int result, 416 String details, 417 ReportLog reportLog, 418 TestResultHistoryCollection historyCollection, 419 TestScreenshotsMetadata screenshotsMetadata) { 420 mTestName = testName; 421 mResult = result; 422 mDetails = details; 423 mReportLog = reportLog; 424 mHistoryCollection = historyCollection; 425 mScreenshotsMetadata = screenshotsMetadata; 426 } 427 428 @Override doInBackground(Void... params)429 protected Void doInBackground(Void... params) { 430 if (mHasLoadedResultHistory.get()) { 431 mHistoryCollection.merge(null, mHistories.get(mTestName)); 432 } else { 433 // Loads history from ContentProvider directly if it has not been loaded yet. 434 ContentResolver resolver = mContext.getContentResolver(); 435 436 try (Cursor cursor = resolver.query( 437 TestResultsProvider.getTestNameUri(mContext, mTestName), 438 new String[] {TestResultsProvider.COLUMN_TEST_RESULT_HISTORY}, 439 null, 440 null, 441 null)) { 442 if (cursor.moveToFirst()) { 443 do { 444 TestResultHistoryCollection historyCollection = 445 (TestResultHistoryCollection) deserialize(cursor.getBlob(0)); 446 mHistoryCollection.merge(null, historyCollection); 447 } while (cursor.moveToNext()); 448 } 449 } 450 } 451 TestResultsProvider.setTestResult( 452 mContext, mTestName, mResult, mDetails, mReportLog, mHistoryCollection, 453 mScreenshotsMetadata); 454 return null; 455 } 456 } 457 458 class TestResultContentObserver extends ContentObserver { 459 TestResultContentObserver()460 public TestResultContentObserver() { 461 super(new Handler()); 462 } 463 464 @Override onChange(boolean selfChange)465 public void onChange(boolean selfChange) { 466 super.onChange(selfChange); 467 loadTestResults(); 468 } 469 } 470 471 @Override areAllItemsEnabled()472 public boolean areAllItemsEnabled() { 473 // Section headers for test categories are not clickable. 474 return false; 475 } 476 477 @Override isEnabled(int position)478 public boolean isEnabled(int position) { 479 if (getItem(position) == null) { 480 return false; 481 } 482 return getItem(position).isTest(); 483 } 484 485 @Override getItemViewType(int position)486 public int getItemViewType(int position) { 487 return getItem(position).isTest() ? TEST_VIEW_TYPE : CATEGORY_HEADER_VIEW_TYPE; 488 } 489 490 @Override getViewTypeCount()491 public int getViewTypeCount() { 492 return 2; 493 } 494 495 @Override getCount()496 public int getCount() { 497 return mRows.size(); 498 } 499 500 @Override getItem(int position)501 public TestListItem getItem(int position) { 502 return mRows.get(position); 503 } 504 505 @Override getItemId(int position)506 public long getItemId(int position) { 507 return position; 508 } 509 getTestResult(int position)510 public int getTestResult(int position) { 511 TestListItem item = getItem(position); 512 return mTestResults.containsKey(item.testName) 513 ? mTestResults.get(item.testName) 514 : TestResult.TEST_RESULT_NOT_EXECUTED; 515 } 516 getTestDetails(int position)517 public String getTestDetails(int position) { 518 TestListItem item = getItem(position); 519 return mTestDetails.containsKey(item.testName) 520 ? mTestDetails.get(item.testName) 521 : null; 522 } 523 getReportLog(int position)524 public ReportLog getReportLog(int position) { 525 TestListItem item = getItem(position); 526 return mReportLogs.containsKey(item.testName) 527 ? mReportLogs.get(item.testName) 528 : null; 529 } 530 531 /** 532 * Get test result histories. 533 * 534 * @param position The position of test. 535 * @return A {@link TestResultHistoryCollection} object containing test result histories of tests. 536 */ getHistoryCollection(int position)537 public TestResultHistoryCollection getHistoryCollection(int position) { 538 TestListItem item = getItem(position); 539 if (item == null) { 540 return null; 541 } 542 return mHistories.containsKey(item.testName) ? mHistories.get(item.testName) : null; 543 } 544 545 /** 546 * Get test screenshots metadata 547 * 548 * @param position The position of test 549 * @return A {@link TestScreenshotsMetadata} object containing test screenshots metadata. 550 */ getScreenshotsMetadata(String mode, int position)551 public TestScreenshotsMetadata getScreenshotsMetadata(String mode, int position) { 552 TestListItem item = getItem(mode, position); 553 return mScreenshotsMetadata.containsKey(item.testName) 554 ? mScreenshotsMetadata.get(item.testName) 555 : null; 556 } 557 558 /** 559 * Get test item by the given display mode and position. 560 * 561 * @param mode The display mode. 562 * @param position The position of test. 563 * @return A {@link TestListItem} object containing the test item. 564 */ getItem(String mode, int position)565 public TestListItem getItem(String mode, int position) { 566 return mDisplayModesTests.get(mode).get(position); 567 } 568 569 /** 570 * Get test item count by the given display mode. 571 * 572 * @param mode The display mode. 573 * @return A count of test items. 574 */ getCount(String mode)575 public int getCount(String mode){ 576 return mDisplayModesTests.getOrDefault(mode, new ArrayList<>()).size(); 577 } 578 579 /** 580 * Get test result by the given display mode and position. 581 * 582 * @param mode The display mode. 583 * @param position The position of test. 584 * @return The test item result. 585 */ getTestResult(String mode, int position)586 public int getTestResult(String mode, int position) { 587 TestListItem item = mDisplayModesTests.get(mode).get(position); 588 return mTestResults.containsKey(item.testName) 589 ? mTestResults.get(item.testName) 590 : TestResult.TEST_RESULT_NOT_EXECUTED; 591 } 592 593 /** 594 * Get test details by the given display mode and position. 595 * 596 * @param mode The display mode. 597 * @param position The position of test. 598 * @return A string containing the test details. 599 */ getTestDetails(String mode, int position)600 public String getTestDetails(String mode, int position) { 601 TestListItem item = mDisplayModesTests.get(mode).get(position); 602 return mTestDetails.containsKey(item.testName) 603 ? mTestDetails.get(item.testName) 604 : null; 605 } 606 607 /** 608 * Get test report log by the given display mode and position. 609 * 610 * @param mode The display mode. 611 * @param position The position of test. 612 * @return A {@link ReportLog} object containing the test report log of the test item. 613 */ getReportLog(String mode, int position)614 public ReportLog getReportLog(String mode, int position) { 615 TestListItem item = mDisplayModesTests.get(mode).get(position); 616 return mReportLogs.containsKey(item.testName) 617 ? mReportLogs.get(item.testName) 618 : null; 619 } 620 621 /** 622 * Get test result histories by the given display mode and position. 623 * 624 * @param mode The display mode. 625 * @param position The position of test. 626 * @return A {@link TestResultHistoryCollection} object containing the test result histories of 627 * the test item. 628 */ getHistoryCollection(String mode, int position)629 public TestResultHistoryCollection getHistoryCollection(String mode, int position) { 630 TestListItem item = mDisplayModesTests.get(mode).get(position); 631 return mHistories.containsKey(item.testName) 632 ? mHistories.get(item.testName) 633 : null; 634 } 635 allTestsPassed()636 public boolean allTestsPassed() { 637 for (TestListItem item : mRows) { 638 if (item != null && item.isTest() 639 && (!mTestResults.containsKey(item.testName) 640 || (mTestResults.get(item.testName) 641 != TestResult.TEST_RESULT_PASSED))) { 642 return false; 643 } 644 } 645 return true; 646 } 647 648 @Override getView(int position, View convertView, ViewGroup parent)649 public View getView(int position, View convertView, ViewGroup parent) { 650 TextView textView; 651 if (convertView == null) { 652 int layout = getLayout(position); 653 textView = (TextView) mLayoutInflater.inflate(layout, parent, false); 654 } else { 655 textView = (TextView) convertView; 656 } 657 658 TestListItem item = getItem(position); 659 textView.setText(item.title); 660 textView.setPadding(PADDING, 0, PADDING, 0); 661 textView.setCompoundDrawablePadding(PADDING); 662 663 if (item.isTest()) { 664 int testResult = getTestResult(position); 665 int backgroundResource = 0; 666 int iconResource = 0; 667 668 /** TODO: Remove fs_ prefix from feature icons since they are used here too. */ 669 switch (testResult) { 670 case TestResult.TEST_RESULT_PASSED: 671 backgroundResource = R.drawable.test_pass_gradient; 672 iconResource = R.drawable.fs_good; 673 break; 674 675 case TestResult.TEST_RESULT_FAILED: 676 backgroundResource = R.drawable.test_fail_gradient; 677 iconResource = R.drawable.fs_error; 678 break; 679 680 case TestResult.TEST_RESULT_NOT_EXECUTED: 681 break; 682 683 default: 684 throw new IllegalArgumentException("Unknown test result: " + testResult); 685 } 686 687 textView.setBackgroundResource(backgroundResource); 688 textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, iconResource, 0); 689 } 690 691 return textView; 692 } 693 getLayout(int position)694 private int getLayout(int position) { 695 int viewType = getItemViewType(position); 696 switch (viewType) { 697 case CATEGORY_HEADER_VIEW_TYPE: 698 return R.layout.test_category_row; 699 case TEST_VIEW_TYPE: 700 return android.R.layout.simple_list_item_1; 701 default: 702 throw new IllegalArgumentException("Illegal view type: " + viewType); 703 704 } 705 } 706 deserialize(byte[] bytes)707 public static Object deserialize(byte[] bytes) { 708 if (bytes == null || bytes.length == 0) { 709 return null; 710 } 711 ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes); 712 ObjectInputStream objectInput = null; 713 try { 714 objectInput = new ObjectInputStream(byteStream); 715 return objectInput.readObject(); 716 } catch (IOException e) { 717 return null; 718 } catch (ClassNotFoundException e) { 719 return null; 720 } finally { 721 try { 722 if (objectInput != null) { 723 objectInput.close(); 724 } 725 byteStream.close(); 726 } catch (IOException e) { 727 // Ignore close exception. 728 } 729 } 730 } 731 732 /** 733 * Sets test name suffix. In the folded mode, the suffix is [folded]; otherwise, it is empty 734 * string. 735 * 736 * @param mode A string of current display mode. 737 * @param name A string of test name. 738 * @return A string of test name with suffix, [folded], in the folded mode. 739 * A string of input test name in the unfolded mode. 740 */ setTestNameSuffix(String mode, String name)741 public static String setTestNameSuffix(String mode, String name) { 742 if (name != null && mode.equals(DisplayMode.FOLDED.toString()) 743 && !name.endsWith(DisplayMode.FOLDED.asSuffix())){ 744 return name + DisplayMode.FOLDED.asSuffix(); 745 } 746 return name; 747 } 748 } 749