Home | History | Annotate | Download | only in verifier
      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         public static TestListItem newTest(Context context, int titleResId, String testName,
     87                 Intent intent, String[] requiredFeatures) {
     88             return newTest(context.getString(titleResId), testName, intent, requiredFeatures);
     89         }
     90 
     91         public static TestListItem newTest(String title, String testName, Intent intent,
     92                 String[] requiredFeatures) {
     93             return new TestListItem(title, testName, intent, requiredFeatures);
     94         }
     95 
     96         public static TestListItem newCategory(Context context, int titleResId) {
     97             return newCategory(context.getString(titleResId));
     98         }
     99 
    100         public static TestListItem newCategory(String title) {
    101             return new TestListItem(title, null, null, null);
    102         }
    103 
    104         private TestListItem(String title, String testName, Intent intent,
    105                 String[] requiredFeatures) {
    106             this.title = title;
    107             this.testName = testName;
    108             this.intent = intent;
    109             this.requiredFeatures = requiredFeatures;
    110         }
    111 
    112         boolean isTest() {
    113             return intent != null;
    114         }
    115     }
    116 
    117     public TestListAdapter(Context context) {
    118         this.mContext = context;
    119         this.mLayoutInflater =
    120                 (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    121 
    122         TestResultContentObserver observer = new TestResultContentObserver();
    123         ContentResolver resolver = context.getContentResolver();
    124         resolver.registerContentObserver(TestResultsProvider.RESULTS_CONTENT_URI, true, observer);
    125     }
    126 
    127     public void loadTestResults() {
    128         new RefreshTestResultsTask().execute();
    129     }
    130 
    131     public void clearTestResults() {
    132         new ClearTestResultsTask().execute();
    133     }
    134 
    135     public void setTestResult(TestResult testResult) {
    136         new SetTestResultTask(testResult.getName(), testResult.getResult(),
    137                 testResult.getDetails()).execute();
    138     }
    139 
    140     class RefreshTestResultsTask extends AsyncTask<Void, Void, RefreshResult> {
    141         @Override
    142         protected RefreshResult doInBackground(Void... params) {
    143             List<TestListItem> rows = getRows();
    144             return getRefreshResults(rows);
    145         }
    146 
    147         @Override
    148         protected void onPostExecute(RefreshResult result) {
    149             super.onPostExecute(result);
    150             mRows.clear();
    151             mRows.addAll(result.mItems);
    152             mTestResults.clear();
    153             mTestResults.putAll(result.mResults);
    154             mTestDetails.clear();
    155             mTestDetails.putAll(result.mDetails);
    156             notifyDataSetChanged();
    157         }
    158     }
    159 
    160     static class RefreshResult {
    161         List<TestListItem> mItems;
    162         Map<String, Integer> mResults;
    163         Map<String, String> mDetails;
    164 
    165         RefreshResult(List<TestListItem> items, Map<String, Integer> results,
    166                 Map<String, String> details) {
    167             mItems = items;
    168             mResults = results;
    169             mDetails = details;
    170         }
    171     }
    172 
    173     protected abstract List<TestListItem> getRows();
    174 
    175     static final String[] REFRESH_PROJECTION = {
    176         TestResultsProvider._ID,
    177         TestResultsProvider.COLUMN_TEST_NAME,
    178         TestResultsProvider.COLUMN_TEST_RESULT,
    179         TestResultsProvider.COLUMN_TEST_DETAILS,
    180     };
    181 
    182     RefreshResult getRefreshResults(List<TestListItem> items) {
    183         Map<String, Integer> results = new HashMap<String, Integer>();
    184         Map<String, String> details = new HashMap<String, String>();
    185         ContentResolver resolver = mContext.getContentResolver();
    186         Cursor cursor = null;
    187         try {
    188             cursor = resolver.query(TestResultsProvider.RESULTS_CONTENT_URI, REFRESH_PROJECTION,
    189                     null, null, null);
    190             if (cursor.moveToFirst()) {
    191                 do {
    192                     String testName = cursor.getString(1);
    193                     int testResult = cursor.getInt(2);
    194                     String testDetails = cursor.getString(3);
    195                     results.put(testName, testResult);
    196                     details.put(testName, testDetails);
    197                 } while (cursor.moveToNext());
    198             }
    199         } finally {
    200             if (cursor != null) {
    201                 cursor.close();
    202             }
    203         }
    204         return new RefreshResult(items, results, details);
    205     }
    206 
    207     class ClearTestResultsTask extends AsyncTask<Void, Void, Void> {
    208 
    209         @Override
    210         protected Void doInBackground(Void... params) {
    211             ContentResolver resolver = mContext.getContentResolver();
    212             resolver.delete(TestResultsProvider.RESULTS_CONTENT_URI, "1", null);
    213             return null;
    214         }
    215     }
    216 
    217     class SetTestResultTask extends AsyncTask<Void, Void, Void> {
    218 
    219         private final String mTestName;
    220 
    221         private final int mResult;
    222 
    223         private final String mDetails;
    224 
    225         SetTestResultTask(String testName, int result, String details) {
    226             mTestName = testName;
    227             mResult = result;
    228             mDetails = details;
    229         }
    230 
    231         @Override
    232         protected Void doInBackground(Void... params) {
    233             TestResultsProvider.setTestResult(mContext, mTestName, mResult, mDetails);
    234             return null;
    235         }
    236     }
    237 
    238     class TestResultContentObserver extends ContentObserver {
    239 
    240         public TestResultContentObserver() {
    241             super(new Handler());
    242         }
    243 
    244         @Override
    245         public void onChange(boolean selfChange) {
    246             super.onChange(selfChange);
    247             loadTestResults();
    248         }
    249     }
    250 
    251     @Override
    252     public boolean areAllItemsEnabled() {
    253         // Section headers for test categories are not clickable.
    254         return false;
    255     }
    256 
    257     @Override
    258     public boolean isEnabled(int position) {
    259         return getItem(position).isTest();
    260     }
    261 
    262     @Override
    263     public int getItemViewType(int position) {
    264         return getItem(position).isTest() ? TEST_VIEW_TYPE : CATEGORY_HEADER_VIEW_TYPE;
    265     }
    266 
    267     @Override
    268     public int getViewTypeCount() {
    269         return 2;
    270     }
    271 
    272     @Override
    273     public int getCount() {
    274         return mRows.size();
    275     }
    276 
    277     @Override
    278     public TestListItem getItem(int position) {
    279         return mRows.get(position);
    280     }
    281 
    282     @Override
    283     public long getItemId(int position) {
    284         return position;
    285     }
    286 
    287     public int getTestResult(int position) {
    288         TestListItem item = getItem(position);
    289         return mTestResults.containsKey(item.testName)
    290                 ? mTestResults.get(item.testName)
    291                 : TestResult.TEST_RESULT_NOT_EXECUTED;
    292     }
    293 
    294     public String getTestDetails(int position) {
    295         TestListItem item = getItem(position);
    296         return mTestDetails.containsKey(item.testName)
    297                 ? mTestDetails.get(item.testName)
    298                 : null;
    299     }
    300 
    301     public boolean allTestsPassed() {
    302         for (TestListItem item : mRows) {
    303             if (item.isTest() && (!mTestResults.containsKey(item.testName)
    304                     || (mTestResults.get(item.testName) != TestResult.TEST_RESULT_PASSED))) {
    305                 return false;
    306             }
    307         }
    308         return true;
    309     }
    310 
    311     @Override
    312     public View getView(int position, View convertView, ViewGroup parent) {
    313         TextView textView;
    314         if (convertView == null) {
    315             int layout = getLayout(position);
    316             textView = (TextView) mLayoutInflater.inflate(layout, parent, false);
    317         } else {
    318             textView = (TextView) convertView;
    319         }
    320 
    321         TestListItem item = getItem(position);
    322         textView.setText(item.title);
    323         textView.setPadding(PADDING, 0, PADDING, 0);
    324         textView.setCompoundDrawablePadding(PADDING);
    325 
    326         if (item.isTest()) {
    327             int testResult = getTestResult(position);
    328             int backgroundResource = 0;
    329             int iconResource = 0;
    330 
    331             /** TODO: Remove fs_ prefix from feature icons since they are used here too. */
    332             switch (testResult) {
    333                 case TestResult.TEST_RESULT_PASSED:
    334                     backgroundResource = R.drawable.test_pass_gradient;
    335                     iconResource = R.drawable.fs_good;
    336                     break;
    337 
    338                 case TestResult.TEST_RESULT_FAILED:
    339                     backgroundResource = R.drawable.test_fail_gradient;
    340                     iconResource = R.drawable.fs_error;
    341                     break;
    342 
    343                 case TestResult.TEST_RESULT_NOT_EXECUTED:
    344                     break;
    345 
    346                 default:
    347                     throw new IllegalArgumentException("Unknown test result: " + testResult);
    348             }
    349 
    350             textView.setBackgroundResource(backgroundResource);
    351             textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, iconResource, 0);
    352         }
    353 
    354         return textView;
    355     }
    356 
    357     private int getLayout(int position) {
    358         int viewType = getItemViewType(position);
    359         switch (viewType) {
    360             case CATEGORY_HEADER_VIEW_TYPE:
    361                 return R.layout.test_category_row;
    362             case TEST_VIEW_TYPE:
    363                 return android.R.layout.simple_list_item_1;
    364             default:
    365                 throw new IllegalArgumentException("Illegal view type: " + viewType);
    366 
    367         }
    368     }
    369 }