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