diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-02-01 02:26:02 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2024-02-01 02:26:02 +0000 |
commit | 0464c22aed42158b51064fec7deedd870de2b0b6 (patch) | |
tree | 2338f4a4d20ff124c497ad22b42a33d8b56da879 | |
parent | 4256ce17cbcebb7c225486ee3b9938e064fdb35d (diff) | |
parent | 791c816a3518b805f7eda7e266f139976d518a7c (diff) | |
download | cts-android-cts-13.0_r7.tar.gz |
Merge "Merge cherrypicks of ['android-review.googlesource.com/2905571', 'android-review.googlesource.com/2935030', 'android-review.googlesource.com/2935032'] into sparse-11368268-L86400030001713872. SPARSE_CHANGE: Ia4e8dc1b3ce017d0ac677b6ab447ae11980d33cb SPARSE_CHANGE: Id31098525e11afdffc1099154ec1ae25dd4a686c SPARSE_CHANGE: Ic9c945a10e50f27de6c71716ff134bf68fdee359" into sparse-11368268-L86400030001713872android-cts-13.0_r7
9 files changed, 787 insertions, 425 deletions
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml index c2cf1e19b2f..1cf81576523 100644 --- a/apps/CtsVerifier/AndroidManifest.xml +++ b/apps/CtsVerifier/AndroidManifest.xml @@ -4257,10 +4257,13 @@ android:targetActivity=".TestListActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> + <action android:name="android.intent.action.SEARCH" /> <category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LEANBACK_LAUNCHER" /> </intent-filter> + <meta-data android:name="android.app.searchable" + android:resource="@xml/searchable"/> </activity-alias> <!-- remove comment from the next activity to see the sample test surfacing in the app --> diff --git a/apps/CtsVerifier/res/layout/system_switch.xml b/apps/CtsVerifier/res/layout/system_switch.xml new file mode 100644 index 00000000000..d810f18f684 --- /dev/null +++ b/apps/CtsVerifier/res/layout/system_switch.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2023 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. +--> + +<!-- Switch button to enable verifier-system plan. --> +<RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="match_parent" + android:orientation="horizontal" > + <Switch + android:id="@+id/switch_button" + android:text="@string/system" + android:textOn="@string/system_on" + android:textOff="@string/system_off" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerHorizontal="true" + android:layout_centerVertical="true" /> +</RelativeLayout>
\ No newline at end of file diff --git a/apps/CtsVerifier/res/menu/test_list_menu.xml b/apps/CtsVerifier/res/menu/test_list_menu.xml index 2c104a0a34b..70982b09263 100644 --- a/apps/CtsVerifier/res/menu/test_list_menu.xml +++ b/apps/CtsVerifier/res/menu/test_list_menu.xml @@ -4,7 +4,12 @@ android:id="@+id/switch_item" android:title="@string/view" android:actionLayout="@layout/display_mode_switch" - android:showAsAction="ifRoom" /> + android:showAsAction="always" /> + <item + android:id="@+id/system_switch_item" + android:title="@string/system" + android:actionLayout="@layout/system_switch" + android:showAsAction="always" /> <item android:id="@+id/clear" android:icon="@android:drawable/ic_menu_delete" android:title="@string/clear" @@ -13,4 +18,10 @@ android:icon="@android:drawable/ic_menu_save" android:title="@string/export" android:showAsAction="ifRoom" /> + <item + android:id="@+id/search_test" + android:title="@string/search_title" + android:actionViewClass="android.widget.SearchView" + android:showAsAction="collapseActionView|ifRoom" + android:imeOptions="actionSearch" /> </menu> diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml index 5ebb7c14645..5aa2b91fd7c 100644 --- a/apps/CtsVerifier/res/values/strings.xml +++ b/apps/CtsVerifier/res/values/strings.xml @@ -17,7 +17,8 @@ <string name="app_name">CTS Verifier</string> <string name="module_id">noabi CtsVerifier</string> - <string name="title_version">CTS Verifier %1$s</string> + <string name="title_version">Verifier %1$s</string> + <string name="version_number_format">Version #: %d</string> <string name="pass_button_text">Pass</string> <string name="info_button_text">Info</string> @@ -31,6 +32,14 @@ <string name="retry_button_text">Retry</string> <string name="finish_button_text">Finish</string> <string name="fail_and_next_button_text">Fail and Next</string> + <string name="yes_string">Yes</string> + <string name="no_string">No</string> + <string name="search_label">TestListActivity</string> + <string name="search_hint">Search Tests</string> + <string name="search_title">Search</string> + <string name="system">System</string> + <string name="system_on">ON</string> + <string name="system_off">OFF</string> <!-- Strings for CtsReportLog warning --> <string name="reportlog_warning_title">CTS-Verifier Report Log</string> diff --git a/apps/CtsVerifier/res/xml/searchable.xml b/apps/CtsVerifier/res/xml/searchable.xml new file mode 100644 index 00000000000..a443c076ee3 --- /dev/null +++ b/apps/CtsVerifier/res/xml/searchable.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<searchable xmlns:android="http://schemas.android.com/apk/res/android" + android:label="@string/search_label" + android:hint="@string/search_hint" > +</searchable>
\ No newline at end of file diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java index e9a3e0d8e9c..5a29690c9c0 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java @@ -17,7 +17,6 @@ package com.android.cts.verifier; import static com.android.cts.verifier.TestListActivity.sCurrentDisplayMode; -import static com.android.cts.verifier.TestListActivity.sInitialLaunch; import android.annotation.SuppressLint; import android.content.Context; @@ -28,8 +27,8 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.hardware.SensorPrivacyManager; -import android.os.Bundle; import android.os.BatteryManager; +import android.os.Bundle; import android.telephony.TelephonyManager; import android.util.Log; import android.widget.ListView; @@ -45,76 +44,69 @@ import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; /** - * {@link TestListAdapter} that populates the {@link TestListActivity}'s {@link ListView} by - * reading data from the CTS Verifier's AndroidManifest.xml. - * <p> - * Making a new test activity to appear in the list requires the following steps: + * {@link TestListAdapter} that populates the {@link TestListActivity}'s {@link ListView} by reading + * data from the CTS Verifier's AndroidManifest.xml. + * + * <p>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> + * <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>REQUIRED: Add a meta data attribute to indicate which display modes of tests the activity - * should belong to. "single_display_mode" indicates a test is only needed to run on the - * main display mode (i.e. unfolded), and "multi_display_mode" indicates a test is required - * to run under both modes (i.e. both folded and unfolded).If you don't add this attribute, - * your test will show up in both unfolded and folded modes. - * <pre> + * <li>REQUIRED: Add a meta data attribute to indicate which display modes of tests the activity + * should belong to. "single_display_mode" indicates a test is only needed to run on the main + * display mode (i.e. unfolded), and "multi_display_mode" indicates a test is required to run + * under both modes (i.e. both folded and unfolded).If you don't add this attribute, your test + * will show up in both unfolded and folded modes. + * <pre> * <meta-data android:name="display_mode" android:value="multi_display_mode" /> * </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> + * <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> - * <li>OPTIONAL: Add a meta data attribute to indicate whether this test has a parent test. - * <pre> + * <li>OPTIONAL: Add a meta data attribute to indicate whether this test has a parent test. + * <pre> * <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" /> * </pre> - * </li> - * <li>OPTIONAL: Add a meta data attribute to indicate what features are required to run the - * test. If the device does not have all of the required features then it will not appear - * in the test list. Use a colon (:) to specify multiple required features. - * <pre> + * <li>OPTIONAL: Add a meta data attribute to indicate what features are required to run the test. + * If the device does not have all of the required features then it will not appear in the + * test list. Use a colon (:) to specify multiple required features. + * <pre> * <meta-data android:name="test_required_features" android:value="android.hardware.sensor.accelerometer" /> * </pre> - * </li> - * <li>OPTIONAL: Add a meta data attribute to indicate features such that, if any present, the - * test gets excluded from being shown. If the device has any of the excluded features then - * the test will not appear in the test list. Use a colon (:) to specify multiple features - * to exclude for the test. Note that the colon means "or" in this case. - * <pre> + * <li>OPTIONAL: Add a meta data attribute to indicate features such that, if any present, the + * test gets excluded from being shown. If the device has any of the excluded features then + * the test will not appear in the test list. Use a colon (:) to specify multiple features to + * exclude for the test. Note that the colon means "or" in this case. + * <pre> * <meta-data android:name="test_excluded_features" android:value="android.hardware.type.television" /> * </pre> - * </li> - * <li>OPTIONAL: Add a meta data attribute to indicate features such that, if any present, - * the test is applicable to run. If the device has any of the applicable features then - * the test will appear in the test list. Use a colon (:) to specify multiple features - * <pre> + * <li>OPTIONAL: Add a meta data attribute to indicate features such that, if any present, the + * test is applicable to run. If the device has any of the applicable features then the test + * will appear in the test list. Use a colon (:) to specify multiple features + * <pre> * <meta-data android:name="test_applicable_features" android:value="android.hardware.sensor.compass" /> * </pre> - * </li> - * <li>OPTIONAL: Add a meta data attribute to indicate which intent actions are required to run - * the test. If the device does not have activities that handle all those actions, then it - * will not appear in the test list. Use a colon (:) to specify multiple required intent actions. - * <pre> + * <li>OPTIONAL: Add a meta data attribute to indicate which intent actions are required to run + * the test. If the device does not have activities that handle all those actions, then it + * will not appear in the test list. Use a colon (:) to specify multiple required intent + * actions. + * <pre> * <meta-data android:name="test_required_actions" android:value="android.app.action.ADD_DEVICE_ADMIN" /> * </pre> - * </li> - * * </ol> */ public class ManifestTestListAdapter extends TestListAdapter { @@ -154,20 +146,50 @@ public class ManifestTestListAdapter extends TestListAdapter { private static final String CONFIG_CHANGEABLE_VOLUME = "config_changeable_volume"; - /** The config to represent that a test is only needed to run in the main display mode - * (i.e. unfolded) */ + /** + * The config to represent that a test is only needed to run in the main display mode (i.e. + * unfolded). + */ private static final String SINGLE_DISPLAY_MODE = "single_display_mode"; - /** The config to represent that a test is needed to run in the multiple display modes - * (i.e. both unfolded and folded) */ + /** + * The config to represent that a test is needed to run in the multiple display modes (i.e. both + * unfolded and folded). + */ private static final String MULTIPLE_DISPLAY_MODE = "multi_display_mode"; + /** The config to represent that a test is only needed to run in the folded display mode. */ + private static final String FOLDED_DISPLAY_MODE = "folded_display_mode"; + + /** + * The config to represent that a test is marked as pass when it passes either in folded mode or + * in unfolded mode. + */ + private static final String EITHER_MODE = "either_mode"; + + /** + * The user is not a {@link UserManager#isProfile() profile} and is running in the background, + * but {@link UserManager#isUserVisible() visible} in a display. + */ + private static final String USER_TYPE_VISIBLE_BG_USER = "visible_background_non-profile_user"; + + /** The name of the camera ITS test of a {@link TestListItem}. */ + private static final String CAMERA_ITS_TEST = + "com.android.cts.verifier.camera.its.ItsTestActivity"; + + /** The name of the camera ITS test (folded mode) of a {@link TestListItem}. */ + private static final String CAMERA_ITS_TEST_FOLDED = CAMERA_ITS_TEST + "[folded]"; + private final HashSet<String> mDisabledTests; private Context mContext; private String mTestParent; + public ManifestTestListAdapter(Context context, String testParent) { + this(context, testParent, context.getResources().getStringArray(R.array.disabled_tests)); + } + public ManifestTestListAdapter(Context context, String testParent, String[] disabledTestArray) { super(context); mContext = context; @@ -178,36 +200,33 @@ public class ManifestTestListAdapter extends TestListAdapter { } } - public ManifestTestListAdapter(Context context, String testParent) { - this(context, testParent, context.getResources().getStringArray(R.array.disabled_tests)); - } - @Override protected List<TestListItem> getRows() { - List<TestListItem> allRows = new ArrayList<TestListItem>(); - // When launching at the first time or after killing the process, needs to fetch the // test items of all display modes as the bases for switching. if (mDisplayModesTests.isEmpty()) { for (DisplayMode mode : DisplayMode.values()) { - allRows = getRowsWithDisplayMode(mode.toString()); - mDisplayModesTests.put(mode.toString(), allRows); + mDisplayModesTests.put(mode.toString(), getRowsWithDisplayMode(mode.toString())); } } - if (!sInitialLaunch) { - return getRowsWithDisplayMode(sCurrentDisplayMode); + if (mTestFilter != null || TestListActivity.getIsSystemEnabled()) { + // Filter test rows dynamically when the filter is specified or verifier-system plan is + // enabled. + return getRowsWithDisplayMode(sCurrentDisplayMode.toString()); + } else { + return mDisplayModesTests.getOrDefault( + sCurrentDisplayMode.toString(), new ArrayList<>()); } - return allRows; } /** * Gets all rows based on the specific display mode. * - * @param mode Given display mode. - * @return A list containing all test itmes in the given display mode. + * @param mode the given display mode + * @return a list containing all test itmes in the given display mode */ - private List<TestListItem> getRowsWithDisplayMode (String mode) { + private List<TestListItem> getRowsWithDisplayMode(String mode) { /* * 1. Get all the tests belonging to the test parent. * 2. Get all the tests keyed by their category. @@ -236,8 +255,9 @@ public class ManifestTestListAdapter extends TestListAdapter { mainIntent.setPackage(mContext.getPackageName()); PackageManager packageManager = mContext.getPackageManager(); - List<ResolveInfo> list = packageManager.queryIntentActivities(mainIntent, - PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA); + List<ResolveInfo> list = + packageManager.queryIntentActivities( + mainIntent, PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA); int size = list.size(); List<ResolveInfo> matchingList = new ArrayList<>(); @@ -272,9 +292,17 @@ public class ManifestTestListAdapter extends TestListAdapter { String[] applicableFeatures = getApplicableFeatures(info.activityInfo.metaData); String displayMode = getDisplayMode(info.activityInfo.metaData); - TestListItem item = TestListItem.newTest(title, testName, intent, requiredFeatures, - requiredConfigs, requiredActions, excludedFeatures, applicableFeatures, - displayMode); + TestListItem item = + TestListItem.newTest( + title, + testName, + intent, + requiredFeatures, + requiredConfigs, + requiredActions, + excludedFeatures, + applicableFeatures, + displayMode); String testCategory = getTestCategory(mContext, info.activityInfo.metaData); addTestToCategory(testsByCategory, testCategory, item); @@ -367,8 +395,8 @@ public class ManifestTestListAdapter extends TestListAdapter { /** * Gets the configuration of the display mode per test. The default value is multi_display_mode. * - * @param metaData Given metadata of the display mode. - * @return A string representing the display mode of the test. + * @param metaData the given metadata of the display mode + * @return a string representing the display mode of the test */ static String getDisplayMode(Bundle metaData) { if (metaData == null) { @@ -392,8 +420,10 @@ public class ManifestTestListAdapter extends TestListAdapter { return intent; } - static void addTestToCategory(Map<String, List<TestListItem>> testsByCategory, - String testCategory, TestListItem item) { + static void addTestToCategory( + Map<String, List<TestListItem>> testsByCategory, + String testCategory, + TestListItem item) { List<TestListItem> tests; if (testsByCategory.containsKey(testCategory)) { tests = testsByCategory.get(testCategory); @@ -444,17 +474,18 @@ public class ManifestTestListAdapter extends TestListAdapter { return true; } - private boolean matchAllConfigs(String[] configs) { + private boolean matchAllConfigs(Context context, String[] configs) { if (configs != null) { for (String config : configs) { switch (config) { case CONFIG_NO_EMULATOR: try { - Method getStringMethod = ClassLoader.getSystemClassLoader() - .loadClass("android.os.SystemProperties") - .getMethod("get", String.class); - String emulatorKernel = (String) getStringMethod.invoke("0", - "ro.boot.qemu"); + Method getStringMethod = + ClassLoader.getSystemClassLoader() + .loadClass("android.os.SystemProperties") + .getMethod("get", String.class); + String emulatorKernel = + (String) getStringMethod.invoke("0", "ro.boot.qemu"); if (emulatorKernel.equals("1")) { return false; } @@ -463,14 +494,14 @@ public class ManifestTestListAdapter extends TestListAdapter { } break; case CONFIG_VOICE_CAPABLE: - TelephonyManager telephonyManager = mContext.getSystemService( - TelephonyManager.class); + TelephonyManager telephonyManager = + mContext.getSystemService(TelephonyManager.class); if (!telephonyManager.isVoiceCapable()) { return false; } break; case CONFIG_HAS_RECENTS: - if (!getSystemResourceFlag("config_hasRecents")) { + if (!getSystemResourceFlag(context, "config_hasRecents")) { return false; } break; @@ -493,7 +524,7 @@ public class ManifestTestListAdapter extends TestListAdapter { } break; case CONFIG_QUICK_SETTINGS_SUPPORTED: - if (!getSystemResourceFlag("config_quickSettingsSupported")) { + if (!getSystemResourceFlag(context, "config_quickSettingsSupported")) { return false; } break; @@ -502,7 +533,7 @@ public class ManifestTestListAdapter extends TestListAdapter { case CONFIG_HAS_CAMERA_TOGGLE: return isHardwareToggleSupported(SensorPrivacyManager.Sensors.CAMERA); case CONFIG_CHANGEABLE_VOLUME: - return !getSystemResourceFlag("config_useFixedVolume"); + return !getSystemResourceFlag(context, "config_useFixedVolume"); default: break; } @@ -512,11 +543,11 @@ public class ManifestTestListAdapter extends TestListAdapter { } /** - * Check if the test should be ran by the given display mode. + * Checks if the test should be ran by the given display mode. * - * @param mode Configs of the display mode. - * @param currentMode Given display mode. - * @return True if the given display mode matches the configs, otherwise, return false; + * @param mode the display mode config of the test + * @param currentMode the given display mode + * @return true if the given display mode matches the configs, otherwise, return false */ private boolean matchDisplayMode(String mode, String currentMode) { if (mode == null) { @@ -532,8 +563,33 @@ public class ManifestTestListAdapter extends TestListAdapter { } } - private boolean getSystemResourceFlag(String key) { - final Resources systemRes = mContext.getResources().getSystem(); + /** Checks whether the title of the test matches the test filter. */ + private boolean macthTestFilter(String testTitle) { + if (mTestFilter == null) { + return true; + } + return testTitle != null + && testTitle + .toLowerCase(Locale.getDefault()) + .contains(mTestFilter.toLowerCase(Locale.getDefault())); + } + + /** + * Checks whether the test matches the current status of verifier-system plan. + * + * <p>When verifier-system plan is disabled, all CTS-V tests are shown. + * + * <p>When verifier-system plan is enabled, specific tests are filtered out, e.g., camera ITS. + */ + private static boolean matchSystemPlanStatus(String testName) { + if (testName == null || !TestListActivity.getIsSystemEnabled()) { + return true; + } + return !testName.equals(CAMERA_ITS_TEST) && !testName.equals(CAMERA_ITS_TEST_FOLDED); + } + + private static boolean getSystemResourceFlag(Context context, String key) { + final Resources systemRes = context.getResources().getSystem(); final int id = systemRes.getIdentifier(key, "bool", "android"); if (id == Resources.ID_NULL) { // The flag being queried should exist in @@ -544,7 +600,9 @@ public class ManifestTestListAdapter extends TestListAdapter { } private static List<Integer> getHdmiDeviceType() - throws InvocationTargetException, IllegalAccessException, ClassNotFoundException, + throws InvocationTargetException, + IllegalAccessException, + ClassNotFoundException, NoSuchMethodException { Method getStringMethod = ClassLoader.getSystemClassLoader() @@ -559,18 +617,22 @@ public class ManifestTestListAdapter extends TestListAdapter { .collect(Collectors.toList()); } - private boolean hasBattery(){ - final Intent batteryInfo = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + private boolean hasBattery() { + final Intent batteryInfo = + mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); return batteryInfo.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true); } List<TestListItem> filterTests(List<TestListItem> tests, String mode) { List<TestListItem> filteredTests = new ArrayList<>(); for (TestListItem test : tests) { - if (!hasAnyFeature(test.excludedFeatures) && hasAllFeatures(test.requiredFeatures) + if (!hasAnyFeature(test.excludedFeatures) + && hasAllFeatures(test.requiredFeatures) && hasAllActions(test.requiredActions) - && matchAllConfigs(test.requiredConfigs) - && matchDisplayMode(test.displayMode, mode)) { + && matchAllConfigs(mContext, test.requiredConfigs) + && matchDisplayMode(test.displayMode, mode) + && macthTestFilter(test.title) + && matchSystemPlanStatus(test.testName)) { if (test.applicableFeatures == null || hasAnyFeature(test.applicableFeatures)) { // Add suffix in test name if the test is in the folded mode. test.testName = setTestNameSuffix(mode, test.testName); @@ -585,39 +647,15 @@ public class ManifestTestListAdapter extends TestListAdapter { return filteredTests; } - @Override - public int getCount() { - if (!sInitialLaunch && mTestParent == null) { - return mDisplayModesTests.getOrDefault(sCurrentDisplayMode, new ArrayList<>()).size(); - } - return super.getCount(); - } - - @Override - public TestListItem getItem(int position) { - if (mTestParent == null) { - return mDisplayModesTests.get(sCurrentDisplayMode).get(position); - } - return super.getItem(position); - } - - @Override - public void loadTestResults() { - if (mTestParent == null) { - new RefreshTestResultsTask(true).execute(); - } else { - super.loadTestResults(); - } - } - @SuppressLint("NewApi") private boolean isHardwareToggleSupported(final int sensorType) { boolean isToggleSupported = false; - SensorPrivacyManager sensorPrivacyManager = mContext.getSystemService( - SensorPrivacyManager.class); + SensorPrivacyManager sensorPrivacyManager = + mContext.getSystemService(SensorPrivacyManager.class); if (sensorPrivacyManager != null) { - isToggleSupported = sensorPrivacyManager.supportsSensorToggle( - SensorPrivacyManager.TOGGLE_TYPE_HARDWARE, sensorType); + isToggleSupported = + sensorPrivacyManager.supportsSensorToggle( + SensorPrivacyManager.TOGGLE_TYPE_HARDWARE, sensorType); } return isToggleSupported; } diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java b/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java index f95393a3101..baa19519c26 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java @@ -50,9 +50,7 @@ import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger; -/** - * Background task to generate a report and save it to external storage. - */ +/** Background task to generate a report and save it to external storage. */ public class ReportExporter extends AsyncTask<Void, Void, String> { private static final String TAG = ReportExporter.class.getSimpleName(); private static final boolean DEBUG = true; @@ -65,7 +63,10 @@ public class ReportExporter extends AsyncTask<Void, Void, String> { private static final String LOG_URL = null; private static final String REFERENCE_URL = null; private static final String SUITE_NAME_METADATA_KEY = "SuiteName"; - private static final String SUITE_PLAN = "verifier"; + // Default CTS-V suite_plan shown in test_result.xml. + private static final String DEFAULT_SUITE_PLAN = "verifier"; + // CTS Verifier System suite_plan shown in test_result.xml. + private static final String SYSTEM_SUITE_PLAN = "verifier-system"; private static final String SUITE_BUILD = "0"; private static final String ZIP_EXTENSION = ".zip"; private final long START_MS = System.currentTimeMillis(); @@ -88,9 +89,10 @@ public class ReportExporter extends AsyncTask<Void, Void, String> { } File reportLogFolder = - new File(Environment.getExternalStorageDirectory().getAbsolutePath() - + File.separator - + LOGS_DIRECTORY); + new File( + Environment.getExternalStorageDirectory().getAbsolutePath() + + File.separator + + LOGS_DIRECTORY); copyFilesRecursively(reportLogFolder, tempDir); } @@ -104,10 +106,7 @@ public class ReportExporter extends AsyncTask<Void, Void, String> { for (File file : files) { Path src = Paths.get(file.getAbsolutePath()); - Path dest = Paths.get( - destFolder.getAbsolutePath() - + File.separator - + file.getName()); + Path dest = Paths.get(destFolder.getAbsolutePath() + File.separator + file.getName()); try { Files.copy(src, dest, StandardCopyOption.REPLACE_EXISTING); } catch (IOException ex) { @@ -119,7 +118,6 @@ public class ReportExporter extends AsyncTask<Void, Void, String> { } } - @Override protected String doInBackground(Void... params) { if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { @@ -148,15 +146,24 @@ public class ReportExporter extends AsyncTask<Void, Void, String> { copyReportFiles(tempDir); // create a File object for a report ZIP file - File reportZipFile = new File( - verifierReportsDir, getReportName(suiteName) + ZIP_EXTENSION); + File reportZipFile = new File(verifierReportsDir, getReportName(suiteName) + ZIP_EXTENSION); try { // Serialize the report String versionName = Version.getVersionName(mContext); - ResultHandler.writeResults(suiteName, versionName, SUITE_PLAN, SUITE_BUILD, - result, tempDir, START_MS, END_MS, REFERENCE_URL, LOG_URL, - COMMAND_LINE_ARGS, null); + ResultHandler.writeResults( + suiteName, + versionName, + TestListActivity.getIsSystemEnabled() ? SYSTEM_SUITE_PLAN : DEFAULT_SUITE_PLAN, + SUITE_BUILD, + result, + tempDir, + START_MS, + END_MS, + REFERENCE_URL, + LOG_URL, + COMMAND_LINE_ARGS, + null); // Serialize the screenshots metadata if at least one exists if (containsScreenshotMetadata(result)) { @@ -200,8 +207,8 @@ public class ReportExporter extends AsyncTask<Void, Void, String> { Log.d(TAG, "---- saveReportOnInternalStorage(" + reportZipFile.getAbsolutePath() + ")"); } try { - ParcelFileDescriptor pfd = ParcelFileDescriptor.open( - reportZipFile, ParcelFileDescriptor.MODE_READ_ONLY); + ParcelFileDescriptor pfd = + ParcelFileDescriptor.open(reportZipFile, ParcelFileDescriptor.MODE_READ_ONLY); InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd); File verifierDir = mContext.getDir(REPORT_DIRECTORY, Context.MODE_PRIVATE); @@ -223,8 +230,7 @@ public class ReportExporter extends AsyncTask<Void, Void, String> { for (String resultFileName : ResultHandler.RESULT_RESOURCES) { InputStream rawStream = null; try { - rawStream = mContext.getAssets().open( - String.format("report/%s", resultFileName)); + rawStream = mContext.getAssets().open(String.format("report/%s", resultFileName)); } catch (IOException e) { LOG.log(Level.WARNING, "Failed to load " + resultFileName + " from assets."); } @@ -242,7 +248,8 @@ public class ReportExporter extends AsyncTask<Void, Void, String> { private String getReportName(String suiteName) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd_HH.mm.ss", Locale.ENGLISH); String date = dateFormat.format(new Date()); - return String.format("%s-%s-%s-%s-%s-%s", + return String.format( + "%s-%s-%s-%s-%s-%s", date, suiteName, Build.MANUFACTURER, Build.PRODUCT, Build.DEVICE, Build.ID); } diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java index 9f987a2822e..e3f06ddb2cf 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java @@ -37,6 +37,7 @@ import android.view.MenuItem; import android.view.View; import android.view.Window; import android.widget.CompoundButton; +import android.widget.SearchView; import android.widget.Switch; import android.widget.Toast; @@ -52,15 +53,19 @@ public class TestListActivity extends AbstractTestListActivity implements View.O private static final String TAG = TestListActivity.class.getSimpleName(); // Records the current display mode. // Default is unfolded mode, and it will be changed when clicking the switch button. - public static String sCurrentDisplayMode = DisplayMode.UNFOLDED.toString(); - // Flag of launch app to fetch the unfolded/folded tests in main view from AndroidManifest.xml. - protected static boolean sInitialLaunch; + public static volatile String sCurrentDisplayMode = DisplayMode.UNFOLDED.toString(); + + // Whether the verifier-system plan is enabled. + private static boolean sIsSystemEnabled = false; + // Whether the system switch has been toggled. + private static boolean sHasSystemToggled = false; private String[] mRequestedPermissions; // Enumerates the display modes, including unfolded and folded. protected enum DisplayMode { - UNFOLDED, FOLDED; + UNFOLDED, + FOLDED; @Override public String toString() { @@ -68,10 +73,10 @@ public class TestListActivity extends AbstractTestListActivity implements View.O } /** - * Coverts the mode as suffix with brackets for test name. + * Converts the mode as suffix with brackets for test name. * - * @return A string containing mode with brackets for folded mode; - * empty string for unfolded mode. + * @return a string containing mode with brackets for folded mode; empty string for unfolded + * mode */ public String asSuffix() { if (name().equals(FOLDED.name())) { @@ -92,21 +97,29 @@ public class TestListActivity extends AbstractTestListActivity implements View.O try { PackageManager pm = getPackageManager(); - PackageInfo packageInfo = pm.getPackageInfo( - getApplicationInfo().packageName, PackageManager.GET_PERMISSIONS); + PackageInfo packageInfo = + pm.getPackageInfo( + getApplicationInfo().packageName, PackageManager.GET_PERMISSIONS); mRequestedPermissions = packageInfo.requestedPermissions; if (mRequestedPermissions != null) { - String[] permissionsToRequest = removeString(mRequestedPermissions, - Manifest.permission.ACCESS_BACKGROUND_LOCATION); - permissionsToRequest = Arrays.stream(permissionsToRequest).filter(s -> { - try { - return (pm.getPermissionInfo(s, 0).getProtection() & PROTECTION_DANGEROUS) - != 0; - } catch (NameNotFoundException e) { - return false; - } - }).toArray(String[]::new); + String[] permissionsToRequest = + removeString( + mRequestedPermissions, + Manifest.permission.ACCESS_BACKGROUND_LOCATION); + permissionsToRequest = + Arrays.stream(permissionsToRequest) + .filter( + s -> { + try { + return (pm.getPermissionInfo(s, 0).getProtection() + & PROTECTION_DANGEROUS) + != 0; + } catch (NameNotFoundException e) { + return false; + } + }) + .toArray(String[]::new); requestPermissions(permissionsToRequest, CTS_VERIFIER_PERMISSION_REQUEST); } createContinue(); @@ -116,31 +129,6 @@ public class TestListActivity extends AbstractTestListActivity implements View.O } } - private void createContinue() { - if (!isTaskRoot()) { - finish(); - } - sInitialLaunch = true; - - // Restores the last display mode when launching the app after killing the process. - if (getCurrentDisplayMode().equals(DisplayMode.FOLDED.toString())) { - sCurrentDisplayMode = DisplayMode.FOLDED.toString(); - } - - setTitle(getString(R.string.title_version, Version.getVersionName(this))); - - if (!getWindow().hasFeature(Window.FEATURE_ACTION_BAR)) { - View footer = getLayoutInflater().inflate(R.layout.test_list_footer, null); - - footer.findViewById(R.id.clear).setOnClickListener(this); - footer.findViewById(R.id.export).setOnClickListener(this); - - getListView().addFooterView(footer); - } - - setTestListAdapter(new ManifestTestListAdapter(this, null)); - } - @Override public void onRequestPermissionsResult( int requestCode, String permissions[], int[] grantResults) { @@ -150,9 +138,10 @@ public class TestListActivity extends AbstractTestListActivity implements View.O // If we're sending them to settings we don't need to request background location // since they can just grant in settings. sendUserToSettings(); - } else if (new ArrayList<>(Arrays.asList(mRequestedPermissions)).contains( - Manifest.permission.ACCESS_BACKGROUND_LOCATION)) { - requestPermissions(new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION}, + } else if (new ArrayList<>(Arrays.asList(mRequestedPermissions)) + .contains(Manifest.permission.ACCESS_BACKGROUND_LOCATION)) { + requestPermissions( + new String[] {Manifest.permission.ACCESS_BACKGROUND_LOCATION}, CTS_VERIFIER_BACKGROUND_LOCATION_PERMISSION_REQUEST); } return; @@ -166,20 +155,6 @@ public class TestListActivity extends AbstractTestListActivity implements View.O } } - private AlertDialog sendUserToSettings() { - return new AlertDialog.Builder(this) - .setTitle("Please grant all permissions") - .setPositiveButton( - "Ok", (dialog, which) -> { - if (which == AlertDialog.BUTTON_POSITIVE) { - startActivity(new Intent( - Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData( - Uri.fromParts("package", getPackageName(), null))); - } - }) - .show(); - } - @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); @@ -194,18 +169,60 @@ public class TestListActivity extends AbstractTestListActivity implements View.O boolean isFoldedMode = sCurrentDisplayMode.equals(DisplayMode.FOLDED.toString()); displayModeSwitch.setChecked(isFoldedMode); - displayModeSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, - boolean isChecked) { - if (isChecked) { - sCurrentDisplayMode = DisplayMode.FOLDED.toString(); - } else { - sCurrentDisplayMode = DisplayMode.UNFOLDED.toString(); - } - handleSwitchItemSelected(); - } - }); + displayModeSwitch.setOnCheckedChangeListener( + new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked) { + sCurrentDisplayMode = DisplayMode.FOLDED.toString(); + } else { + sCurrentDisplayMode = DisplayMode.UNFOLDED.toString(); + } + handleSwitchItemSelected(); + } + }); + + // Switch button for verifier-system plan. + item = (MenuItem) menu.findItem(R.id.system_switch_item); + item.setActionView(R.layout.system_switch); + final Switch systemSwitch = item.getActionView().findViewById(R.id.switch_button); + + systemSwitch.setChecked(sIsSystemEnabled); + systemSwitch.setOnCheckedChangeListener( + new CompoundButton.OnCheckedChangeListener() { + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (!sHasSystemToggled && isChecked) { + sHasSystemToggled = true; + notifyUserSystemPlan(systemSwitch); + } else { + updateIsSystemEnabled(isChecked); + } + } + }); + + SearchView searchView = (SearchView) menu.findItem(R.id.search_test).getActionView(); + searchView.setOnQueryTextListener( + new SearchView.OnQueryTextListener() { + + public boolean onQueryTextSubmit(String query) { + Log.i(TAG, "Got submitted query: " + query); + handleQueryUpdated(query); + return true; + } + + public boolean onQueryTextChange(String newText) { + if (newText == null || newText.isEmpty()) { + Log.i(TAG, "Clear filter"); + handleQueryUpdated(newText); + return true; + } else { + return false; + } + } + }); + return true; } @@ -214,17 +231,141 @@ public class TestListActivity extends AbstractTestListActivity implements View.O return handleMenuItemSelected(item.getItemId()) ? true : super.onOptionsItemSelected(item); } + /** Gets the verifier-system plan enabled status. */ + static boolean getIsSystemEnabled() { + return sIsSystemEnabled; + } + + /** Checks if a list of int array contains a given int value. */ + private static boolean arrayContains(int[] array, int value) { + if (array == null) { + return false; + } + for (int element : array) { + if (element == value) { + return true; + } + } + return false; + } + + /** Removes the first occurrence of a string from a given string array. */ + private static String[] removeString(String[] cur, String val) { + if (cur == null) { + return null; + } + final int n = cur.length; + for (int i = 0; i < n; i++) { + if (Objects.equals(cur[i], val)) { + String[] ret = new String[n - 1]; + if (i > 0) { + System.arraycopy(cur, 0, ret, 0, i); + } + if (i < (n - 1)) { + System.arraycopy(cur, i + 1, ret, i, n - i - 1); + } + return ret; + } + } + return cur; + } + + private void createContinue() { + if (!isTaskRoot()) { + finish(); + } + + // Restores the last display mode when launching the app after killing the process. + if (getCurrentDisplayMode().equals(DisplayMode.FOLDED.toString())) { + sCurrentDisplayMode = DisplayMode.FOLDED.toString(); + } + + setTitle(getString(R.string.title_version, Version.getVersionName(this))); + + if (!getWindow().hasFeature(Window.FEATURE_ACTION_BAR)) { + View footer = getLayoutInflater().inflate(R.layout.test_list_footer, null); + + footer.findViewById(R.id.clear).setOnClickListener(this); + footer.findViewById(R.id.export).setOnClickListener(this); + + getListView().addFooterView(footer); + } + + setTestListAdapter( + new ManifestTestListAdapter(/* context= */ this, /* testParent= */ null)); + } + + private AlertDialog sendUserToSettings() { + return new AlertDialog.Builder(this) + .setTitle("Please grant all permissions") + .setPositiveButton( + "Ok", + (dialog, which) -> { + if (which == AlertDialog.BUTTON_POSITIVE) { + startActivity( + new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) + .setData( + Uri.fromParts( + "package", + getPackageName(), + null))); + } + }) + .show(); + } + + /** Notifies the user about the verifier-system plan. */ + private AlertDialog notifyUserSystemPlan(Switch systemSwitch) { + return new AlertDialog.Builder(this) + .setTitle("Verifier System Plan") + .setMessage( + "This is a feature to execute verifier tests for the system layer" + + " partitions. Click \"Yes\" to proceed or \"No\" to run all of the" + + " verifier tests.") + .setPositiveButton( + "Yes", + new DialogInterface.OnClickListener() { + + public void onClick(DialogInterface dialog, int whichButton) { + updateIsSystemEnabled(true); + } + }) + .setNegativeButton( + "No", + new DialogInterface.OnClickListener() { + + public void onClick(DialogInterface dialog, int whichButton) { + systemSwitch.setChecked(false); + } + }) + .show(); + } + + /** Updates the verifier-system plan enabled status and refreshes the test list. */ + private void updateIsSystemEnabled(boolean isChecked) { + Log.i(TAG, "verifier-system plan enabled: " + isChecked); + sIsSystemEnabled = isChecked; + handleSwitchItemSelected(); + } + + /** Sets up the flags after switching display mode and reloads tests on UI. */ + private void handleSwitchItemSelected() { + setCurrentDisplayMode(sCurrentDisplayMode); + mAdapter.loadTestResults(); + } + private void handleClearItemSelected() { new AlertDialog.Builder(this) .setMessage(R.string.test_results_clear_title) - .setPositiveButton(R.string.test_results_clear_yes, + .setPositiveButton( + R.string.test_results_clear_yes, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { mAdapter.clearTestResults(); Toast.makeText( - TestListActivity.this, - R.string.test_results_cleared, - Toast.LENGTH_SHORT) + TestListActivity.this, + R.string.test_results_cleared, + Toast.LENGTH_SHORT) .show(); } }) @@ -236,12 +377,6 @@ public class TestListActivity extends AbstractTestListActivity implements View.O new ReportExporter(this, mAdapter).execute(); } - // Sets up the flags after switching display mode and reloads tests on UI. - private void handleSwitchItemSelected() { - setCurrentDisplayMode(sCurrentDisplayMode); - mAdapter.loadTestResults(); - } - private boolean handleMenuItemSelected(int id) { if (id == R.id.clear) { handleClearItemSelected(); @@ -254,10 +389,21 @@ public class TestListActivity extends AbstractTestListActivity implements View.O return true; } + /** Triggered when a new query is input. */ + private void handleQueryUpdated(String query) { + if (query != null && !query.isEmpty()) { + mAdapter.setTestFilter(query); + } else { + // Reset the filter as null to show all tests. + mAdapter.setTestFilter(/* testFilter= */ null); + } + mAdapter.loadTestResults(); + } + /** * Sets current display mode to sharedpreferences. * - * @param mode A string of current display mode. + * @param mode a string of current display mode */ private void setCurrentDisplayMode(String mode) { SharedPreferences pref = getSharedPreferences(DisplayMode.class.getName(), MODE_PRIVATE); @@ -267,41 +413,12 @@ public class TestListActivity extends AbstractTestListActivity implements View.O /** * Gets current display mode from sharedpreferences. * - * @return A string of current display mode. + * @return a string of current display mode */ private String getCurrentDisplayMode() { - String mode = getSharedPreferences(DisplayMode.class.getName(), MODE_PRIVATE) - .getString(DisplayMode.class.getName(), ""); + String mode = + getSharedPreferences(DisplayMode.class.getName(), MODE_PRIVATE) + .getString(DisplayMode.class.getName(), ""); return mode; } - - private static boolean arrayContains(int[] array, int value) { - if (array == null) return false; - for (int element : array) { - if (element == value) { - return true; - } - } - return false; - } - - private static String[] removeString(String[] cur, String val) { - if (cur == null) { - return null; - } - final int n = cur.length; - for (int i = 0; i < n; i++) { - if (Objects.equals(cur[i], val)) { - String[] ret = new String[n - 1]; - if (i > 0) { - System.arraycopy(cur, 0, ret, 0, i); - } - if (i < (n - 1)) { - System.arraycopy(cur, i + 1, ret, i, n - i - 1); - } - return ret; - } - } - return cur; - } } diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java index de692d7f429..418e957bef9 100644 --- a/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java +++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java @@ -18,7 +18,6 @@ package com.android.cts.verifier; import static com.android.cts.verifier.ReportExporter.LOGS_DIRECTORY; import static com.android.cts.verifier.TestListActivity.sCurrentDisplayMode; -import static com.android.cts.verifier.TestListActivity.sInitialLaunch; import android.content.ContentResolver; import android.content.Context; @@ -50,9 +49,8 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; /** - * {@link BaseAdapter} that handles loading, refreshing, and setting test - * results. What tests are shown can be customized by overriding - * {@link #getRows()}. See {@link ArrayTestListAdapter} and + * {@link BaseAdapter} that handles loading, refreshing, and setting test results. What tests are + * shown can be customized by overriding {@link #getRows()}. See {@link ArrayTestListAdapter} and * {@link ManifestTestListAdapter} for examples. */ public abstract class TestListAdapter extends BaseAdapter { @@ -94,11 +92,15 @@ public abstract class TestListAdapter extends BaseAdapter { private final LayoutInflater mLayoutInflater; - /** Map from display mode to the list of {@link TestListItem}. - * Records the TestListItem from main view only, including unfolded mode and folded mode - * respectively. */ + /** + * Map from display mode to the list of {@link TestListItem}. Records the TestListItem from main + * view only, including unfolded mode and folded mode respectively. + */ protected Map<String, List<TestListItem>> mDisplayModesTests = new HashMap<>(); + /** A keyword to help filter out test cases by the test name. */ + protected String mTestFilter; + /** {@link ListView} row that is either a test category header or a test. */ public static class TestListItem { @@ -131,59 +133,167 @@ public abstract class TestListAdapter extends BaseAdapter { // TODO: refactor to use a Builder approach instead - public static TestListItem newTest(Context context, int titleResId, String testName, - Intent intent, String[] requiredFeatures, String[] excludedFeatures, - String[] applicableFeatures) { - return newTest(context.getString(titleResId), testName, intent, requiredFeatures, - excludedFeatures, applicableFeatures); - } - - public static TestListItem newTest(Context context, int titleResId, String testName, - Intent intent, String[] requiredFeatures, String[] excludedFeatures) { - return newTest(context.getString(titleResId), testName, intent, requiredFeatures, - excludedFeatures, /* applicableFeatures= */ null); - } - - public static TestListItem newTest(Context context, int titleResId, String testName, - Intent intent, String[] requiredFeatures) { - return newTest(context.getString(titleResId), testName, intent, requiredFeatures, - /* excludedFeatures= */ null, /* applicableFeatures= */ null); - } - - public static TestListItem newTest(String title, String testName, Intent intent, - String[] requiredFeatures, String[] requiredConfigs, String[] requiredActions, - String[] excludedFeatures, String[] applicableFeatures, String displayMode) { - return new TestListItem(title, testName, intent, requiredFeatures, requiredConfigs, - requiredActions, excludedFeatures, applicableFeatures, displayMode); - } - - public static TestListItem newTest(String title, String testName, Intent intent, - String[] requiredFeatures, String[] requiredConfigs, String[] excludedFeatures, - String[] applicableFeatures) { - return new TestListItem(title, testName, intent, requiredFeatures, requiredConfigs, - /* requiredActions = */ null, excludedFeatures, applicableFeatures, + /** + * Creates a new test item with given required, excluded and applicable features, the + * context and the resource ID of the title. + */ + public static TestListItem newTest( + Context context, + int titleResId, + String testName, + Intent intent, + String[] requiredFeatures, + String[] excludedFeatures, + String[] applicableFeatures) { + return newTest( + context.getString(titleResId), + testName, + intent, + requiredFeatures, + excludedFeatures, + applicableFeatures); + } + + /** + * Creates a new test item with given required and excluded features, the context and the + * resource ID of the title. + */ + public static TestListItem newTest( + Context context, + int titleResId, + String testName, + Intent intent, + String[] requiredFeatures, + String[] excludedFeatures) { + return newTest( + context.getString(titleResId), + testName, + intent, + requiredFeatures, + excludedFeatures, + /* applicableFeatures= */ null); + } + + /** + * Creates a new test item with given required features, the context and the resource ID of + * the title. + */ + public static TestListItem newTest( + Context context, + int titleResId, + String testName, + Intent intent, + String[] requiredFeatures) { + return newTest( + context.getString(titleResId), + testName, + intent, + requiredFeatures, + /* excludedFeatures= */ null, + /* applicableFeatures= */ null); + } + + /** + * Creates a new test item with given display mode, the required, excluded, applicable + * features and required configurations and actions. + */ + public static TestListItem newTest( + String title, + String testName, + Intent intent, + String[] requiredFeatures, + String[] requiredConfigs, + String[] requiredActions, + String[] excludedFeatures, + String[] applicableFeatures, + String displayMode) { + return new TestListItem( + title, + testName, + intent, + requiredFeatures, + requiredConfigs, + requiredActions, + excludedFeatures, + applicableFeatures, + displayMode); + } + + /** + * Creates a new test item with given required, excluded, applicable features and required + * configurations. + */ + public static TestListItem newTest( + String title, + String testName, + Intent intent, + String[] requiredFeatures, + String[] requiredConfigs, + String[] excludedFeatures, + String[] applicableFeatures) { + return new TestListItem( + title, + testName, + intent, + requiredFeatures, + requiredConfigs, + /* requiredActions= */ null, + excludedFeatures, + applicableFeatures, /* displayMode= */ null); } - public static TestListItem newTest(String title, String testName, Intent intent, - String[] requiredFeatures, String[] excludedFeatures, String[] applicableFeatures) { - return new TestListItem(title, testName, intent, requiredFeatures, - /* requiredConfigs= */ null, /* requiredActions = */ null, excludedFeatures, - applicableFeatures, /* displayMode= */ null); + /** Creates a new test item with given required, excluded and applicable features. */ + public static TestListItem newTest( + String title, + String testName, + Intent intent, + String[] requiredFeatures, + String[] excludedFeatures, + String[] applicableFeatures) { + return new TestListItem( + title, + testName, + intent, + requiredFeatures, + /* requiredConfigs= */ null, + /* requiredActions= */ null, + excludedFeatures, + applicableFeatures, + /* displayMode= */ null); } - public static TestListItem newTest(String title, String testName, Intent intent, - String[] requiredFeatures, String[] excludedFeatures) { - return new TestListItem(title, testName, intent, requiredFeatures, - /* requiredConfigs= */ null, /* requiredActions = */ null, excludedFeatures, - /* applicableFeatures= */ null, /* displayMode= */ null); + /** Creates a new test item with given required and excluded features. */ + public static TestListItem newTest( + String title, + String testName, + Intent intent, + String[] requiredFeatures, + String[] excludedFeatures) { + return new TestListItem( + title, + testName, + intent, + requiredFeatures, + /* requiredConfigs= */ null, + /* requiredActions= */ null, + excludedFeatures, + /* applicableFeatures= */ null, + /* displayMode= */ null); } - public static TestListItem newTest(String title, String testName, Intent intent, - String[] requiredFeatures) { - return new TestListItem(title, testName, intent, requiredFeatures, - /* requiredConfigs= */ null, /* requiredActions = */ null, - /* excludedFeatures= */ null, /* applicableFeatures= */ null, + /** Creates a new test item with given required features. */ + public static TestListItem newTest( + String title, String testName, Intent intent, String[] requiredFeatures) { + return new TestListItem( + title, + testName, + intent, + requiredFeatures, + /* requiredConfigs= */ null, + /* requiredActions= */ null, + /* excludedFeatures= */ null, + /* applicableFeatures= */ null, /* displayMode= */ null); } @@ -192,27 +302,49 @@ public abstract class TestListAdapter extends BaseAdapter { } public static TestListItem newCategory(String title) { - return new TestListItem(title, /* testName= */ null, /* intent= */ null, - /* requiredFeatures= */ null, /* requiredConfigs= */ null, - /* requiredActions = */ null, /* excludedFeatures= */ null, - /* applicableFeatures= */ null, /* displayMode= */ null); + return new TestListItem( + title, + /* testName= */ null, + /* intent= */ null, + /* requiredFeatures= */ null, + /* requiredConfigs= */ null, + /* requiredActions= */ null, + /* excludedFeatures= */ null, + /* applicableFeatures= */ null, + /* displayMode= */ null); } - protected TestListItem(String title, String testName, Intent intent, - String[] requiredFeatures, String[] excludedFeatures, String[] applicableFeatures) { - this(title, testName, intent, requiredFeatures, /* requiredConfigs= */ null, - /* requiredActions = */ null, excludedFeatures, applicableFeatures, + protected TestListItem( + String title, + String testName, + Intent intent, + String[] requiredFeatures, + String[] excludedFeatures, + String[] applicableFeatures) { + this( + title, + testName, + intent, + requiredFeatures, + /* requiredConfigs= */ null, + /* requiredActions= */ null, + excludedFeatures, + applicableFeatures, /* displayMode= */ null); } - protected TestListItem(String title, String testName, Intent intent, - String[] requiredFeatures, String[] requiredConfigs, String[] requiredActions, - String[] excludedFeatures, String[] applicableFeatures, String displayMode) { + protected TestListItem( + String title, + String testName, + Intent intent, + String[] requiredFeatures, + String[] requiredConfigs, + String[] requiredActions, + String[] excludedFeatures, + String[] applicableFeatures, + String displayMode) { this.title = title; - if (!sInitialLaunch) { - testName = setTestNameSuffix(sCurrentDisplayMode, testName); - } - this.testName = testName; + this.testName = setTestNameSuffix(sCurrentDisplayMode, testName); this.intent = intent; this.requiredActions = requiredActions; this.requiredFeatures = requiredFeatures; @@ -234,11 +366,12 @@ public abstract class TestListAdapter extends BaseAdapter { TestResultContentObserver observer = new TestResultContentObserver(); ContentResolver resolver = context.getContentResolver(); - resolver.registerContentObserver(TestResultsProvider.getResultContentUri(context), true, observer); + resolver.registerContentObserver( + TestResultsProvider.getResultContentUri(context), true, observer); } public void loadTestResults() { - new RefreshTestResultsTask(false).execute(); + new RefreshTestResultsTask().execute(); } public void clearTestResults() { @@ -252,33 +385,25 @@ public abstract class TestListAdapter extends BaseAdapter { TestResultHistoryCollection histories = testResult.getHistoryCollection(); histories.merge(null, mHistories.get(name)); - new SetTestResultTask(name, testResult.getResult(), - testResult.getDetails(), testResult.getReportLog(), histories, - mScreenshotsMetadata.get(name)).execute(); + new SetTestResultTask( + name, + testResult.getResult(), + testResult.getDetails(), + testResult.getReportLog(), + histories, + mScreenshotsMetadata.get(name)) + .execute(); } - class RefreshTestResultsTask extends AsyncTask<Void, Void, RefreshResult> { - - private boolean mIsFromMainView; + void setTestFilter(String testFilter) { + mTestFilter = testFilter; + } - RefreshTestResultsTask(boolean isFromMainView) { - mIsFromMainView = isFromMainView; - } + class RefreshTestResultsTask extends AsyncTask<Void, Void, RefreshResult> { @Override protected RefreshResult doInBackground(Void... params) { - List<TestListItem> rows = getRows(); - // When initial launch, needs to fetch tests in the unfolded/folded mode - // to be stored in mDisplayModesTests as the basis for the future switch. - if (sInitialLaunch) { - sInitialLaunch = false; - } - - if (mIsFromMainView) { - rows = mDisplayModesTests.get(sCurrentDisplayMode); - } - - return getRefreshResults(rows); + return getRefreshResults(getRows()); } @Override @@ -346,8 +471,13 @@ public abstract class TestListAdapter extends BaseAdapter { ContentResolver resolver = mContext.getContentResolver(); Cursor cursor = null; try { - cursor = resolver.query(TestResultsProvider.getResultContentUri(mContext), REFRESH_PROJECTION, - null, null, null); + cursor = + resolver.query( + TestResultsProvider.getResultContentUri(mContext), + REFRESH_PROJECTION, + null, + null, + null); if (cursor.moveToFirst()) { do { String testName = cursor.getString(1); @@ -355,7 +485,7 @@ public abstract class TestListAdapter extends BaseAdapter { String testDetails = cursor.getString(3); ReportLog reportLog = (ReportLog) deserialize(cursor.getBlob(4)); TestResultHistoryCollection historyCollection = - (TestResultHistoryCollection) deserialize(cursor.getBlob(5)); + (TestResultHistoryCollection) deserialize(cursor.getBlob(5)); TestScreenshotsMetadata screenshots = (TestScreenshotsMetadata) deserialize(cursor.getBlob(6)); results.put(testName, testResult); @@ -392,9 +522,11 @@ public abstract class TestListAdapter extends BaseAdapter { // Apart from deleting metadata from content resolver database, need to delete // files generated in LOGS_DIRECTORY. For example screenshots. - File resFolder = new File( - Environment.getExternalStorageDirectory().getAbsolutePath() - + File.separator + LOGS_DIRECTORY); + File resFolder = + new File( + Environment.getExternalStorageDirectory().getAbsolutePath() + + File.separator + + LOGS_DIRECTORY); deleteDirectory(resFolder); return null; @@ -433,12 +565,13 @@ public abstract class TestListAdapter extends BaseAdapter { // Loads history from ContentProvider directly if it has not been loaded yet. ContentResolver resolver = mContext.getContentResolver(); - try (Cursor cursor = resolver.query( - TestResultsProvider.getTestNameUri(mContext, mTestName), - new String[] {TestResultsProvider.COLUMN_TEST_RESULT_HISTORY}, - null, - null, - null)) { + try (Cursor cursor = + resolver.query( + TestResultsProvider.getTestNameUri(mContext, mTestName), + new String[] {TestResultsProvider.COLUMN_TEST_RESULT_HISTORY}, + null, + null, + null)) { if (cursor.moveToFirst()) { do { TestResultHistoryCollection historyCollection = @@ -449,7 +582,12 @@ public abstract class TestListAdapter extends BaseAdapter { } } TestResultsProvider.setTestResult( - mContext, mTestName, mResult, mDetails, mReportLog, mHistoryCollection, + mContext, + mTestName, + mResult, + mDetails, + mReportLog, + mHistoryCollection, mScreenshotsMetadata); return null; } @@ -507,6 +645,16 @@ public abstract class TestListAdapter extends BaseAdapter { return position; } + /** Gets {@link TestListItem} with the given test name. */ + public TestListItem getItemByName(String testName) { + for (TestListItem item : mRows) { + if (item != null && item.testName != null && item.testName.equals(testName)) { + return item; + } + } + return null; + } + public int getTestResult(int position) { TestListItem item = getItem(position); return mTestResults.containsKey(item.testName) @@ -516,23 +664,20 @@ public abstract class TestListAdapter extends BaseAdapter { public String getTestDetails(int position) { TestListItem item = getItem(position); - return mTestDetails.containsKey(item.testName) - ? mTestDetails.get(item.testName) - : null; + return mTestDetails.containsKey(item.testName) ? mTestDetails.get(item.testName) : null; } public ReportLog getReportLog(int position) { TestListItem item = getItem(position); - return mReportLogs.containsKey(item.testName) - ? mReportLogs.get(item.testName) - : null; + return mReportLogs.containsKey(item.testName) ? mReportLogs.get(item.testName) : null; } /** - * Get test result histories. + * Gets test result histories. * - * @param position The position of test. - * @return A {@link TestResultHistoryCollection} object containing test result histories of tests. + * @param position the position of test + * @return a {@link TestResultHistoryCollection} object containing test result histories of + * tests */ public TestResultHistoryCollection getHistoryCollection(int position) { TestListItem item = getItem(position); @@ -543,10 +688,10 @@ public abstract class TestListAdapter extends BaseAdapter { } /** - * Get test screenshots metadata + * Gets test screenshots metadata. * - * @param position The position of test - * @return A {@link TestScreenshotsMetadata} object containing test screenshots metadata. + * @param position the position of test + * @return a {@link TestScreenshotsMetadata} object containing test screenshots metadata */ public TestScreenshotsMetadata getScreenshotsMetadata(String mode, int position) { TestListItem item = getItem(mode, position); @@ -556,86 +701,81 @@ public abstract class TestListAdapter extends BaseAdapter { } /** - * Get test item by the given display mode and position. + * Gets test item by the given display mode and position. * - * @param mode The display mode. - * @param position The position of test. - * @return A {@link TestListItem} object containing the test item. + * @param mode the display mode + * @param position the position of test + * @return a {@link TestListItem} object containing the test item */ public TestListItem getItem(String mode, int position) { return mDisplayModesTests.get(mode).get(position); } /** - * Get test item count by the given display mode. + * Gets test item count by the given display mode. * - * @param mode The display mode. - * @return A count of test items. + * @param mode the display mode + * @return a count of test items */ - public int getCount(String mode){ + public int getCount(String mode) { return mDisplayModesTests.getOrDefault(mode, new ArrayList<>()).size(); } /** - * Get test result by the given display mode and position. + * Gets test result by the given display mode and position. * - * @param mode The display mode. - * @param position The position of test. - * @return The test item result. + * @param mode the display mode + * @param position the position of test + * @return the test item result */ public int getTestResult(String mode, int position) { TestListItem item = mDisplayModesTests.get(mode).get(position); return mTestResults.containsKey(item.testName) - ? mTestResults.get(item.testName) - : TestResult.TEST_RESULT_NOT_EXECUTED; + ? mTestResults.get(item.testName) + : TestResult.TEST_RESULT_NOT_EXECUTED; } /** - * Get test details by the given display mode and position. + * Gets test details by the given display mode and position. * - * @param mode The display mode. - * @param position The position of test. - * @return A string containing the test details. + * @param mode the display mode + * @param position the position of test + * @return a string containing the test details */ public String getTestDetails(String mode, int position) { TestListItem item = mDisplayModesTests.get(mode).get(position); - return mTestDetails.containsKey(item.testName) - ? mTestDetails.get(item.testName) - : null; + return mTestDetails.containsKey(item.testName) ? mTestDetails.get(item.testName) : null; } /** - * Get test report log by the given display mode and position. + * Gets test report log by the given display mode and position. * - * @param mode The display mode. - * @param position The position of test. - * @return A {@link ReportLog} object containing the test report log of the test item. + * @param mode the display mode + * @param position the position of test + * @return a {@link ReportLog} object containing the test report log of the test item */ public ReportLog getReportLog(String mode, int position) { TestListItem item = mDisplayModesTests.get(mode).get(position); - return mReportLogs.containsKey(item.testName) - ? mReportLogs.get(item.testName) - : null; + return mReportLogs.containsKey(item.testName) ? mReportLogs.get(item.testName) : null; } /** - * Get test result histories by the given display mode and position. + * Gets test result histories by the given display mode and position. * - * @param mode The display mode. - * @param position The position of test. - * @return A {@link TestResultHistoryCollection} object containing the test result histories of - * the test item. + * @param mode the display mode + * @param position the position of test + * @return a {@link TestResultHistoryCollection} object containing the test result histories of + * the test item */ public TestResultHistoryCollection getHistoryCollection(String mode, int position) { TestListItem item = mDisplayModesTests.get(mode).get(position); - return mHistories.containsKey(item.testName) - ? mHistories.get(item.testName) - : null; + return mHistories.containsKey(item.testName) ? mHistories.get(item.testName) : null; } public boolean allTestsPassed() { for (TestListItem item : mRows) { - if (item != null && item.isTest() + if (item != null + && item.isTest() && (!mTestResults.containsKey(item.testName) || (mTestResults.get(item.testName) != TestResult.TEST_RESULT_PASSED))) { @@ -700,7 +840,6 @@ public abstract class TestListAdapter extends BaseAdapter { return android.R.layout.simple_list_item_1; default: throw new IllegalArgumentException("Illegal view type: " + viewType); - } } @@ -735,12 +874,13 @@ public abstract class TestListAdapter extends BaseAdapter { * * @param mode A string of current display mode. * @param name A string of test name. - * @return A string of test name with suffix, [folded], in the folded mode. - * A string of input test name in the unfolded mode. + * @return A string of test name with suffix, [folded], in the folded mode. A string of input + * test name in the unfolded mode. */ public static String setTestNameSuffix(String mode, String name) { - if (name != null && mode.equals(DisplayMode.FOLDED.toString()) - && !name.endsWith(DisplayMode.FOLDED.asSuffix())){ + if (name != null + && mode.equals(DisplayMode.FOLDED.toString()) + && !name.endsWith(DisplayMode.FOLDED.asSuffix())) { return name + DisplayMode.FOLDED.asSuffix(); } return name; |