• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 android.app.cts;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertTrue;
22 import static org.junit.Assert.fail;
23 
24 import android.app.ActivityManager;
25 import android.app.Instrumentation;
26 import android.app.WallpaperManager;
27 import android.bluetooth.BluetoothAdapter;
28 import android.content.ActivityNotFoundException;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.pm.ConfigurationInfo;
32 import android.content.pm.FeatureInfo;
33 import android.content.pm.PackageManager;
34 import android.content.res.Configuration;
35 import android.hardware.Camera;
36 import android.hardware.Camera.CameraInfo;
37 import android.hardware.Camera.Parameters;
38 import android.hardware.Sensor;
39 import android.hardware.SensorManager;
40 import android.hardware.camera2.CameraCharacteristics;
41 import android.hardware.camera2.CameraManager;
42 import android.hardware.camera2.CameraMetadata;
43 import android.location.LocationManager;
44 import android.net.sip.SipManager;
45 import android.net.wifi.WifiManager;
46 import android.nfc.NfcAdapter;
47 import android.os.Build;
48 import android.telephony.TelephonyManager;
49 
50 import androidx.test.filters.FlakyTest;
51 import androidx.test.platform.app.InstrumentationRegistry;
52 
53 import com.android.compatibility.common.util.CddTest;
54 import com.android.compatibility.common.util.PropertyUtil;
55 import com.android.compatibility.common.util.SystemUtil;
56 
57 import org.junit.Before;
58 import org.junit.Test;
59 import org.junit.runner.RunWith;
60 import org.junit.runners.JUnit4;
61 
62 import java.lang.reflect.Field;
63 import java.util.ArrayList;
64 import java.util.HashSet;
65 import java.util.List;
66 import java.util.Set;
67 
68 /**
69  * Test for checking that the {@link PackageManager} is reporting the correct features.
70  */
71 @RunWith(JUnit4.class)
72 public class SystemFeaturesTest {
73     private static final String FEATURE_GOOGLE_ENTERPRISE_DEVICE =
74             "com.google.android.feature.ENTERPRISE_DEVICE";
75 
76     private Context mContext;
77     private PackageManager mPackageManager;
78     private Set<String> mAvailableFeatures;
79 
80     private ActivityManager mActivityManager;
81     private LocationManager mLocationManager;
82     private SensorManager mSensorManager;
83     private TelephonyManager mTelephonyManager;
84     private WifiManager mWifiManager;
85     private CameraManager mCameraManager;
86 
87     @Before
setUp()88     public void setUp() {
89         Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
90         mContext = instrumentation.getTargetContext();
91         mPackageManager = mContext.getPackageManager();
92         mAvailableFeatures = new HashSet<String>();
93         if (mPackageManager.getSystemAvailableFeatures() != null) {
94             for (FeatureInfo feature : mPackageManager.getSystemAvailableFeatures()) {
95                 mAvailableFeatures.add(feature.name);
96             }
97         }
98         mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
99         mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
100         mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
101         mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
102         mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
103         mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
104     }
105 
106     /**
107      * Check for features improperly prefixed with "android." that are not defined in
108      * {@link PackageManager}.
109      */
110     @Test
testFeatureNamespaces()111     public void testFeatureNamespaces() throws IllegalArgumentException, IllegalAccessException {
112         Set<String> officialFeatures = getFeatureConstantsNames("FEATURE_");
113         assertFalse(officialFeatures.isEmpty());
114 
115         Set<String> notOfficialFeatures = new HashSet<String>(mAvailableFeatures);
116         notOfficialFeatures.removeAll(officialFeatures);
117 
118         for (String featureName : notOfficialFeatures) {
119             if (featureName != null) {
120                 if (!Build.VERSION.CODENAME.equals("REL") &&
121                     featureName.equals("android.software.preview_sdk")) {
122                     // Skips preview_sdk in non-release build.
123                     continue;
124                 }
125                 assertFalse("Use a different namespace than 'android' for " + featureName,
126                         featureName.startsWith("android"));
127             }
128         }
129     }
130 
131     @Test
testBluetoothFeature()132     public void testBluetoothFeature() {
133         if (BluetoothAdapter.getDefaultAdapter() != null) {
134             assertAvailable(PackageManager.FEATURE_BLUETOOTH);
135         } else {
136             assertNotAvailable(PackageManager.FEATURE_BLUETOOTH);
137         }
138     }
139 
140     @Test
testCameraFeatures()141     public void testCameraFeatures() throws Exception {
142         int numCameras = Camera.getNumberOfCameras();
143         if (numCameras == 0) {
144             assertNotAvailable(PackageManager.FEATURE_CAMERA);
145             assertNotAvailable(PackageManager.FEATURE_CAMERA_AUTOFOCUS);
146             assertNotAvailable(PackageManager.FEATURE_CAMERA_FLASH);
147             assertNotAvailable(PackageManager.FEATURE_CAMERA_FRONT);
148             assertNotAvailable(PackageManager.FEATURE_CAMERA_ANY);
149             assertNotAvailable(PackageManager.FEATURE_CAMERA_LEVEL_FULL);
150             assertNotAvailable(PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_SENSOR);
151             assertNotAvailable(PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_POST_PROCESSING);
152             assertNotAvailable(PackageManager.FEATURE_CAMERA_CAPABILITY_RAW);
153             assertNotAvailable(PackageManager.FEATURE_CAMERA_AR);
154 
155             assertFalse("Devices supporting external cameras must have a representative camera " +
156                     "connected for testing",
157                     mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL));
158         } else {
159             assertAvailable(PackageManager.FEATURE_CAMERA_ANY);
160             checkFrontCamera();
161             checkRearCamera();
162             checkCamera2Features();
163         }
164     }
165 
166     @CddTest(requirement="7.5.4/C-0-8")
checkCamera2Features()167     private void checkCamera2Features() throws Exception {
168         String[] cameraIds = mCameraManager.getCameraIdList();
169         boolean fullCamera = false;
170         boolean manualSensor = false;
171         boolean manualPostProcessing = false;
172         boolean motionTracking = false;
173         boolean raw = false;
174         boolean hasFlash = false;
175         boolean hasAutofocus = false;
176         CameraCharacteristics[] cameraChars = new CameraCharacteristics[cameraIds.length];
177         for (String cameraId : cameraIds) {
178             CameraCharacteristics chars = mCameraManager.getCameraCharacteristics(cameraId);
179             Integer hwLevel = chars.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
180             int[] capabilities = chars.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
181             if (hwLevel == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL ||
182                     hwLevel == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_3) {
183                 fullCamera = true;
184             }
185             for (int capability : capabilities) {
186                 switch (capability) {
187                     case CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR:
188                         manualSensor = true;
189                         break;
190                     case CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING:
191                         manualPostProcessing = true;
192                         break;
193                     case CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW:
194                         raw = true;
195                         break;
196                   case CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING:
197                         motionTracking = true;
198                         break;
199                     default:
200                         // Capabilities don't have a matching system feature
201                         break;
202                 }
203             }
204 
205             Boolean flashAvailable = chars.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
206             if (flashAvailable) {
207                 hasFlash = true;
208             }
209             Float minFocusDistance =
210                     chars.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
211             if (minFocusDistance != null && minFocusDistance > 0) {
212                 hasAutofocus = true;
213             }
214         }
215         assertFeature(fullCamera, PackageManager.FEATURE_CAMERA_LEVEL_FULL);
216         assertFeature(manualSensor, PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_SENSOR);
217         assertFeature(manualPostProcessing,
218                 PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_POST_PROCESSING);
219         assertFeature(raw, PackageManager.FEATURE_CAMERA_CAPABILITY_RAW);
220         if (!motionTracking) {
221           // FEATURE_CAMERA_AR requires the presence of
222           // CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING but
223           // MOTION_TRACKING does not require the presence of FEATURE_CAMERA_AR
224           //
225           // Logic table:
226           //    AR= F   T
227           // MT=F   Y   N
228           //   =T   Y   Y
229           //
230           // So only check the one disallowed condition: No motion tracking and FEATURE_CAMERA_AR is
231           // available
232           assertNotAvailable(PackageManager.FEATURE_CAMERA_AR);
233         }
234         assertFeature(hasFlash, PackageManager.FEATURE_CAMERA_FLASH);
235         assertFeature(hasAutofocus, PackageManager.FEATURE_CAMERA_AUTOFOCUS);
236     }
237 
checkFrontCamera()238     private void checkFrontCamera() {
239         CameraInfo info = new CameraInfo();
240         int numCameras = Camera.getNumberOfCameras();
241         int frontCameraId = -1;
242         for (int i = 0; i < numCameras; i++) {
243             Camera.getCameraInfo(i, info);
244             if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
245                 frontCameraId = i;
246             }
247         }
248 
249         if (frontCameraId > -1) {
250             assertTrue("Device has front-facing camera but does not report either " +
251                     "the FEATURE_CAMERA_FRONT or FEATURE_CAMERA_EXTERNAL feature",
252                     mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT) ||
253                     mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL));
254         } else {
255             assertFalse("Device does not have front-facing camera but reports either " +
256                     "the FEATURE_CAMERA_FRONT or FEATURE_CAMERA_EXTERNAL feature",
257                     mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT) ||
258                     mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL));
259         }
260     }
261 
checkRearCamera()262     private void checkRearCamera() {
263         Camera camera = null;
264         try {
265             camera = Camera.open();
266             if (camera != null) {
267                 assertAvailable(PackageManager.FEATURE_CAMERA);
268 
269                 Camera.Parameters params = camera.getParameters();
270                 if (params.getSupportedFocusModes().contains(Parameters.FOCUS_MODE_AUTO)) {
271                     assertAvailable(PackageManager.FEATURE_CAMERA_AUTOFOCUS);
272                 }
273 
274                 if (params.getFlashMode() != null) {
275                     assertAvailable(PackageManager.FEATURE_CAMERA_FLASH);
276                 }
277 
278             } else {
279                 assertNotAvailable(PackageManager.FEATURE_CAMERA);
280             }
281         } finally {
282             if (camera != null) {
283                 camera.release();
284             }
285         }
286     }
287 
288     @Test
testGamepadFeature()289     public void testGamepadFeature() {
290         if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
291             assertAvailable(PackageManager.FEATURE_GAMEPAD);
292         }
293     }
294 
295     @Test
testLiveWallpaperFeature()296     public void testLiveWallpaperFeature() {
297         try {
298             Intent intent = new Intent(WallpaperManager.ACTION_LIVE_WALLPAPER_CHOOSER);
299             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
300             mContext.startActivity(intent);
301             assertAvailable(PackageManager.FEATURE_LIVE_WALLPAPER);
302         } catch (ActivityNotFoundException e) {
303             assertNotAvailable(PackageManager.FEATURE_LIVE_WALLPAPER);
304         }
305     }
306 
307     @Test
testLocationFeatures()308     public void testLocationFeatures() {
309         if (mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
310             assertAvailable(PackageManager.FEATURE_LOCATION);
311             assertAvailable(PackageManager.FEATURE_LOCATION_GPS);
312         } else {
313             assertNotAvailable(PackageManager.FEATURE_LOCATION_GPS);
314         }
315 
316         if (mLocationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {
317             assertAvailable(PackageManager.FEATURE_LOCATION);
318             assertAvailable(PackageManager.FEATURE_LOCATION_NETWORK);
319         } else {
320             assertNotAvailable(PackageManager.FEATURE_LOCATION_NETWORK);
321         }
322     }
323 
324     @Test
testLowRamFeature()325     public void testLowRamFeature() {
326         if (mActivityManager.isLowRamDevice()) {
327             assertAvailable(PackageManager.FEATURE_RAM_LOW);
328         } else {
329             assertAvailable(PackageManager.FEATURE_RAM_NORMAL);
330         }
331     }
332 
333     @Test
testNfcFeatures()334     public void testNfcFeatures() {
335         if (NfcAdapter.getDefaultAdapter(mContext) != null) {
336             // Watches/Enterprise devices MAY support all FEATURE_NFC features when an NfcAdapter
337             // is available, but other MUST support them both.
338             if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)
339                     || mPackageManager.hasSystemFeature(FEATURE_GOOGLE_ENTERPRISE_DEVICE)) {
340                 assertOneAvailable(PackageManager.FEATURE_NFC,
341                     PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);
342             } else {
343                 assertAvailable(PackageManager.FEATURE_NFC);
344                 assertAvailable(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);
345             }
346         } else {
347             assertNotAvailable(PackageManager.FEATURE_NFC);
348             assertNotAvailable(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);
349         }
350     }
351 
352     @Test
testScreenFeatures()353     public void testScreenFeatures() {
354         assertTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE)
355                 || mPackageManager.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT));
356     }
357 
358     /**
359      * Check that the sensor features reported by the PackageManager correspond to the sensors
360      * returned by {@link SensorManager#getSensorList(int)}.
361      */
362     @FlakyTest
363     @Test
testSensorFeatures()364     public void testSensorFeatures() throws Exception {
365         Set<String> featuresLeft = getFeatureConstantsNames("FEATURE_SENSOR_");
366 
367         assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_ACCELEROMETER,
368                 Sensor.TYPE_ACCELEROMETER);
369         assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_BAROMETER,
370                 Sensor.TYPE_PRESSURE);
371         assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_COMPASS,
372                 Sensor.TYPE_MAGNETIC_FIELD);
373         assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_GYROSCOPE,
374                 Sensor.TYPE_GYROSCOPE);
375         assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_LIGHT,
376                 Sensor.TYPE_LIGHT);
377         assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_PROXIMITY,
378                 Sensor.TYPE_PROXIMITY);
379         assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_STEP_COUNTER,
380                 Sensor.TYPE_STEP_COUNTER);
381         assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_STEP_DETECTOR,
382                 Sensor.TYPE_STEP_DETECTOR);
383         assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_AMBIENT_TEMPERATURE,
384                 Sensor.TYPE_AMBIENT_TEMPERATURE);
385         assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_RELATIVE_HUMIDITY,
386                 Sensor.TYPE_RELATIVE_HUMIDITY);
387         assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_HINGE_ANGLE,
388                 Sensor.TYPE_HINGE_ANGLE);
389         assertFeatureForSensor(featuresLeft,
390                 PackageManager.FEATURE_SENSOR_ACCELEROMETER_LIMITED_AXES,
391                 Sensor.TYPE_ACCELEROMETER_LIMITED_AXES);
392         assertFeatureForSensor(featuresLeft,
393                 PackageManager.FEATURE_SENSOR_GYROSCOPE_LIMITED_AXES,
394                 Sensor.TYPE_GYROSCOPE_LIMITED_AXES);
395         assertFeatureForSensor(featuresLeft,
396                 PackageManager.FEATURE_SENSOR_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED,
397                 Sensor.TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED);
398         assertFeatureForSensor(featuresLeft,
399                 PackageManager.FEATURE_SENSOR_GYROSCOPE_LIMITED_AXES_UNCALIBRATED,
400                 Sensor.TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED);
401         assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_HEADING,
402                 Sensor.TYPE_HEADING);
403 
404         // Note that FEATURE_SENSOR_DYNAMIC_HEAD_TRACKER requires dynamic sensor discovery, but
405         // dynamic sensor discovery does not require FEATURE_SENSOR_DYNAMIC_HEAD_TRACKER
406         if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_DYNAMIC_HEAD_TRACKER)) {
407             assertTrue("Device declared " + PackageManager.FEATURE_SENSOR_DYNAMIC_HEAD_TRACKER
408                     + " but does not support dynamic sensor discovery",
409                     mSensorManager.isDynamicSensorDiscoverySupported());
410         }
411         featuresLeft.remove(PackageManager.FEATURE_SENSOR_DYNAMIC_HEAD_TRACKER);
412 
413         /*
414          * We have three cases to test for :
415          * Case 1:  Device does not have an HRM
416          * FEATURE_SENSOR_HEART_RATE               false
417          * FEATURE_SENSOR_HEART_RATE_ECG           false
418          * assertFeatureForSensor(TßYPE_HEART_RATE) false
419          *
420          * Case 2:  Device has a PPG HRM
421          * FEATURE_SENSOR_HEART_RATE               true
422          * FEATURE_SENSOR_HEART_RATE_ECG           false
423          * assertFeatureForSensor(TYPE_HEART_RATE) true
424          *
425          * Case 3:  Device has an ECG HRM
426          * FEATURE_SENSOR_HEART_RATE               false
427          * FEATURE_SENSOR_HEART_RATE_ECG           true
428          * assertFeatureForSensor(TYPE_HEART_RATE) true
429          */
430 
431         if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_HEART_RATE_ECG)) {
432                 /* Case 3 for FEATURE_SENSOR_HEART_RATE_ECG true case */
433                 assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_HEART_RATE_ECG,
434                         Sensor.TYPE_HEART_RATE);
435 
436                 /* Remove HEART_RATE from featuresLeft, no way to test that one */
437                 assertTrue("Features left " + featuresLeft + " to check did not include "
438                         + PackageManager.FEATURE_SENSOR_HEART_RATE,
439                         featuresLeft.remove(PackageManager.FEATURE_SENSOR_HEART_RATE));
440         } else if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_HEART_RATE)) {
441                 /* Case 1 & 2 for FEATURE_SENSOR_HEART_RATE_ECG false case */
442                 assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_HEART_RATE_ECG,
443                         Sensor.TYPE_HEART_RATE);
444 
445                 /* Case 1 & 3 for FEATURE_SENSOR_HEART_RATE false case */
446                 assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_HEART_RATE,
447                         Sensor.TYPE_HEART_RATE);
448         } else {
449                 /* Case 2 for FEATURE_SENSOR_HEART_RATE true case */
450                 assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_HEART_RATE,
451                         Sensor.TYPE_HEART_RATE);
452 
453                 /* Remove HEART_RATE_ECG from featuresLeft, no way to test that one */
454                 assertTrue("Features left " + featuresLeft + " to check did not include "
455                         + PackageManager.FEATURE_SENSOR_HEART_RATE_ECG,
456                         featuresLeft.remove(PackageManager.FEATURE_SENSOR_HEART_RATE_ECG));
457         }
458 
459         assertTrue("Assertions need to be added to this test for " + featuresLeft,
460                 featuresLeft.isEmpty());
461     }
462 
463     /** Get a list of feature constants in PackageManager matching a prefix. */
getFeatureConstantsNames(String prefix)464     private static Set<String> getFeatureConstantsNames(String prefix)
465             throws IllegalArgumentException, IllegalAccessException {
466         Set<String> features = new HashSet<String>();
467         Field[] fields = PackageManager.class.getFields();
468         for (Field field : fields) {
469             if (field.getName().startsWith(prefix)) {
470                 String feature = (String) field.get(null);
471                 features.add(feature);
472             }
473         }
474         return features;
475     }
476 
477     @Test
testSipFeatures()478     public void testSipFeatures() {
479         if (SipManager.newInstance(mContext) != null) {
480             assertAvailable(PackageManager.FEATURE_SIP);
481         } else {
482             assertNotAvailable(PackageManager.FEATURE_SIP);
483             assertNotAvailable(PackageManager.FEATURE_SIP_VOIP);
484         }
485 
486         if (SipManager.isApiSupported(mContext)) {
487             assertAvailable(PackageManager.FEATURE_SIP);
488         } else {
489             assertNotAvailable(PackageManager.FEATURE_SIP);
490             assertNotAvailable(PackageManager.FEATURE_SIP_VOIP);
491         }
492 
493         if (SipManager.isVoipSupported(mContext)) {
494             assertAvailable(PackageManager.FEATURE_SIP);
495             assertAvailable(PackageManager.FEATURE_SIP_VOIP);
496         } else {
497             assertNotAvailable(PackageManager.FEATURE_SIP_VOIP);
498         }
499     }
500 
501     /**
502      * Check that if the PackageManager declares a sensor feature that the device has at least
503      * one sensor that matches that feature. Also check that if a PackageManager does not declare
504      * a sensor that the device also does not have such a sensor.
505      *
506      * @param featuresLeft to check in order to make sure the test covers all sensor features
507      * @param expectedFeature that the PackageManager may report
508      * @param expectedSensorType that that {@link SensorManager#getSensorList(int)} may have
509      */
assertFeatureForSensor(Set<String> featuresLeft, String expectedFeature, int expectedSensorType)510     private void assertFeatureForSensor(Set<String> featuresLeft, String expectedFeature,
511             int expectedSensorType) {
512         assertTrue("Features left " + featuresLeft + " to check did not include "
513                 + expectedFeature, featuresLeft.remove(expectedFeature));
514 
515         boolean hasSensorFeature = mPackageManager.hasSystemFeature(expectedFeature);
516 
517         List<Sensor> sensors = mSensorManager.getSensorList(expectedSensorType);
518         List<String> sensorNames = new ArrayList<String>(sensors.size());
519         for (Sensor sensor : sensors) {
520             sensorNames.add(sensor.getName());
521         }
522         boolean hasSensorType = !sensors.isEmpty();
523 
524         String message = "PackageManager#hasSystemFeature(" + expectedFeature + ") returns "
525                 + hasSensorFeature
526                 + " but SensorManager#getSensorList(" + expectedSensorType + ") shows sensors "
527                 + sensorNames;
528 
529         assertEquals(message, hasSensorFeature, hasSensorType);
530     }
531 
532     /**
533      * Check that the {@link TelephonyManager#getPhoneType()} matches the reported features.
534      */
535     @Test
testTelephonyFeatures()536     public void testTelephonyFeatures() {
537         if (!(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
538                 && mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELECOM)
539                 && mTelephonyManager.isVoiceCapable())) {
540                 return;
541         }
542 
543         int phoneType = mTelephonyManager.getPhoneType();
544         switch (phoneType) {
545             case TelephonyManager.PHONE_TYPE_GSM:
546                 assertAvailable(PackageManager.FEATURE_TELEPHONY_GSM);
547                 break;
548 
549             case TelephonyManager.PHONE_TYPE_CDMA:
550                 assertAvailable(PackageManager.FEATURE_TELEPHONY_CDMA);
551                 break;
552 
553             case TelephonyManager.PHONE_TYPE_NONE:
554                 fail("FEATURE_TELEPHONY is present; phone type should not be PHONE_TYPE_NONE");
555                 break;
556 
557             default:
558                 throw new IllegalArgumentException("Did you add a new phone type? " + phoneType);
559         }
560     }
561 
562     @Test
testTouchScreenFeatures()563     public void testTouchScreenFeatures() {
564         // If device implementations include a touchscreen (single-touch or better), they:
565         // [C-1-1] MUST report TOUCHSCREEN_FINGER for the Configuration.touchscreen API field.
566         // [C-1-2] MUST report the android.hardware.touchscreen and
567         // android.hardware.faketouch feature flags
568         ConfigurationInfo configInfo = mActivityManager.getDeviceConfigurationInfo();
569         if (configInfo.reqTouchScreen == Configuration.TOUCHSCREEN_NOTOUCH) {
570             // Device does not include a touchscreen
571             assertNotAvailable(PackageManager.FEATURE_TOUCHSCREEN);
572         } else {
573             // Device has a touchscreen
574             assertAvailable(PackageManager.FEATURE_TOUCHSCREEN);
575             assertAvailable(PackageManager.FEATURE_FAKETOUCH);
576         }
577     }
578 
579     @Test
testFakeTouchFeatures()580     public void testFakeTouchFeatures() {
581         // If device implementations declare support for android.hardware.faketouch, they:
582         // [C-1-7] MUST report TOUCHSCREEN_NOTOUCH for the Configuration.touchscreen API field
583         if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FAKETOUCH) &&
584                 !mPackageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) {
585             // The device *only* supports faketouch, and does not have a touchscreen
586             Configuration configuration = mContext.getResources().getConfiguration();
587             assertEquals(configuration.touchscreen, Configuration.TOUCHSCREEN_NOTOUCH);
588         }
589 
590         // If device implementations declare support for
591         // android.hardware.faketouch.multitouch.distinct, they:
592         // [C-2-1] MUST declare support for android.hardware.faketouch
593         if (mPackageManager.hasSystemFeature(
594                 PackageManager.FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT)) {
595             assertAvailable(PackageManager.FEATURE_FAKETOUCH);
596         }
597 
598         // If device implementations declare support for
599         // android.hardware.faketouch.multitouch.jazzhand, they:
600         // [C-3-1] MUST declare support for android.hardware.faketouch
601         if (mPackageManager.hasSystemFeature(
602                 PackageManager.FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND)) {
603             assertAvailable(PackageManager.FEATURE_FAKETOUCH);
604         }
605     }
606 
607     @Test
testUsbAccessory()608     public void testUsbAccessory() {
609         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) &&
610                 !mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK) &&
611                 !mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH) &&
612                 !mPackageManager.hasSystemFeature(PackageManager.FEATURE_EMBEDDED) &&
613                 !isAndroidEmulator() &&
614                 !mPackageManager.hasSystemFeature(PackageManager.FEATURE_PC) &&
615                 mPackageManager.hasSystemFeature(PackageManager.FEATURE_MICROPHONE) &&
616                 mPackageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) {
617             // USB accessory mode is only a requirement for devices with USB ports supporting
618             // peripheral mode. As there is no public API to distinguish a device with only host
619             // mode support from having both peripheral and host support, the test may have
620             // false negatives.
621             assertAvailable(PackageManager.FEATURE_USB_ACCESSORY);
622         }
623     }
624 
625     @Test
testWifiFeature()626     public void testWifiFeature() throws Exception {
627         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
628             // no WiFi, skip the test
629             return;
630         }
631         boolean enabled = mWifiManager.isWifiEnabled();
632         try {
633             // assert wifimanager can toggle wifi from current sate
634             SystemUtil.runShellCommand("svc wifi " + (!enabled ? "enable" : "disable"));
635             Thread.sleep(5_000); // wait for the toggle to take effect.
636             assertEquals(!enabled, mWifiManager.isWifiEnabled());
637 
638         } finally {
639             SystemUtil.runShellCommand("svc wifi " + (enabled ? "enable" : "disable"));
640         }
641     }
642 
643     @Test
testAudioOutputFeature()644     public void testAudioOutputFeature() throws Exception {
645         if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) ||
646                 mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
647             assertAvailable(PackageManager.FEATURE_AUDIO_OUTPUT);
648         }
649     }
650 
assertAvailable(String feature)651     private void assertAvailable(String feature) {
652         assertTrue("PackageManager#hasSystemFeature should return true for " + feature,
653                 mPackageManager.hasSystemFeature(feature));
654         assertTrue("PackageManager#getSystemAvailableFeatures should have " + feature,
655                 mAvailableFeatures.contains(feature));
656     }
657 
assertNotAvailable(String feature)658     private void assertNotAvailable(String feature) {
659         assertFalse("PackageManager#hasSystemFeature should NOT return true for " + feature,
660                 mPackageManager.hasSystemFeature(feature));
661         assertFalse("PackageManager#getSystemAvailableFeatures should NOT have " + feature,
662                 mAvailableFeatures.contains(feature));
663     }
664 
assertOneAvailable(String feature1, String feature2)665     private void assertOneAvailable(String feature1, String feature2) {
666         if ((mPackageManager.hasSystemFeature(feature1) && mAvailableFeatures.contains(feature1)) ||
667             (mPackageManager.hasSystemFeature(feature2) && mAvailableFeatures.contains(feature2))) {
668             return;
669         } else {
670             fail("Must support at least one of " + feature1 + " or " + feature2);
671         }
672     }
673 
isAndroidEmulator()674     private boolean isAndroidEmulator() {
675         return PropertyUtil.propertyEquals("ro.boot.qemu", "1");
676     }
677 
assertFeature(boolean exist, String feature)678     private void assertFeature(boolean exist, String feature) {
679         if (exist) {
680             assertAvailable(feature);
681         } else {
682             assertNotAvailable(feature);
683         }
684     }
685 }
686