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