Merge "Test zoom in each preview size." into gingerbread
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 08d96e8..625dfe5 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -40,6 +40,7 @@
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_security" />
         </activity>
 
         <activity android:name=".features.FeatureSummaryActivity" android:label="@string/feature_summary">
@@ -47,6 +48,7 @@
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_features" />
         </activity>
 
         <activity android:name=".sensors.AccelerometerTestActivity" android:label="@string/snsr_accel_test"
@@ -55,6 +57,7 @@
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_sensors" />
         </activity>
 
         <activity android:name=".sensors.MagnetometerTestActivity" android:label="@string/snsr_mag_test"
@@ -63,6 +66,7 @@
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_sensors" />
         </activity>
     </application>
 </manifest> 
diff --git a/apps/CtsVerifier/res/layout/test_category_row.xml b/apps/CtsVerifier/res/layout/test_category_row.xml
new file mode 100644
index 0000000..ad47c0a
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/test_category_row.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    style="?android:attr/listSeparatorTextViewStyle"
+    android:id="@+android:id/text1"
+    />
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index ae2406f..6d4d52b 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -17,7 +17,13 @@
     <string name="app_name">CTS Verifier</string>
     <string name="welcome_text">Welcome to the CTS Verifier!</string>
     <string name="continue_button_text">Continue</string>
+    
+    <!-- Strings for TestListActivity -->
     <string name="test_list_title">Manual Test List</string>
+    <string name="test_category_sensors">Sensors</string>
+    <string name="test_category_security">Security</string>
+    <string name="test_category_features">Features</string>
+    <string name="test_category_other">Other</string>
 
     <!-- Strings for FeatureSummaryActivity -->
     <string name="feature_summary">Hardware/Software Feature Summary</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
index 9bf06ee..f0bba52 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
@@ -23,10 +23,13 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Bundle;
+import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
 import android.widget.ListAdapter;
 import android.widget.ListView;
-import android.widget.SimpleAdapter;
+import android.widget.TextView;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -41,6 +44,8 @@
     /** Activities implementing {@link Intent#ACTION_MAIN} and this will appear in the list. */
     static final String CATEGORY_MANUAL_TEST = "android.cts.intent.category.MANUAL_TEST";
 
+    static final String TEST_CATEGORY_META_DATA = "test_category";
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -65,43 +70,92 @@
 
     /**
      * Each {@link ListView} item will have a map associated it with containing the title to
-     * display and the intent used to launch it.
+     * display and the intent used to launch it. If there is no intent, then it is a test category
+     * header.
      */
