| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.cts.verifier; |
| |
| import android.content.ContentResolver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.pm.ActivityInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.ResolveInfo; |
| import android.database.Cursor; |
| import android.os.Bundle; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.widget.BaseAdapter; |
| import android.widget.ListView; |
| import android.widget.TextView; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * {@link BaseAdapter} that populates the {@link TestListActivity}'s {@link ListView}. |
| * Making a new test activity to appear in the list requires the following steps: |
| * |
| * <ol> |
| * <li>REQUIRED: Add an activity to the AndroidManifest.xml with an intent filter with a |
| * main action and the MANUAL_TEST category. |
| * <pre> |
| * <intent-filter> |
| * <action android:name="android.intent.action.MAIN" /> |
| * <category android:name="android.cts.intent.category.MANUAL_TEST" /> |
| * </intent-filter> |
| * </pre> |
| * </li> |
| * <li>OPTIONAL: Add a meta data attribute to indicate what category of tests the activity |
| * should belong to. If you don't add this attribute, your test will show up in the |
| * "Other" tests category. |
| * <pre> |
| * <meta-data android:name="test_category" android:value="@string/test_category_security" /> |
| * </pre> |
| * </li> |
| * </ol> |
| */ |
| class TestListAdapter extends BaseAdapter { |
| |
| /** Activities implementing {@link Intent#ACTION_MAIN} and this will appear in the list. */ |
| public static final String CATEGORY_MANUAL_TEST = "android.cts.intent.category.MANUAL_TEST"; |
| |
| private static final String TEST_CATEGORY_META_DATA = "test_category"; |
| |
| /** View type for a category of tests like "Sensors" or "Features" */ |
| private static final int CATEGORY_HEADER_VIEW_TYPE = 0; |
| |
| /** View type for an actual test like the Accelerometer test. */ |
| private static final int TEST_VIEW_TYPE = 1; |
| |
| /** Padding around the text views and icons. */ |
| private static final int PADDING = 10; |
| |
| private final Context mContext; |
| |
| /** Immutable data of tests like the test's title and launch intent. */ |
| private final List<TestListItem> mRows; |
| |
| /** Mutable test results that will change as each test activity finishes. */ |
| private final Map<String, Integer> mTestResults = new HashMap<String, Integer>(); |
| |
| private final LayoutInflater mLayoutInflater; |
| |
| /** {@link ListView} row that is either a test category header or a test. */ |
| static class TestListItem { |
| |
| /** Title shown in the {@link ListView}. */ |
| final String title; |
| |
| /** Class name with package to uniquely identify the test. Null for categories. */ |
| final String className; |
| |
| /** Intent used to launch the activity from the list. Null for categories. */ |
| final Intent intent; |
| |
| static TestListItem newTest(String title, String className, Intent intent) { |
| return new TestListItem(title, className, intent); |
| } |
| |
| static TestListItem newCategory(String title) { |
| return new TestListItem(title, null, null); |
| } |
| |
| private TestListItem(String title, String className, Intent intent) { |
| this.title = title; |
| this.className = className; |
| this.intent = intent; |
| } |
| |
| boolean isTest() { |
| return intent != null; |
| } |
| } |
| |
| TestListAdapter(Context context) { |
| this.mContext = context; |
| this.mRows = getRows(context); |
| this.mLayoutInflater = |
| (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); |
| updateTestResults(mContext, mTestResults); |
| } |
| |
| static List<TestListItem> getRows(Context context) { |
| /* |
| * 1. Get all the tests keyed by their category. |
| * 2. Flatten the tests and categories into one giant list for the list view. |
| */ |
| |
| Map<String, List<TestListItem>> testsByCategory = getTestsByCategory(context); |
| |
| List<String> testCategories = new ArrayList<String>(testsByCategory.keySet()); |
| Collections.sort(testCategories); |
| |
| List<TestListItem> allRows = new ArrayList<TestListItem>(); |
| for (String testCategory : testCategories) { |
| allRows.add(TestListItem.newCategory(testCategory)); |
| |
| List<TestListItem> tests = testsByCategory.get(testCategory); |
| Collections.sort(tests, new Comparator<TestListItem>() { |
| public int compare(TestListItem item, TestListItem otherItem) { |
| return item.title.compareTo(otherItem.title); |
| } |
| }); |
| allRows.addAll(tests); |
| } |
| return allRows; |
| } |
| |
| static Map<String, List<TestListItem>> getTestsByCategory(Context context) { |
| Map<String, List<TestListItem>> testsByCategory = |
| new HashMap<String, List<TestListItem>>(); |
| |
| Intent mainIntent = new Intent(Intent.ACTION_MAIN); |
| mainIntent.addCategory(CATEGORY_MANUAL_TEST); |
| |
| PackageManager packageManager = context.getPackageManager(); |
| List<ResolveInfo> list = packageManager.queryIntentActivities(mainIntent, |
| PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA); |
| |
| for (int i = 0; i < list.size(); i++) { |
| ResolveInfo info = list.get(i); |
| String testCategory = getTestCategory(context, info.activityInfo.metaData); |
| String title = getTitle(context, info.activityInfo); |
| String className = info.activityInfo.name; |
| Intent intent = getActivityIntent(info.activityInfo); |
| |
| addTestToCategory(testsByCategory, testCategory, title, className, intent); |
| } |
| |
| return testsByCategory; |
| } |
| |
| static String getTestCategory(Context context, Bundle metaData) { |
| String testCategory = null; |
| if (metaData != null) { |
| testCategory = metaData.getString(TEST_CATEGORY_META_DATA); |
| } |
| if (testCategory != null) { |
| return testCategory; |
| } else { |
| return context.getString(R.string.test_category_other); |
| } |
| } |
| |
| static String getTitle(Context context, ActivityInfo activityInfo) { |
| if (activityInfo.labelRes != 0) { |
| return context.getString(activityInfo.labelRes); |
| } else { |
| return activityInfo.name; |
| } |
| } |
| |
| static Intent getActivityIntent(ActivityInfo activityInfo) { |
| Intent intent = new Intent(); |
| intent.setClassName(activityInfo.packageName, activityInfo.name); |
| return intent; |
| } |
| |
| static void addTestToCategory(Map<String, List<TestListItem>> testsByCategory, |
| String testCategory, String title, String className, Intent intent) { |
| List<TestListItem> tests; |
| if (testsByCategory.containsKey(testCategory)) { |
| tests = testsByCategory.get(testCategory); |
| } else { |
| tests = new ArrayList<TestListItem>(); |
| } |
| testsByCategory.put(testCategory, tests); |
| tests.add(TestListItem.newTest(title, className, intent)); |
| } |
| |
| static void updateTestResults(Context context, Map<String, Integer> testResults) { |
| testResults.clear(); |
| ContentResolver resolver = context.getContentResolver(); |
| Cursor cursor = null; |
| try { |
| cursor = resolver.query(TestResultsProvider.RESULTS_CONTENT_URI, |
| TestResultsProvider.ALL_COLUMNS, null, null, null); |
| if (cursor.moveToFirst()) { |
| do { |
| String className = cursor.getString(1); |
| int testResult = cursor.getInt(2); |
| testResults.put(className, testResult); |
| } while (cursor.moveToNext()); |
| } |
| } finally { |
| if (cursor != null) { |
| cursor.close(); |
| } |
| } |
| } |
| |
| public void refreshTestResults() { |
| updateTestResults(mContext, mTestResults); |
| notifyDataSetChanged(); |
| } |
| |
| @Override |
| public boolean areAllItemsEnabled() { |
| // Section headers for test categories are not clickable. |
| return false; |
| } |
| |
| @Override |
| public boolean isEnabled(int position) { |
| return getItem(position).isTest(); |
| } |
| |
| @Override |
| public int getItemViewType(int position) { |
| return getItem(position).isTest() ? TEST_VIEW_TYPE : CATEGORY_HEADER_VIEW_TYPE; |
| } |
| |
| @Override |
| public int getViewTypeCount() { |
| return 2; |
| } |
| |
| public int getCount() { |
| return mRows.size(); |
| } |
| |
| public TestListItem getItem(int position) { |
| return mRows.get(position); |
| } |
| |
| public long getItemId(int position) { |
| return position; |
| } |
| |
| public int getTestResult(int position) { |
| TestListItem item = getItem(position); |
| return mTestResults.containsKey(item.className) |
| ? mTestResults.get(item.className) |
| : TestResult.TEST_RESULT_NOT_EXECUTED; |
| } |
| |
| public View getView(int position, View convertView, ViewGroup parent) { |
| TextView textView; |
| if (convertView == null) { |
| int layout = getLayout(position); |
| textView = (TextView) mLayoutInflater.inflate(layout, parent, false); |
| } else { |
| textView = (TextView) convertView; |
| } |
| |
| TestListItem item = getItem(position); |
| textView.setText(item.title); |
| textView.setPadding(PADDING, 0, PADDING, 0); |
| textView.setCompoundDrawablePadding(PADDING); |
| |
| if (item.isTest()) { |
| int testResult = getTestResult(position); |
| int backgroundResource = 0; |
| int iconResource = 0; |
| |
| /** TODO: Remove fs_ prefix from feature icons since they are used here too. */ |
| switch (testResult) { |
| case TestResult.TEST_RESULT_PASSED: |
| backgroundResource = R.drawable.test_pass_gradient; |
| iconResource = R.drawable.fs_good; |
| break; |
| |
| case TestResult.TEST_RESULT_FAILED: |
| backgroundResource = R.drawable.test_fail_gradient; |
| iconResource = R.drawable.fs_error; |
| break; |
| |
| case TestResult.TEST_RESULT_NOT_EXECUTED: |
| break; |
| |
| default: |
| throw new IllegalArgumentException("Unknown test result: " + testResult); |
| } |
| |
| textView.setBackgroundResource(backgroundResource); |
| textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, iconResource, 0); |
| } |
| |
| return textView; |
| } |
| |
| private int getLayout(int position) { |
| int viewType = getItemViewType(position); |
| switch (viewType) { |
| case CATEGORY_HEADER_VIEW_TYPE: |
| return R.layout.test_category_row; |
| case TEST_VIEW_TYPE: |
| return android.R.layout.simple_list_item_1; |
| default: |
| throw new IllegalArgumentException("Illegal view type: " + viewType); |
| |
| } |
| } |
| } |