| /* |
| * Copyright (C) 2020 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.bluetooth.cts; |
| |
| import static org.junit.Assert.assertNotEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.fail; |
| |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.bluetooth.BluetoothAdapter; |
| import android.bluetooth.BluetoothManager; |
| import android.bluetooth.BluetoothProfile; |
| import android.bluetooth.le.ScanRecord; |
| import android.content.Context; |
| import android.content.pm.PackageManager; |
| import android.content.res.Resources; |
| import android.provider.Settings; |
| import android.util.Log; |
| |
| import androidx.test.platform.app.InstrumentationRegistry; |
| |
| import junit.framework.Assert; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.Arrays; |
| |
| /** |
| * Utility class for Bluetooth CTS test. |
| */ |
| class TestUtils { |
| /** |
| * Bluetooth package name |
| */ |
| static final String BLUETOOTH_PACKAGE_NAME = "com.android.bluetooth.services"; |
| |
| /** |
| * Get the Config.xml name tag for a particular Bluetooth profile |
| * @param profile profile id from {@link BluetoothProfile} |
| * @return config name tag, or null if the tag name is not available |
| */ |
| @Nullable static String profileIdToConfigTag(int profile) { |
| switch (profile) { |
| case BluetoothProfile.A2DP: |
| return "profile_supported_a2dp"; |
| case BluetoothProfile.A2DP_SINK: |
| return "profile_supported_a2dp_sink"; |
| case BluetoothProfile.HEADSET: |
| return "profile_supported_hs_hfp"; |
| case BluetoothProfile.HEADSET_CLIENT: |
| return "profile_supported_hfpclient"; |
| case BluetoothProfile.HID_HOST: |
| return "profile_supported_hid_host"; |
| case BluetoothProfile.OPP: |
| return "profile_supported_opp"; |
| case BluetoothProfile.PAN: |
| return "profile_supported_pan"; |
| case BluetoothProfile.PBAP: |
| return "profile_supported_pbap"; |
| case BluetoothProfile.GATT: |
| return "profile_supported_gatt"; |
| case BluetoothProfile.MAP: |
| return "profile_supported_map"; |
| // Hidden profile |
| // case BluetoothProfile.AVRCP: |
| // return "profile_supported_avrcp_target"; |
| case BluetoothProfile.AVRCP_CONTROLLER: |
| return "profile_supported_avrcp_controller"; |
| case BluetoothProfile.SAP: |
| return "profile_supported_sap"; |
| case BluetoothProfile.PBAP_CLIENT: |
| return "profile_supported_pbapclient"; |
| case BluetoothProfile.MAP_CLIENT: |
| return "profile_supported_mapmce"; |
| case BluetoothProfile.HID_DEVICE: |
| return "profile_supported_hid_device"; |
| case BluetoothProfile.LE_AUDIO: |
| return "profile_supported_le_audio"; |
| case BluetoothProfile.LE_AUDIO_BROADCAST: |
| return "profile_supported_le_audio_broadcast"; |
| case BluetoothProfile.VOLUME_CONTROL: |
| return "profile_supported_vc"; |
| // Hidden profile |
| // case BluetoothProfile.MCP_SERVER: |
| // return "profile_supported_mcp_server"; |
| case BluetoothProfile.CSIP_SET_COORDINATOR: |
| return "profile_supported_csip_set_coordinator"; |
| // Hidden profile |
| // case BluetoothProfile.LE_CALL_CONTROL: |
| // return "profile_supported_le_call_control"; |
| case BluetoothProfile.HAP_CLIENT: |
| return "profile_supported_hap_client"; |
| case BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT: |
| return "profile_supported_bass_client"; |
| default: |
| return null; |
| } |
| } |
| |
| /** |
| * Checks if a particular Bluetooth profile is configured for this device |
| * Fail the test if profile config status cannot be obtained |
| */ |
| static boolean getProfileConfigValueOrDie(int profile) { |
| String profileConfigValueTag = profileIdToConfigTag(profile); |
| assertNotNull(profileConfigValueTag); |
| assertNotEquals("profile tag cannot be empty", 0, profileConfigValueTag.length()); |
| Context context = InstrumentationRegistry.getInstrumentation().getContext(); |
| Resources bluetoothResources = null; |
| try { |
| bluetoothResources = context.getPackageManager().getResourcesForApplication( |
| BLUETOOTH_PACKAGE_NAME); |
| } catch (PackageManager.NameNotFoundException e) { |
| fail("Cannot get Bluetooth package resource"); |
| } |
| int resourceId = bluetoothResources.getIdentifier( |
| profileConfigValueTag, "bool", BLUETOOTH_PACKAGE_NAME); |
| if (resourceId == 0) { |
| return false; |
| } |
| return bluetoothResources.getBoolean(resourceId); |
| } |
| |
| /** |
| * Checks whether this device has Bluetooth feature |
| * @return true if this device has Bluetooth feature |
| */ |
| static boolean hasBluetooth() { |
| Context context = InstrumentationRegistry.getInstrumentation().getContext(); |
| return context.getPackageManager().hasSystemFeature( |
| PackageManager.FEATURE_BLUETOOTH); |
| } |
| |
| /** |
| * Adopt shell UID's permission via {@link android.app.UiAutomation} |
| * @param permission permission to adopt |
| */ |
| static void adoptPermissionAsShellUid(@Nullable String... permission) { |
| InstrumentationRegistry.getInstrumentation().getUiAutomation() |
| .adoptShellPermissionIdentity(permission); |
| } |
| |
| /** |
| * Drop all permissions adopted as shell UID |
| */ |
| static void dropPermissionAsShellUid() { |
| InstrumentationRegistry.getInstrumentation().getUiAutomation() |
| .dropShellPermissionIdentity(); |
| } |
| |
| /** |
| * Get {@link BluetoothAdapter} via {@link android.bluetooth.BluetoothManager} |
| * Fail the test if {@link BluetoothAdapter} is null |
| * @return instance of {@link BluetoothAdapter} |
| */ |
| @NonNull static BluetoothAdapter getBluetoothAdapterOrDie() { |
| Context context = InstrumentationRegistry.getInstrumentation().getContext(); |
| BluetoothManager manager = context.getSystemService(BluetoothManager.class); |
| assertNotNull(manager); |
| BluetoothAdapter adapter = manager.getAdapter(); |
| assertNotNull(adapter); |
| return adapter; |
| } |
| |
| /** |
| * Utility method to call hidden ScanRecord.parseFromBytes method. |
| */ |
| static ScanRecord parseScanRecord(byte[] bytes) { |
| Class<?> scanRecordClass = ScanRecord.class; |
| try { |
| Method method = scanRecordClass.getDeclaredMethod("parseFromBytes", byte[].class); |
| return (ScanRecord) method.invoke(null, bytes); |
| } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException |
| | InvocationTargetException e) { |
| return null; |
| } |
| } |
| |
| /** |
| * Assert two byte arrays are equal. |
| */ |
| static void assertArrayEquals(byte[] expected, byte[] actual) { |
| if (!Arrays.equals(expected, actual)) { |
| Assert.fail("expected:<" + Arrays.toString(expected) + |
| "> but was:<" + Arrays.toString(actual) + ">"); |
| } |
| } |
| |
| /** |
| * Get current location mode settings. |
| */ |
| static int getLocationMode(Context context) { |
| return Settings.Secure.getInt(context.getContentResolver(), |
| Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF); |
| } |
| |
| /** |
| * Set location settings mode. |
| */ |
| static void setLocationMode(Context context, int mode) { |
| Settings.Secure.putInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE, |
| mode); |
| } |
| |
| /** |
| * Return true if location is on. |
| */ |
| static boolean isLocationOn(Context context) { |
| return getLocationMode(context) != Settings.Secure.LOCATION_MODE_OFF; |
| } |
| |
| /** |
| * Enable location and set the mode to GPS only. |
| */ |
| static void enableLocation(Context context) { |
| setLocationMode(context, Settings.Secure.LOCATION_MODE_SENSORS_ONLY); |
| } |
| |
| /** |
| * Disable location. |
| */ |
| static void disableLocation(Context context) { |
| setLocationMode(context, Settings.Secure.LOCATION_MODE_OFF); |
| } |
| |
| /** |
| * Check if BLE is supported by this platform |
| * @param context current device context |
| * @return true if BLE is supported, false otherwise |
| */ |
| static boolean isBleSupported(Context context) { |
| return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE); |
| } |
| |
| /** |
| * Put the current thread to sleep. |
| * @param sleepMillis number of milliseconds to sleep for |
| */ |
| static void sleep(int sleepMillis) { |
| try { |
| Thread.sleep(sleepMillis); |
| } catch (InterruptedException e) { |
| Log.e(TestUtils.class.getSimpleName(), "interrupted", e); |
| } |
| } |
| } |