-    static class TestListAdapter extends SimpleAdapter {
+    static class TestListAdapter extends BaseAdapter {
 
         static final String TITLE = "title";
 
         static final String INTENT = "intent";
 
+        /** View type for a category of tests like "Sensors" or "Features" */
+        static final int TEST_CATEGORY_HEADER_VIEW_TYPE = 0;
+
+        /** View type for an actual test like the Accelerometer test. */
+        static final int TEST_VIEW_TYPE = 1;
+
+        private final List<Map<String, ?>> mData;
+
+        private final LayoutInflater mLayoutInflater;
+
         TestListAdapter(Context context) {
-            super(context, getData(context), android.R.layout.simple_list_item_1,
-                    new String[] {TITLE}, new int[] {android.R.id.text1});
+            this.mData = getData(context);
+            this.mLayoutInflater =
+                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         }
 
         static List<Map<String, ?>> getData(Context context) {
-            List<Map<String, ?>> data = new ArrayList<Map<String,?>>();
+            /*
+             * 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<Map<String, ?>>> testsByCategory = getTestsByCategory(context);
+
+            List<String> testCategories = new ArrayList<String>(testsByCategory.keySet());
+            Collections.sort(testCategories);
+
+            List<Map<String, ?>> data = new ArrayList<Map<String, ?>>();
+            for (String testCategory : testCategories) {
+                addItem(data, testCategory, null);
+
+                List<Map<String, ?>> tests = testsByCategory.get(testCategory);
+                Collections.sort(tests, new Comparator<Map<String, ?>>() {
+                    public int compare(Map<String, ?> item, Map<String, ?> otherItem) {
+                        String title = (String) item.get(TITLE);
+                        String otherTitle = (String) otherItem.get(TITLE);
+                        return title.compareTo(otherTitle);
+                    }
+                });
+                data.addAll(tests);
+            }
+
+            return data;
+        }
+
+        static Map<String, List<Map<String, ?>>> getTestsByCategory(Context context) {
+            Map<String, List<Map<String, ?>>> testsByCategory =
+                new HashMap<String, List<Map<String, ?>>>();
 
             Intent mainIntent = new Intent(Intent.ACTION_MAIN);
             mainIntent.addCategory(CATEGORY_MANUAL_TEST);
 
             PackageManager packageManager = context.getPackageManager();
-            List<ResolveInfo> list = packageManager.queryIntentActivities(mainIntent, 0);
+            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);
                 Intent intent = getActivityIntent(info.activityInfo);
-                addItem(data, title, intent);
+                addItemToCategory(testsByCategory, testCategory, title, intent);
             }
 
-            Collections.sort(data, new Comparator<Map<String, ?>> () {
-                public int compare(Map<String, ?> item, Map<String, ?> otherItem) {
-                    String title = (String) item.get(TITLE);
-                    String otherTitle = (String) otherItem.get(TITLE);
-                    return title.compareTo(otherTitle);
-                }
-            });
+            return testsByCategory;
+        }
 
-            return data;
+        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) {
@@ -118,12 +172,95 @@
             return intent;
         }
 
+        static void addItemToCategory(Map<String, List<Map<String, ?>>> data, String testCategory,
+                String title, Intent intent) {
+            List<Map<String, ?>> tests;
+            if (data.containsKey(testCategory)) {
+                tests = data.get(testCategory);
+            } else {
+                tests = new ArrayList<Map<String, ?>>();
+            }
+            data.put(testCategory, tests);
+            addItem(tests, title, intent);
+        }
+
+        /**
+         * @param tests to add this new item to
+         * @param title to show in the list view
+         * @param intent for a test to launch or null for a test category header
+         */
         @SuppressWarnings("unchecked")
-        static void addItem(List<Map<String, ?>> data, String title, Intent intent) {
+        static void addItem(List<Map<String, ?>> tests, String title, Intent intent) {
             HashMap item = new HashMap(2);
             item.put(TITLE, title);
             item.put(INTENT, intent);
-            data.add(item);
+            tests.add(item);
+        }
+
+        @Override
+        public boolean areAllItemsEnabled() {
+            // Section headers for test categories are not clickable.
+            return false;
+        }
+
+        @Override
+        public boolean isEnabled(int position) {
+            return isTestActivity(position);
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            return isTestActivity(position) ? TEST_VIEW_TYPE : TEST_CATEGORY_HEADER_VIEW_TYPE;
+        }
+
+        private boolean isTestActivity(int position) {
+            Map<String, ?> item = getItem(position);
+            return item.get(INTENT) != null;
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            return 2;
+        }
+
+        public int getCount() {
+            return mData.size();
+        }
+
+        public Map<String, ?> getItem(int position) {
+            return mData.get(position);
+        }
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        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;
+            }
+
+            Map<String, ?> data = getItem(position);
+            String title = (String) data.get(TITLE);
+            textView.setText(title);
+            return textView;
+        }
+
+        private int getLayout(int position) {
+            int viewType = getItemViewType(position);
+            switch (viewType) {
+                case TEST_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);
+
+            }
         }
     }
 }
diff --git a/tools/utils/buildCts.py b/tools/utils/buildCts.py
index b1a6700..35a3a11 100755
--- a/tools/utils/buildCts.py
+++ b/tools/utils/buildCts.py
@@ -94,9 +94,9 @@
     source_path = [
         'frameworks/base/core/java',            # android test classes
         'frameworks/base/test-runner/src',      # test runner
-        'dalvik/libcore/junit/src/main/java',   # junit classes
+        'libcore/junit/src/main/java',          # junit classes
         'development/tools/hosttestlib/src',    # hosttestlib TestCase extensions
-        'dalvik/libcore/dalvik/src/main/java',  # test annotations
+        'libcore/dalvik/src/main/java',         # test annotations
         'cts/tests/src',                        # cts test stubs
         source_root                             # the source for this package
     ]