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 static com.android.cts.verifier.TestListActivity.sCurrentDisplayMode; 20 21 import android.annotation.SuppressLint; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.content.pm.ActivityInfo; 26 import android.content.pm.PackageManager; 27 import android.content.pm.ResolveInfo; 28 import android.content.res.Resources; 29 import android.hardware.SensorPrivacyManager; 30 import android.os.BatteryManager; 31 import android.os.Bundle; 32 import android.os.UserManager; 33 import android.util.Log; 34 import android.widget.ListView; 35 36 import com.android.cts.verifier.TestListActivity.DisplayMode; 37 import com.android.modules.utils.build.SdkLevel; 38 39 import java.lang.reflect.InvocationTargetException; 40 import java.lang.reflect.Method; 41 import java.util.ArrayList; 42 import java.util.Arrays; 43 import java.util.Collections; 44 import java.util.Comparator; 45 import java.util.HashMap; 46 import java.util.HashSet; 47 import java.util.List; 48 import java.util.Locale; 49 import java.util.Map; 50 import java.util.stream.Collectors; 51 52 /** 53 * {@link TestListAdapter} that populates the {@link TestListActivity}'s {@link ListView} by reading 54 * data from the CTS Verifier's AndroidManifest.xml. 55 * 56 * <p>Making a new test activity to appear in the list requires the following steps: 57 * 58 * <ol> 59 * <li>REQUIRED: Add an activity to the AndroidManifest.xml with an intent filter with a main 60 * action and the MANUAL_TEST category. 61 * <pre> 62 * <intent-filter> 63 * <action android:name="android.intent.action.MAIN" /> 64 * <category android:name="android.cts.intent.category.MANUAL_TEST" /> 65 * </intent-filter> 66 * </pre> 67 * <li>REQUIRED: Add a meta data attribute to indicate which display modes of tests the activity 68 * should belong to. "single_display_mode" indicates a test is only needed to run on the main 69 * display mode (i.e. unfolded), and "multi_display_mode" indicates a test is required to run 70 * under both modes (i.e. both folded and unfolded).If you don't add this attribute, your test 71 * will show up in both unfolded and folded modes. 72 * <pre> 73 * <meta-data android:name="display_mode" android:value="multi_display_mode" /> 74 * </pre> 75 * <li>OPTIONAL: Add a meta data attribute to indicate what category of tests the activity should 76 * belong to. If you don't add this attribute, your test will show up in the "Other" tests 77 * category. 78 * <pre> 79 * <meta-data android:name="test_category" android:value="@string/test_category_security" /> 80 * </pre> 81 * <li>OPTIONAL: Add a meta data attribute to indicate whether this test has a parent test. 82 * <pre> 83 * <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" /> 84 * </pre> 85 * <li>OPTIONAL: Add a meta data attribute to indicate what features are required to run the test. 86 * If the device does not have all of the required features then it will not appear in the 87 * test list. Use a colon (:) to specify multiple required features. 88 * <pre> 89 * <meta-data android:name="test_required_features" android:value="android.hardware.sensor.accelerometer" /> 90 * </pre> 91 * <li>OPTIONAL: Add a meta data attribute to indicate features such that, if any present, the 92 * test gets excluded from being shown. If the device has any of the excluded features then 93 * the test will not appear in the test list. Use a colon (:) to specify multiple features to 94 * exclude for the test. Note that the colon means "or" in this case. 95 * <pre> 96 * <meta-data android:name="test_excluded_features" android:value="android.hardware.type.television" /> 97 * </pre> 98 * <li>OPTIONAL: Add a meta data attribute to indicate features such that, if any present, the 99 * test is applicable to run. If the device has any of the applicable features then the test 100 * will appear in the test list. Use a colon (:) to specify multiple features 101 * <pre> 102 * <meta-data android:name="test_applicable_features" android:value="android.hardware.sensor.compass" /> 103 * </pre> 104 * <li>OPTIONAL: Add a meta data attribute to indicate which intent actions are required to run 105 * the test. If the device does not have activities that handle all those actions, then it 106 * will not appear in the test list. Use a colon (:) to specify multiple required intent 107 * actions. 108 * <pre> 109 * <meta-data android:name="test_required_actions" android:value="android.app.action.ADD_DEVICE_ADMIN" /> 110 * </pre> 111 * <li>OPTIONAL: Add a meta data attribute to indicate which intent actions should not run when 112 * the user running the test is of the given "type" (notice that the type here is not 113 * necessarily the same as {@link UserManager#getUserType()}). Use a colon (:) to specify 114 * multiple user types. 115 * <pre> 116 * <meta-data android:name="test_excluded_user_types" android:value="visible_background_non-profile_user" /> 117 * </pre> 118 * </ol> 119 */ 120 public class ManifestTestListAdapter extends TestListAdapter { 121 private static final String LOG_TAG = "ManifestTestListAdapter"; 122 123 private static final String TEST_CATEGORY_META_DATA = "test_category"; 124 125 private static final String TEST_PARENT_META_DATA = "test_parent"; 126 127 private static final String TEST_REQUIRED_FEATURES_META_DATA = "test_required_features"; 128 129 private static final String TEST_EXCLUDED_FEATURES_META_DATA = "test_excluded_features"; 130 131 private static final String TEST_APPLICABLE_FEATURES_META_DATA = "test_applicable_features"; 132 133 private static final String TEST_REQUIRED_CONFIG_META_DATA = "test_required_configs"; 134 135 private static final String TEST_REQUIRED_ACTIONS_META_DATA = "test_required_actions"; 136 137 private static final String TEST_EXCLUDED_USER_TYPES_META_DATA = "test_excluded_user_types"; 138 139 private static final String TEST_DISPLAY_MODE_META_DATA = "display_mode"; 140 141 private static final String TEST_PASS_MODE = "test_pass_mode"; 142 143 private static final String CONFIG_BATTERY_SUPPORTED = "config_battery_supported"; 144 145 private static final String CONFIG_NO_EMULATOR = "config_no_emulator"; 146 147 private static final String CONFIG_HAS_RECENTS = "config_has_recents"; 148 149 private static final String CONFIG_HDMI_SOURCE = "config_hdmi_source"; 150 151 private static final String CONFIG_QUICK_SETTINGS_SUPPORTED = "config_quick_settings_supported"; 152 153 private static final String CONFIG_HAS_MIC_TOGGLE = "config_has_mic_toggle"; 154 155 private static final String CONFIG_HAS_CAMERA_TOGGLE = "config_has_camera_toggle"; 156 157 private static final String CONFIG_CHANGEABLE_VOLUME = "config_changeable_volume"; 158 159 private static final String CONFIG_SUPPORTS_BUBBLE = "config_supports_bubble"; 160 161 /** 162 * The config to represent that a test is only needed to run in the main display mode (i.e. 163 * unfolded). 164 */ 165 private static final String SINGLE_DISPLAY_MODE = "single_display_mode"; 166 167 /** 168 * The config to represent that a test is needed to run in the multiple display modes (i.e. both 169 * unfolded and folded). 170 */ 171 private static final String MULTIPLE_DISPLAY_MODE = "multi_display_mode"; 172 173 /** The config to represent that a test is only needed to run in the folded display mode. */ 174 private static final String FOLDED_DISPLAY_MODE = "folded_display_mode"; 175 176 /** 177 * The config to represent that a test is marked as pass when it passes either in folded mode or 178 * in unfolded mode. 179 */ 180 private static final String EITHER_MODE = "either_mode"; 181 182 /** 183 * The user is not a {@link UserManager#isProfile() profile} and is running in the background, 184 * but {@link UserManager#isUserVisible() visible} in a display. 185 */ 186 private static final String USER_TYPE_VISIBLE_BG_USER = "visible_background_non-profile_user"; 187 188 /** The name of the camera ITS test of a {@link TestListItem}. */ 189 private static final String CAMERA_ITS_TEST = 190 "com.android.cts.verifier.camera.its.ItsTestActivity"; 191 192 /** The name of the camera ITS test (folded mode) of a {@link TestListItem}. */ 193 private static final String CAMERA_ITS_TEST_FOLDED = CAMERA_ITS_TEST + "[folded]"; 194 195 private final HashSet<String> mDisabledTests; 196 197 private Context mContext; 198 199 private String mTestParent; 200 ManifestTestListAdapter(Context context, String testParent)201 public ManifestTestListAdapter(Context context, String testParent) { 202 this(context, testParent, context.getResources().getStringArray(R.array.disabled_tests)); 203 } 204 ManifestTestListAdapter(Context context, String testParent, String[] disabledTestArray)205 public ManifestTestListAdapter(Context context, String testParent, String[] disabledTestArray) { 206 super(context); 207 mContext = context; 208 mTestParent = testParent; 209 mDisabledTests = new HashSet<>(disabledTestArray.length); 210 for (int i = 0; i < disabledTestArray.length; i++) { 211 mDisabledTests.add(disabledTestArray[i]); 212 } 213 } 214 215 @Override getRows()216 protected List<TestListItem> getRows() { 217 // When launching at the first time or after killing the process, needs to fetch the 218 // test items of all display modes as the bases for switching. 219 if (mDisplayModesTests.isEmpty()) { 220 for (DisplayMode mode : DisplayMode.values()) { 221 mDisplayModesTests.put(mode.toString(), getRowsWithDisplayMode(mode.toString())); 222 PackageManager packageManager = mContext.getPackageManager(); 223 boolean isCustomLauncher = 224 packageManager.hasSystemFeature("com.google.android.tv.custom_launcher"); 225 if (isCustomLauncher) { 226 mDisabledTests.add( 227 "com.android.cts.verifier.net.ConnectivityBackgroundTestActivity"); 228 } 229 } 230 } 231 232 if (mTestFilter != null || TestListActivity.getIsSystemEnabled()) { 233 // Filter test rows dynamically when the filter is specified or verifier-system plan is 234 // enabled. 235 return getRowsWithDisplayMode(sCurrentDisplayMode.toString()); 236 } else { 237 return mDisplayModesTests.getOrDefault( 238 sCurrentDisplayMode.toString(), new ArrayList<>()); 239 } 240 } 241 242 /** 243 * Gets all rows based on the specific display mode. 244 * 245 * @param mode the given display mode 246 * @return a list containing all test itmes in the given display mode 247 */ getRowsWithDisplayMode(String mode)248 private List<TestListItem> getRowsWithDisplayMode(String mode) { 249 /* 250 * 1. Get all the tests belonging to the test parent. 251 * 2. Get all the tests keyed by their category. 252 * 3. Flatten the tests and categories into one giant list for the list view. 253 */ 254 List<TestListItem> allRows = new ArrayList<TestListItem>(); 255 List<ResolveInfo> infos = getResolveInfosForParent(); 256 Map<String, List<TestListItem>> testsByCategory = getTestsByCategory(infos); 257 258 List<String> testCategories = new ArrayList<String>(testsByCategory.keySet()); 259 Collections.sort(testCategories); 260 for (String testCategory : testCategories) { 261 List<TestListItem> tests = filterTests(testsByCategory.get(testCategory), mode); 262 if (!tests.isEmpty()) { 263 allRows.add(TestListItem.newCategory(testCategory)); 264 Collections.sort(tests, Comparator.comparing(item -> item.title)); 265 allRows.addAll(tests); 266 } 267 } 268 return allRows; 269 } 270 getResolveInfosForParent()271 List<ResolveInfo> getResolveInfosForParent() { 272 Intent mainIntent = new Intent(Intent.ACTION_MAIN); 273 mainIntent.addCategory(CATEGORY_MANUAL_TEST); 274 mainIntent.setPackage(mContext.getPackageName()); 275 276 PackageManager packageManager = mContext.getPackageManager(); 277 List<ResolveInfo> list = 278 packageManager.queryIntentActivities( 279 mainIntent, PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA); 280 int size = list.size(); 281 282 List<ResolveInfo> matchingList = new ArrayList<>(); 283 for (int i = 0; i < size; i++) { 284 ResolveInfo info = list.get(i); 285 String parent = getTestParent(info.activityInfo.metaData); 286 if ((mTestParent == null && parent == null) 287 || (mTestParent != null && mTestParent.equals(parent))) { 288 matchingList.add(info); 289 } 290 } 291 return matchingList; 292 } 293 getTestsByCategory(List<ResolveInfo> list)294 Map<String, List<TestListItem>> getTestsByCategory(List<ResolveInfo> list) { 295 Map<String, List<TestListItem>> testsByCategory = new HashMap<>(); 296 297 int size = list.size(); 298 for (int i = 0; i < size; i++) { 299 ResolveInfo info = list.get(i); 300 if (info.activityInfo == null || mDisabledTests.contains(info.activityInfo.name)) { 301 Log.w(LOG_TAG, "ignoring disabled test: " + info.activityInfo.name); 302 continue; 303 } 304 String title = getTitle(mContext, info.activityInfo); 305 String testName = info.activityInfo.name; 306 Intent intent = getActivityIntent(info.activityInfo); 307 String[] requiredFeatures = getRequiredFeatures(info.activityInfo.metaData); 308 String[] requiredConfigs = getRequiredConfigs(info.activityInfo.metaData); 309 String[] requiredActions = getRequiredActions(info.activityInfo.metaData); 310 String[] excludedFeatures = getExcludedFeatures(info.activityInfo.metaData); 311 String[] excludedUserTypes = getExcludedUserTypes(info.activityInfo.metaData); 312 String[] applicableFeatures = getApplicableFeatures(info.activityInfo.metaData); 313 String displayMode = getDisplayMode(info.activityInfo.metaData); 314 boolean passInEitherMode = getTestPassMode(info.activityInfo.metaData, displayMode); 315 316 TestListItem item = 317 TestListItem.newTest( 318 title, 319 testName, 320 intent, 321 requiredFeatures, 322 requiredConfigs, 323 requiredActions, 324 excludedFeatures, 325 applicableFeatures, 326 excludedUserTypes, 327 displayMode, 328 passInEitherMode); 329 330 String testCategory = getTestCategory(mContext, info.activityInfo.metaData); 331 addTestToCategory(testsByCategory, testCategory, item); 332 } 333 334 return testsByCategory; 335 } 336 getTestCategory(Context context, Bundle metaData)337 static String getTestCategory(Context context, Bundle metaData) { 338 String testCategory = null; 339 if (metaData != null) { 340 testCategory = metaData.getString(TEST_CATEGORY_META_DATA); 341 } 342 if (testCategory != null) { 343 return testCategory; 344 } else { 345 return context.getString(R.string.test_category_other); 346 } 347 } 348 getTestParent(Bundle metaData)349 static String getTestParent(Bundle metaData) { 350 return metaData != null ? metaData.getString(TEST_PARENT_META_DATA) : null; 351 } 352 getRequiredFeatures(Bundle metaData)353 static String[] getRequiredFeatures(Bundle metaData) { 354 return getMetadataAttributes(metaData, TEST_REQUIRED_FEATURES_META_DATA); 355 } 356 getRequiredActions(Bundle metaData)357 static String[] getRequiredActions(Bundle metaData) { 358 return getMetadataAttributes(metaData, TEST_REQUIRED_ACTIONS_META_DATA); 359 } 360 getRequiredConfigs(Bundle metaData)361 static String[] getRequiredConfigs(Bundle metaData) { 362 return getMetadataAttributes(metaData, TEST_REQUIRED_CONFIG_META_DATA); 363 } 364 getExcludedFeatures(Bundle metaData)365 static String[] getExcludedFeatures(Bundle metaData) { 366 return getMetadataAttributes(metaData, TEST_EXCLUDED_FEATURES_META_DATA); 367 } 368 getApplicableFeatures(Bundle metaData)369 static String[] getApplicableFeatures(Bundle metaData) { 370 return getMetadataAttributes(metaData, TEST_APPLICABLE_FEATURES_META_DATA); 371 } 372 getExcludedUserTypes(Bundle metaData)373 static String[] getExcludedUserTypes(Bundle metaData) { 374 return getMetadataAttributes(metaData, TEST_EXCLUDED_USER_TYPES_META_DATA); 375 } 376 getMetadataAttributes(Bundle metaData, String attribute)377 private static String[] getMetadataAttributes(Bundle metaData, String attribute) { 378 if (metaData == null) { 379 return null; 380 } else { 381 String value = metaData.getString(attribute); 382 if (value == null) { 383 return null; 384 } else { 385 return value.split(":"); 386 } 387 } 388 } 389 390 /** 391 * Gets the configuration of the display mode per test. The default value is multi_display_mode. 392 * 393 * @param metaData the given metadata of the display mode 394 * @return a string representing the display mode of the test 395 */ getDisplayMode(Bundle metaData)396 static String getDisplayMode(Bundle metaData) { 397 if (metaData == null) { 398 return MULTIPLE_DISPLAY_MODE; 399 } 400 String displayMode = metaData.getString(TEST_DISPLAY_MODE_META_DATA); 401 return displayMode == null ? MULTIPLE_DISPLAY_MODE : displayMode; 402 } 403 404 /** 405 * Gets the configuration of the test pass mode per test. 406 * 407 * @param metaData the given metadata of the test pass mode 408 * @return a boolean representing whether the test can be marked as pass when it passes either 409 * in the folded mode or in the unfolded mode 410 */ getTestPassMode(Bundle metaData, String displayMode)411 static boolean getTestPassMode(Bundle metaData, String displayMode) { 412 if (metaData == null || !displayMode.equals(MULTIPLE_DISPLAY_MODE)) { 413 return false; 414 } 415 String testPassMode = metaData.getString(TEST_PASS_MODE); 416 return testPassMode != null && testPassMode.equals(EITHER_MODE); 417 } 418 getTitle(Context context, ActivityInfo activityInfo)419 static String getTitle(Context context, ActivityInfo activityInfo) { 420 if (activityInfo.labelRes != 0) { 421 return context.getString(activityInfo.labelRes); 422 } else { 423 return activityInfo.name; 424 } 425 } 426 getActivityIntent(ActivityInfo activityInfo)427 static Intent getActivityIntent(ActivityInfo activityInfo) { 428 Intent intent = new Intent(); 429 intent.setClassName(activityInfo.packageName, activityInfo.name); 430 return intent; 431 } 432 addTestToCategory( Map<String, List<TestListItem>> testsByCategory, String testCategory, TestListItem item)433 static void addTestToCategory( 434 Map<String, List<TestListItem>> testsByCategory, 435 String testCategory, 436 TestListItem item) { 437 List<TestListItem> tests; 438 if (testsByCategory.containsKey(testCategory)) { 439 tests = testsByCategory.get(testCategory); 440 } else { 441 tests = new ArrayList<TestListItem>(); 442 } 443 testsByCategory.put(testCategory, tests); 444 tests.add(item); 445 } 446 hasAnyFeature(String[] features)447 private boolean hasAnyFeature(String[] features) { 448 if (features != null) { 449 PackageManager packageManager = mContext.getPackageManager(); 450 for (String feature : features) { 451 if (packageManager.hasSystemFeature(feature)) { 452 return true; 453 } 454 } 455 Log.v(LOG_TAG, "Missing features " + Arrays.toString(features)); 456 } 457 return false; 458 } 459 hasAllFeatures(String[] features)460 private boolean hasAllFeatures(String[] features) { 461 if (features != null) { 462 PackageManager packageManager = mContext.getPackageManager(); 463 for (String feature : features) { 464 if (!packageManager.hasSystemFeature(feature)) { 465 Log.v(LOG_TAG, "Missing feature " + feature); 466 return false; 467 } 468 } 469 } 470 return true; 471 } 472 hasAllActions(String[] actions)473 private boolean hasAllActions(String[] actions) { 474 if (actions != null) { 475 PackageManager packageManager = mContext.getPackageManager(); 476 for (String action : actions) { 477 Intent intent = new Intent(action); 478 if (packageManager.queryIntentActivities(intent, /* flags= */ 0).isEmpty()) { 479 Log.v(LOG_TAG, "Missing action " + action); 480 return false; 481 } 482 } 483 } 484 return true; 485 } 486 matchAllConfigs(Context context, String[] configs)487 public static boolean matchAllConfigs(Context context, String[] configs) { 488 if (configs != null) { 489 for (String config : configs) { 490 switch (config) { 491 case CONFIG_NO_EMULATOR: 492 try { 493 Method getStringMethod = 494 ClassLoader.getSystemClassLoader() 495 .loadClass("android.os.SystemProperties") 496 .getMethod("get", String.class); 497 String emulatorKernel = 498 (String) getStringMethod.invoke("0", "ro.boot.qemu"); 499 if (emulatorKernel.equals("1")) { 500 return false; 501 } 502 } catch (Exception e) { 503 Log.e(LOG_TAG, "Exception while checking for emulator support.", e); 504 } 505 break; 506 case CONFIG_HAS_RECENTS: 507 if (!getSystemResourceFlag(context, "config_hasRecents")) { 508 return false; 509 } 510 break; 511 case CONFIG_HDMI_SOURCE: 512 final int DEVICE_TYPE_HDMI_SOURCE = 4; 513 try { 514 if (!getHdmiDeviceType().contains(DEVICE_TYPE_HDMI_SOURCE)) { 515 return false; 516 } 517 } catch (Exception exception) { 518 Log.e( 519 LOG_TAG, 520 "Exception while looking up HDMI device type.", 521 exception); 522 } 523 break; 524 case CONFIG_BATTERY_SUPPORTED: 525 if (!hasBattery(context)) { 526 return false; 527 } 528 break; 529 case CONFIG_QUICK_SETTINGS_SUPPORTED: 530 if (!getSystemResourceFlag(context, "config_quickSettingsSupported")) { 531 return false; 532 } 533 break; 534 case CONFIG_HAS_MIC_TOGGLE: 535 return isHardwareToggleSupported( 536 context, SensorPrivacyManager.Sensors.MICROPHONE); 537 case CONFIG_HAS_CAMERA_TOGGLE: 538 return isHardwareToggleSupported( 539 context, SensorPrivacyManager.Sensors.CAMERA); 540 case CONFIG_CHANGEABLE_VOLUME: 541 return !getSystemResourceFlag(context, "config_useFixedVolume"); 542 case CONFIG_SUPPORTS_BUBBLE: 543 return getSystemResourceFlag(context, "config_supportsBubble"); 544 default: 545 break; 546 } 547 } 548 } 549 return true; 550 } 551 552 /** 553 * Checks if the test should be ran by the given display mode. 554 * 555 * @param mode the display mode config of the test 556 * @param currentMode the given display mode 557 * @return true if the given display mode matches the configs, otherwise, return false 558 */ matchDisplayMode(String mode, String currentMode)559 private boolean matchDisplayMode(String mode, String currentMode) { 560 if (mode == null) { 561 return false; 562 } 563 switch (mode) { 564 case SINGLE_DISPLAY_MODE: 565 return currentMode.equals(DisplayMode.UNFOLDED.toString()); 566 case MULTIPLE_DISPLAY_MODE: 567 return true; 568 case FOLDED_DISPLAY_MODE: 569 return currentMode.equals(DisplayMode.FOLDED.toString()); 570 default: 571 return false; 572 } 573 } 574 575 /** Checks whether the test is being run by a user type that doesn't support it. */ matchAnyExcludedUserType(String[] userTypes)576 private boolean matchAnyExcludedUserType(String[] userTypes) { 577 if (userTypes == null) { 578 return false; 579 } 580 581 for (String userType : userTypes) { 582 switch (userType) { 583 case USER_TYPE_VISIBLE_BG_USER: 584 if (isVisibleBackgroundNonProfileUser()) { 585 Log.d(LOG_TAG, "Match for " + USER_TYPE_VISIBLE_BG_USER); 586 return true; 587 } 588 return false; 589 default: 590 throw new IllegalArgumentException( 591 "Invalid " 592 + TEST_EXCLUDED_USER_TYPES_META_DATA 593 + " value: " 594 + userType); 595 } 596 } 597 598 return false; 599 } 600 601 /** Checks whether the title of the test matches the test filter. */ macthTestFilter(String testTitle)602 private boolean macthTestFilter(String testTitle) { 603 if (mTestFilter == null) { 604 return true; 605 } 606 return testTitle != null 607 && testTitle 608 .toLowerCase(Locale.getDefault()) 609 .contains(mTestFilter.toLowerCase(Locale.getDefault())); 610 } 611 612 /** 613 * Checks whether the test matches the current status of verifier-system plan. 614 * 615 * <p>When verifier-system plan is disabled, all CTS-V tests are shown. 616 * 617 * <p>When verifier-system plan is enabled, specific tests are filtered out, e.g., camera ITS. 618 */ matchSystemPlanStatus(String testName)619 private static boolean matchSystemPlanStatus(String testName) { 620 if (testName == null || !TestListActivity.getIsSystemEnabled()) { 621 return true; 622 } 623 return !testName.equals(CAMERA_ITS_TEST) && !testName.equals(CAMERA_ITS_TEST_FOLDED); 624 } 625 isVisibleBackgroundNonProfileUser()626 private boolean isVisibleBackgroundNonProfileUser() { 627 if (!SdkLevel.isAtLeastU()) { 628 Log.d(LOG_TAG, "isVisibleBagroundNonProfileUser() returning false on pre-UDC device"); 629 return false; 630 } 631 UserManager userMgr = mContext.getSystemService(UserManager.class); 632 return userMgr.isUserVisible() && !userMgr.isUserForeground() && !userMgr.isProfile(); 633 } 634 getSystemResourceFlag(Context context, String key)635 private static boolean getSystemResourceFlag(Context context, String key) { 636 final Resources systemRes = context.getResources().getSystem(); 637 final int id = systemRes.getIdentifier(key, "bool", "android"); 638 if (id == Resources.ID_NULL) { 639 // The flag being queried should exist in 640 // frameworks/base/core/res/res/values/config.xml. 641 throw new RuntimeException("System resource flag " + key + " not found"); 642 } 643 return systemRes.getBoolean(id); 644 } 645 getHdmiDeviceType()646 private static List<Integer> getHdmiDeviceType() 647 throws InvocationTargetException, 648 IllegalAccessException, 649 ClassNotFoundException, 650 NoSuchMethodException { 651 Method getStringMethod = 652 ClassLoader.getSystemClassLoader() 653 .loadClass("android.os.SystemProperties") 654 .getMethod("get", String.class); 655 String deviceTypesStr = (String) getStringMethod.invoke(null, "ro.hdmi.device_type"); 656 if (deviceTypesStr.equals("")) { 657 return new ArrayList<>(); 658 } 659 return Arrays.stream(deviceTypesStr.split(",")) 660 .map(Integer::parseInt) 661 .collect(Collectors.toList()); 662 } 663 hasBattery(Context context)664 private static boolean hasBattery(Context context) { 665 final Intent batteryInfo = 666 context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); 667 return batteryInfo.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true); 668 } 669 filterTests(List<TestListItem> tests, String mode)670 List<TestListItem> filterTests(List<TestListItem> tests, String mode) { 671 List<TestListItem> filteredTests = new ArrayList<>(); 672 for (TestListItem test : tests) { 673 if (!hasAnyFeature(test.excludedFeatures) 674 && hasAllFeatures(test.requiredFeatures) 675 && hasAllActions(test.requiredActions) 676 && matchAllConfigs(mContext, test.requiredConfigs) 677 && matchDisplayMode(test.displayMode, mode) 678 && !matchAnyExcludedUserType(test.excludedUserTypes) 679 && macthTestFilter(test.title) 680 && matchSystemPlanStatus(test.testName)) { 681 if (test.applicableFeatures == null || hasAnyFeature(test.applicableFeatures)) { 682 // Add suffix in test name if the test is in the folded mode. 683 test.testName = setTestNameSuffix(mode, test.testName); 684 // Remove suffix in test name if the test is in the unfolded mode. 685 test.testName = removeTestNameSuffix(mode, test.testName); 686 filteredTests.add(test); 687 } else { 688 Log.d(LOG_TAG, "Skipping " + test.testName + " due to metadata filtering"); 689 } 690 } else { 691 Log.d(LOG_TAG, "Skipping " + test.testName + " due to metadata filtering"); 692 } 693 } 694 return filteredTests; 695 } 696 697 @SuppressLint("NewApi") isHardwareToggleSupported(Context context, final int sensorType)698 private static boolean isHardwareToggleSupported(Context context, final int sensorType) { 699 boolean isToggleSupported = false; 700 SensorPrivacyManager sensorPrivacyManager = 701 context.getSystemService(SensorPrivacyManager.class); 702 if (sensorPrivacyManager != null) { 703 isToggleSupported = 704 sensorPrivacyManager.supportsSensorToggle( 705 SensorPrivacyManager.TOGGLE_TYPE_HARDWARE, sensorType); 706 } 707 return isToggleSupported; 708 } 709 } 710