Home | History | Annotate | Download | only in verifier
      1 /*
      2  * Copyright (C) 2011 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.Context;
     20 import android.content.Intent;
     21 import android.content.pm.ActivityInfo;
     22 import android.content.pm.PackageManager;
     23 import android.content.pm.ResolveInfo;
     24 import android.os.Bundle;
     25 import android.widget.ListView;
     26 
     27 import java.util.ArrayList;
     28 import java.util.Collections;
     29 import java.util.Comparator;
     30 import java.util.HashMap;
     31 import java.util.Iterator;
     32 import java.util.List;
     33 import java.util.Map;
     34 
     35 /**
     36  * {@link TestListAdapter} that populates the {@link TestListActivity}'s {@link ListView} by
     37  * reading data from the CTS Verifier's AndroidManifest.xml.
     38  * <p>
     39  * Making a new test activity to appear in the list requires the following steps:
     40  *
     41  * <ol>
     42  *     <li>REQUIRED: Add an activity to the AndroidManifest.xml with an intent filter with a
     43  *         main action and the MANUAL_TEST category.
     44  *         <pre>
     45  *             <intent-filter>
     46  *                <action android:name="android.intent.action.MAIN" />
     47  *                <category android:name="android.cts.intent.category.MANUAL_TEST" />
     48  *             </intent-filter>
     49  *         </pre>
     50  *     </li>
     51  *     <li>OPTIONAL: Add a meta data attribute to indicate what category of tests the activity
     52  *         should belong to. If you don't add this attribute, your test will show up in the
     53  *         "Other" tests category.
     54  *         <pre>
     55  *             <meta-data android:name="test_category" android:value="@string/test_category_security" />
     56  *         </pre>
     57  *     </li>
     58  *     <li>OPTIONAL: Add a meta data attribute to indicate whether this test has a parent test.
     59  *         <pre>
     60  *             <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
     61  *         </pre>
     62  *     </li>
     63  *     <li>OPTIONAL: Add a meta data attribute to indicate what features are required to run the
     64  *         test. If the device does not have all of the required features then it will not appear
     65  *         in the test list. Use a colon (:) to specify multiple required features.
     66  *         <pre>
     67  *             <meta-data android:name="test_required_features" android:value="android.hardware.sensor.accelerometer" />
     68  *         </pre>
     69  *     </li>
     70  *
     71  * </ol>
     72  */
     73 public class ManifestTestListAdapter extends TestListAdapter {
     74 
     75     private static final String TEST_CATEGORY_META_DATA = "test_category";
     76 
     77     private static final String TEST_PARENT_META_DATA = "test_parent";
     78 
     79     private static final String TEST_REQUIRED_FEATURES_META_DATA = "test_required_features";
     80 
     81     private Context mContext;
     82 
     83     private String mTestParent;
     84 
     85     public ManifestTestListAdapter(Context context, String testParent) {
     86         super(context);
     87         mContext = context;
     88         mTestParent = testParent;
     89     }
     90 
     91     @Override
     92     protected List<TestListItem> getRows() {
     93 
     94         /*
     95          * 1. Get all the tests belonging to the test parent.
     96          * 2. Get all the tests keyed by their category.
     97          * 3. Flatten the tests and categories into one giant list for the list view.
     98          */
     99 
    100         List<ResolveInfo> infos = getResolveInfosForParent();
    101         Map<String, List<TestListItem>> testsByCategory = getTestsByCategory(infos);
    102 
    103         List<String> testCategories = new ArrayList<String>(testsByCategory.keySet());
    104         Collections.sort(testCategories);
    105 
    106         List<TestListItem> allRows = new ArrayList<TestListItem>();
    107         for (String testCategory : testCategories) {
    108             List<TestListItem> tests = filterTests(testsByCategory.get(testCategory));
    109             if (!tests.isEmpty()) {
    110                 allRows.add(TestListItem.newCategory(testCategory));
    111                 Collections.sort(tests, new Comparator<TestListItem>() {
    112                     @Override
    113                     public int compare(TestListItem item, TestListItem otherItem) {
    114                         return item.title.compareTo(otherItem.title);
    115                     }
    116                 });
    117                 allRows.addAll(tests);
    118             }
    119         }
    120         return allRows;
    121     }
    122 
    123     List<ResolveInfo> getResolveInfosForParent() {
    124         Intent mainIntent = new Intent(Intent.ACTION_MAIN);
    125         mainIntent.addCategory(CATEGORY_MANUAL_TEST);
    126 
    127         PackageManager packageManager = mContext.getPackageManager();
    128         List<ResolveInfo> list = packageManager.queryIntentActivities(mainIntent,
    129                 PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
    130         int size = list.size();
    131 
    132         List<ResolveInfo> matchingList = new ArrayList<ResolveInfo>();
    133         for (int i = 0; i < size; i++) {
    134             ResolveInfo info = list.get(i);
    135             String parent = getTestParent(info.activityInfo.metaData);
    136             if ((mTestParent == null && parent == null)
    137                     || (mTestParent != null && mTestParent.equals(parent))) {
    138                 matchingList.add(info);
    139             }
    140         }
    141         return matchingList;
    142     }
    143 
    144     Map<String, List<TestListItem>> getTestsByCategory(List<ResolveInfo> list) {
    145         Map<String, List<TestListItem>> testsByCategory =
    146                 new HashMap<String, List<TestListItem>>();
    147 
    148         int size = list.size();
    149         for (int i = 0; i < size; i++) {
    150             ResolveInfo info = list.get(i);
    151             String title = getTitle(mContext, info.activityInfo);
    152             String testName = info.activityInfo.name;
    153             Intent intent = getActivityIntent(info.activityInfo);
    154             String[] requiredFeatures = getRequiredFeatures(info.activityInfo.metaData);
    155             TestListItem item = TestListItem.newTest(title, testName, intent, requiredFeatures);
    156 
    157             String testCategory = getTestCategory(mContext, info.activityInfo.metaData);
    158             addTestToCategory(testsByCategory, testCategory, item);
    159         }
    160 
    161         return testsByCategory;
    162     }
    163 
    164     static String getTestCategory(Context context, Bundle metaData) {
    165         String testCategory = null;
    166         if (metaData != null) {
    167             testCategory = metaData.getString(TEST_CATEGORY_META_DATA);
    168         }
    169         if (testCategory != null) {
    170             return testCategory;
    171         } else {
    172             return context.getString(R.string.test_category_other);
    173         }
    174     }
    175 
    176     static String getTestParent(Bundle metaData) {
    177         return metaData != null ? metaData.getString(TEST_PARENT_META_DATA) : null;
    178     }
    179 
    180     static String[] getRequiredFeatures(Bundle metaData) {
    181         if (metaData == null) {
    182             return null;
    183         } else {
    184             String value = metaData.getString(TEST_REQUIRED_FEATURES_META_DATA);
    185             if (value == null) {
    186                 return null;
    187             } else {
    188                 return value.split(":");
    189             }
    190         }
    191     }
    192 
    193     static String getTitle(Context context, ActivityInfo activityInfo) {
    194         if (activityInfo.labelRes != 0) {
    195             return context.getString(activityInfo.labelRes);
    196         } else {
    197             return activityInfo.name;
    198         }
    199     }
    200 
    201     static Intent getActivityIntent(ActivityInfo activityInfo) {
    202         Intent intent = new Intent();
    203         intent.setClassName(activityInfo.packageName, activityInfo.name);
    204         return intent;
    205     }
    206 
    207     static void addTestToCategory(Map<String, List<TestListItem>> testsByCategory,
    208             String testCategory, TestListItem item) {
    209         List<TestListItem> tests;
    210         if (testsByCategory.containsKey(testCategory)) {
    211             tests = testsByCategory.get(testCategory);
    212         } else {
    213             tests = new ArrayList<TestListItem>();
    214         }
    215         testsByCategory.put(testCategory, tests);
    216         tests.add(item);
    217     }
    218 
    219     List<TestListItem> filterTests(List<TestListItem> tests) {
    220         List<TestListItem> filteredTests = new ArrayList<TestListItem>(tests);
    221         PackageManager packageManager = mContext.getPackageManager();
    222         Iterator<TestListItem> iterator = filteredTests.iterator();
    223         while (iterator.hasNext()) {
    224             TestListItem item = iterator.next();
    225             String[] requiredFeatures = item.requiredFeatures;
    226             if (requiredFeatures != null) {
    227                 for (int i = 0; i < requiredFeatures.length; i++) {
    228                     if (!packageManager.hasSystemFeature(requiredFeatures[i])) {
    229                         iterator.remove();
    230                         break;
    231                     }
    232                 }
    233             }
    234         }
    235         return filteredTests;
    236     }
    237 }
    238