1 /* 2 * Copyright (C) 2015 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 package com.android.compatibility.common.deviceinfo; 17 18 import android.content.pm.FeatureInfo; 19 import android.content.pm.PackageManager; 20 import android.os.Build; 21 22 import com.android.compatibility.common.util.DeviceInfoStore; 23 24 import java.lang.reflect.Field; 25 import java.lang.reflect.InvocationTargetException; 26 import java.lang.reflect.Method; 27 import java.util.ArrayList; 28 import java.util.HashSet; 29 import java.util.List; 30 import java.util.Set; 31 32 /** 33 * Feature device info collector. 34 */ 35 public final class FeatureDeviceInfo extends DeviceInfo { 36 37 @Override 38 protected void collectDeviceInfo(DeviceInfoStore store) throws Exception { 39 PackageManager packageManager = 40 getInstrumentation().getContext().getPackageManager(); 41 store.startArray("feature"); 42 43 List<String> sdkFeatures = getPackageManagerFeatures(); 44 45 FeatureInfo[] featureInfos = packageManager.getSystemAvailableFeatures(); 46 if (featureInfos != null) { 47 for (FeatureInfo featureInfo : featureInfos) { 48 if (featureInfo.name != null) { 49 // Check if this feature is a "sdk" feature. 50 String type = "other"; 51 if (sdkFeatures.contains(featureInfo.name)) { 52 type = "sdk"; 53 sdkFeatures.remove(featureInfo.name); 54 } 55 // Add the feature version if avaiable. 56 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 57 int version = featureInfo.version; 58 addFeature(store, featureInfo.name, type, true, version); 59 } else { 60 addFeature(store, featureInfo.name, type, true); 61 } 62 } 63 } 64 } 65 66 // Store the remaining "sdk" features not avaiable on this device. 67 for (String featureName : sdkFeatures) { 68 boolean hasFeature = packageManager.hasSystemFeature(featureName); 69 addFeature(store, featureName, "sdk", hasFeature); 70 } 71 72 store.endArray(); 73 } 74 75 /** 76 * Use reflection to get the features defined by the SDK. If there are 77 * features that do not fit the convention of starting with "FEATURE_" 78 * then they will still be shown under the "Other Features" section. 79 * 80 * @return list of feature names from sdk 81 */ 82 private List<String> getPackageManagerFeatures() { 83 try { 84 List<String> features = new ArrayList<String>(); 85 Field[] fields = PackageManager.class.getFields(); 86 for (Field field : fields) { 87 if (field.getName().startsWith("FEATURE_")) { 88 String feature = (String) field.get(null); 89 features.add(feature); 90 } 91 } 92 return features; 93 } catch (IllegalAccessException illegalAccess) { 94 throw new RuntimeException(illegalAccess); 95 } 96 } 97 98 private void addFeature( 99 DeviceInfoStore store, 100 String name, 101 String type, 102 boolean available) throws Exception { 103 store.startGroup(); 104 store.addResult("name", name); 105 store.addResult("type", type); 106 store.addResult("available", available); 107 store.endGroup(); 108 } 109 110 private void addFeature( 111 DeviceInfoStore store, 112 String name, 113 String type, 114 boolean available, 115 int version) throws Exception { 116 store.startGroup(); 117 store.addResult("name", name); 118 store.addResult("type", type); 119 store.addResult("available", available); 120 store.addResult("version", version); 121 store.endGroup(); 122 } 123 } 124