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