• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.content.ContentResolver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.database.ContentObserver;
23 import android.database.Cursor;
24 import android.os.AsyncTask;
25 import android.os.Handler;
26 import android.view.LayoutInflater;
27 import android.view.View;
28 import android.view.ViewGroup;
29 import android.widget.BaseAdapter;
30 import android.widget.ListView;
31 import android.widget.TextView;
32 
33 import java.util.ArrayList;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37 
38 /**
39  * {@link BaseAdapter} that handles loading, refreshing, and setting test
40  * results. What tests are shown can be customized by overriding
41  * {@link #getRows()}. See {@link ArrayTestListAdapter} and
42  * {@link ManifestTestListAdapter} for examples.
43  */
44 public abstract class TestListAdapter extends BaseAdapter {
45 
46     /** Activities implementing {@link Intent#ACTION_MAIN} and this will appear in the list. */
47     public static final String CATEGORY_MANUAL_TEST = "android.cts.intent.category.MANUAL_TEST";
48 
49     /** View type for a category of tests like "Sensors" or "Features" */
50     private static final int CATEGORY_HEADER_VIEW_TYPE = 0;
51 
52     /** View type for an actual test like the Accelerometer test. */
53     private static final int TEST_VIEW_TYPE = 1;
54 
55     /** Padding around the text views and icons. */
56     private static final int PADDING = 10;
57 
58     private final Context mContext;
59 
60     /** Immutable data of tests like the test's title and launch intent. */
61     private final List<TestListItem> mRows = new ArrayList<TestListItem>();
62 
63     /** Mutable test results that will change as each test activity finishes. */
64     private final Map<String, Integer> mTestResults = new HashMap<String, Integer>();
65 
66     /** Map from test name to test details. */
67     private final Map<String, String> mTestDetails = new HashMap<String, String>();
68 
69     private final LayoutInflater mLayoutInflater;
70 
71     /** {@link ListView} row that is either a test category header or a test. */
72     public static class TestListItem {
73 
74         /** Title shown in the {@link ListView}. */
75         final String title;
76 
77         /** Test name with class and test ID to uniquely identify the test. Null for categories. */
78         final String testName;
79 
80         /** Intent used to launch the activity from the list. Null for categories. */
81         final Intent intent;
82 
83         /** Features necessary to run this test. */
84         final String[] requiredFeatures;
85 
86         /** Features such that, if any present, the test gets excluded from being shown. */
87         final String[] excludedFeatures;
88 
89         /** If any of of the features are present the test is meaningful to run. */
90         final String[] applicableFeatures;
91 
newTest(Context context, int titleResId, String testName, Intent intent, String[] requiredFeatures, String[] excludedFeatures, String[] applicableFeatures)92         public static TestListItem newTest(Context context, int titleResId, String testName,
93                 Intent intent, String[] requiredFeatures, String[] excludedFeatures,
94                 String[] applicableFeatures) {
95             return newTest(context.getString(titleResId), testName, intent, requiredFeatures,
96                     excludedFeatures, applicableFeatures);
97         }
98 
newTest(Context context, int titleResId, String testName, Intent intent, String[] requiredFeatures, String[] excludedFeatures)99         public static TestListItem newTest(Context context, int titleResId, String testName,
100                 Intent intent, String[] requiredFeatures, String[] excludedFeatures) {
101             return newTest(context.getString(titleResId), testName, intent, requiredFeatures,
102                     excludedFeatures, null);
103         }
104 
newTest(Context context, int titleResId, String testName, Intent intent, String[] requiredFeatures)105         public static TestListItem newTest(Context context, int titleResId, String testName,
106                 Intent intent, String[] requiredFeatures) {
107             return newTest(context.getString(titleResId), testName, intent, requiredFeatures, null,
108                     null);
109         }
110 
newTest(String title, String testName, Intent intent, String[] requiredFeatures, String[] excludedFeatures, String[] applicableFeatures)111         public static TestListItem newTest(String title, String testName, Intent intent,
112                 String[] requiredFeatures, String[] excludedFeatures, String[] applicableFeatures) {
113             return new TestListItem(title, testName, intent, requiredFeatures, excludedFeatures,
114                     applicableFeatures);
115         }
116 
newTest(String title, String testName, Intent intent, String[] requiredFeatures, String[] excludedFeatures)117         public static TestListItem newTest(String title, String testName, Intent intent,
118                 String[] requiredFeatures, String[] excludedFeatures) {
119             return new TestListItem(title, testName, intent, requiredFeatures, excludedFeatures,
120                     null);
121         }
122 
newTest(String title, String testName, Intent intent, String[] requiredFeatures)123         public static TestListItem newTest(String title, String testName, Intent intent,
124                 String[] requiredFeatures) {
125             return new TestListItem(title, testName, intent, requiredFeatures, null, null);
126         }
127 
newCategory(Context context, int titleResId)128         public static TestListItem newCategory(Context context, int titleResId) {
129             return newCategory(context.getString(titleResId));
130         }
131 
newCategory(String title)132         public static TestListItem newCategory(String title) {
133             return new TestListItem(title, null, null, null, null, null);
134         }
135 
TestListItem(String title, String testName, Intent intent, String[] requiredFeatures, String[] excludedFeatures, String[] applicableFeatures)136         private TestListItem(String title, String testName, Intent intent,
137                 String[] requiredFeatures, String[] excludedFeatures, String[] applicableFeatures) {
138             this.title = title;
139             this.testName = testName;
140             this.intent = intent;
141             this.requiredFeatures = requiredFeatures;
142             this.excludedFeatures = excludedFeatures;
143             this.applicableFeatures = applicableFeatures;
144         }
145 
isTest()146         boolean isTest() {
147             return intent != null;
148         }
149     }
150 
TestListAdapter(Context context)151     public TestListAdapter(Context context) {
152         this.mContext = context;
153         this.mLayoutInflater =
154                 (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
155 
156         TestResultContentObserver observer = new TestResultContentObserver();
157         ContentResolver resolver = context.getContentResolver();
158         resolver.registerContentObserver(TestResultsProvider.RESULTS_CONTENT_URI, true, observer);
159     }
160 
loadTestResults()161     public void loadTestResults() {
162         new RefreshTestResultsTask().execute();
163     }
164 
clearTestResults()165     public void clearTestResults() {
166         new ClearTestResultsTask().execute();
167     }
168 
setTestResult(TestResult testResult)169     public void setTestResult(TestResult testResult) {
170         new SetTestResultTask(testResult.getName(), testResult.getResult(),
171                 testResult.getDetails()).execute();
172     }
173 
174     class RefreshTestResultsTask extends AsyncTask<Void, Void, RefreshResult> {
175         @Override
doInBackground(Void... params)176         protected RefreshResult doInBackground(Void... params) {
177             List<TestListItem> rows = getRows();
178             return getRefreshResults(rows);
179         }
180 
181         @Override
onPostExecute(RefreshResult result)182         protected void onPostExecute(RefreshResult result) {
183             super.onPostExecute(result);
184             mRows.clear();
185             mRows.addAll(result.mItems);
186             mTestResults.clear();
187             mTestResults.putAll(result.mResults);
188             mTestDetails.clear();
189             mTestDetails.putAll(result.mDetails);
190             notifyDataSetChanged();
191         }
192     }
193 
194     static class RefreshResult {
195         List<TestListItem> mItems;
196         Map<String, Integer> mResults;
197         Map<String, String> mDetails;
198 
RefreshResult(List<TestListItem> items, Map<String, Integer> results, Map<String, String> details)199         RefreshResult(List<TestListItem> items, Map<String, Integer> results,
200                 Map<String, String> details) {
201             mItems = items;
202             mResults = results;
203             mDetails = details;
204         }
205     }
206 
getRows()207     protected abstract List<TestListItem> getRows();
208 
209     static final String[] REFRESH_PROJECTION = {
210         TestResultsProvider._ID,
211         TestResultsProvider.COLUMN_TEST_NAME,
212         TestResultsProvider.COLUMN_TEST_RESULT,
213         TestResultsProvider.COLUMN_TEST_DETAILS,
214     };
215 
getRefreshResults(List<TestListItem> items)216     RefreshResult getRefreshResults(List<TestListItem> items) {
217         Map<String, Integer> results = new HashMap<String, Integer>();
218         Map<String, String> details = new HashMap<String, String>();
219         ContentResolver resolver = mContext.getContentResolver();
220         Cursor cursor = null;
221         try {
222             cursor = resolver.query(TestResultsProvider.RESULTS_CONTENT_URI, REFRESH_PROJECTION,
223                     null, null, null);
224             if (cursor.moveToFirst()) {
225                 do {
226                     String testName = cursor.getString(1);
227                     int testResult = cursor.getInt(2);
228                     String testDetails = cursor.getString(3);
229                     results.put(testName, testResult);
230                     details.put(testName, testDetails);
231                 } while (cursor.moveToNext());
232             }
233         } finally {
234             if (cursor != null) {
235                 cursor.close();
236             }
237         }
238         return new RefreshResult(items, results, details);
239     }
240 
241     class ClearTestResultsTask extends AsyncTask<Void, Void, Void> {
242 
243         @Override
doInBackground(Void... params)244         protected Void doInBackground(Void... params) {
245             ContentResolver resolver = mContext.getContentResolver();
246             resolver.delete(TestResultsProvider.RESULTS_CONTENT_URI, "1", null);
247             return null;
248         }
249     }
250 
251     class SetTestResultTask extends AsyncTask<Void, Void, Void> {
252 
253         private final String mTestName;
254 
255         private final int mResult;
256 
257         private final String mDetails;
258 
SetTestResultTask(String testName, int result, String details)259         SetTestResultTask(String testName, int result, String details) {
260             mTestName = testName;
261             mResult = result;
262             mDetails = details;
263         }
264 
265         @Override
doInBackground(Void... params)266         protected Void doInBackground(Void... params) {
267             TestResultsProvider.setTestResult(mContext, mTestName, mResult, mDetails);
268             return null;
269         }
270     }
271 
272     class TestResultContentObserver extends ContentObserver {
273 
TestResultContentObserver()274         public TestResultContentObserver() {
275             super(new Handler());
276         }
277 
278         @Override
onChange(boolean selfChange)279         public void onChange(boolean selfChange) {
280             super.onChange(selfChange);
281             loadTestResults();
282         }
283     }
284 
285     @Override
areAllItemsEnabled()286     public boolean areAllItemsEnabled() {
287         // Section headers for test categories are not clickable.
288         return false;
289     }
290 
291     @Override
isEnabled(int position)292     public boolean isEnabled(int position) {
293         return getItem(position).isTest();
294     }
295 
296     @Override
getItemViewType(int position)297     public int getItemViewType(int position) {
298         return getItem(position).isTest() ? TEST_VIEW_TYPE : CATEGORY_HEADER_VIEW_TYPE;
299     }
300 
301     @Override
getViewTypeCount()302     public int getViewTypeCount() {
303         return 2;
304     }
305 
306     @Override
getCount()307     public int getCount() {
308         return mRows.size();
309     }
310 
311     @Override
getItem(int position)312     public TestListItem getItem(int position) {
313         return mRows.get(position);
314     }
315 
316     @Override
getItemId(int position)317     public long getItemId(int position) {
318         return position;
319     }
320 
getTestResult(int position)321     public int getTestResult(int position) {
322         TestListItem item = getItem(position);
323         return mTestResults.containsKey(item.testName)
324                 ? mTestResults.get(item.testName)
325                 : TestResult.TEST_RESULT_NOT_EXECUTED;
326     }
327 
getTestDetails(int position)328     public String getTestDetails(int position) {
329         TestListItem item = getItem(position);
330         return mTestDetails.containsKey(item.testName)
331                 ? mTestDetails.get(item.testName)
332                 : null;
333     }
334 
allTestsPassed()335     public boolean allTestsPassed() {
336         for (TestListItem item : mRows) {
337             if (item.isTest() && (!mTestResults.containsKey(item.testName)
338                     || (mTestResults.get(item.testName) != TestResult.TEST_RESULT_PASSED))) {
339                 return false;
340             }
341         }
342         return true;
343     }
344 
345     @Override
getView(int position, View convertView, ViewGroup parent)346     public View getView(int position, View convertView, ViewGroup parent) {
347         TextView textView;
348         if (convertView == null) {
349             int layout = getLayout(position);
350             textView = (TextView) mLayoutInflater.inflate(layout, parent, false);
351         } else {
352             textView = (TextView) convertView;
353         }
354 
355         TestListItem item = getItem(position);
356         textView.setText(item.title);
357         textView.setPadding(PADDING, 0, PADDING, 0);
358         textView.setCompoundDrawablePadding(PADDING);
359 
360         if (item.isTest()) {
361             int testResult = getTestResult(position);
362             int backgroundResource = 0;
363             int iconResource = 0;
364 
365             /** TODO: Remove fs_ prefix from feature icons since they are used here too. */
366             switch (testResult) {
367                 case TestResult.TEST_RESULT_PASSED:
368                     backgroundResource = R.drawable.test_pass_gradient;
369                     iconResource = R.drawable.fs_good;
370                     break;
371 
372                 case TestResult.TEST_RESULT_FAILED:
373                     backgroundResource = R.drawable.test_fail_gradient;
374                     iconResource = R.drawable.fs_error;
375                     break;
376 
377                 case TestResult.TEST_RESULT_NOT_EXECUTED:
378                     break;
379 
380                 default:
381                     throw new IllegalArgumentException("Unknown test result: " + testResult);
382             }
383 
384             textView.setBackgroundResource(backgroundResource);
385             textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, iconResource, 0);
386         }
387 
388         return textView;
389     }
390 
getLayout(int position)391     private int getLayout(int position) {
392         int viewType = getItemViewType(position);
393         switch (viewType) {
394             case CATEGORY_HEADER_VIEW_TYPE:
395                 return R.layout.test_category_row;
396             case TEST_VIEW_TYPE:
397                 return android.R.layout.simple_list_item_1;
398             default:
399                 throw new IllegalArgumentException("Illegal view type: " + viewType);
400 
401         }
402     }
403 }
404