blob: 75dfba62804b088b429014d10d7e519a03d5fca1 [file] [log] [blame]
/*
* 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);
}
}
}