Add test cases for AudioManager SCO methods.
Add test cases for AudioManager.startBluetoothSco() and AudioManager.stopBluetoothSco() Bug: http://b/3292864 Change-Id: I743c8d732270262fbaaff79a53d43cedcd5de528
This commit is contained in:
@@ -44,6 +44,7 @@
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
|
||||
|
||||
@@ -316,4 +316,34 @@ public class BluetoothStressTest extends InstrumentationTestCase {
|
||||
mTestUtils.disablePan(adapter);
|
||||
mTestUtils.disable(adapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stress test for verifying that AudioManager can open and close SCO connections.
|
||||
* <p>
|
||||
* In this test, a HSP connection is opened with an external headset and the SCO connection is
|
||||
* repeatibly opened and closed.
|
||||
*/
|
||||
public void testStartStopSco() {
|
||||
int iterations = BluetoothTestRunner.sStartStopScoIterations;
|
||||
if (iterations == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||
BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sHeadsetAddress);
|
||||
mTestUtils.enable(adapter);
|
||||
mTestUtils.pair(adapter, device, BluetoothTestRunner.sPairPasskey,
|
||||
BluetoothTestRunner.sPairPin);
|
||||
mTestUtils.connectProfile(adapter, device, BluetoothProfile.HEADSET);
|
||||
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
mTestUtils.writeOutput("startStopSco iteration " + (i + 1) + " of " + iterations);
|
||||
mTestUtils.startSco(adapter, device);
|
||||
mTestUtils.stopSco(adapter, device);
|
||||
}
|
||||
|
||||
mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET);
|
||||
mTestUtils.unpair(adapter, device);
|
||||
mTestUtils.disable(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import android.util.Log;
|
||||
* [-e connect_headset_iterations <iterations>] \
|
||||
* [-e connect_input_iterations <iterations>] \
|
||||
* [-e connect_pan_iterations <iterations>] \
|
||||
* [-e start_stop_sco_iterations <iterations>] \
|
||||
* [-e pair_address <address>] \
|
||||
* [-e headset_address <address>] \
|
||||
* [-e a2dp_address <address>] \
|
||||
@@ -62,6 +63,7 @@ public class BluetoothTestRunner extends InstrumentationTestRunner {
|
||||
public static int sConnectA2dpIterations = 100;
|
||||
public static int sConnectInputIterations = 100;
|
||||
public static int sConnectPanIterations = 100;
|
||||
public static int sStartStopScoIterations = 100;
|
||||
|
||||
public static String sPairAddress = "";
|
||||
public static String sHeadsetAddress = "";
|
||||
@@ -167,6 +169,14 @@ public class BluetoothTestRunner extends InstrumentationTestRunner {
|
||||
}
|
||||
}
|
||||
|
||||
val = arguments.getString("start_stop_sco_iterations");
|
||||
if (val != null) {
|
||||
try {
|
||||
sStartStopScoIterations = Integer.parseInt(val);
|
||||
} catch (NumberFormatException e) {
|
||||
// Invalid argument, fall back to default value
|
||||
}
|
||||
}
|
||||
val = arguments.getString("pair_address");
|
||||
if (val != null) {
|
||||
sPairAddress = val;
|
||||
@@ -214,6 +224,7 @@ public class BluetoothTestRunner extends InstrumentationTestRunner {
|
||||
Log.i(TAG, String.format("connect_headset_iterations=%d", sConnectHeadsetIterations));
|
||||
Log.i(TAG, String.format("connect_input_iterations=%d", sConnectInputIterations));
|
||||
Log.i(TAG, String.format("connect_pan_iterations=%d", sConnectPanIterations));
|
||||
Log.i(TAG, String.format("start_stop_sco_iterations=%d", sStartStopScoIterations));
|
||||
Log.i(TAG, String.format("pair_address=%s", sPairAddress));
|
||||
Log.i(TAG, String.format("a2dp_address=%s", sA2dpAddress));
|
||||
Log.i(TAG, String.format("headset_address=%s", sHeadsetAddress));
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -66,6 +67,11 @@ public class BluetoothTestUtils extends Assert {
|
||||
*/
|
||||
private static final int CONNECT_PROXY_TIMEOUT = 5000;
|
||||
|
||||
/**
|
||||
* Timeout to start or stop a SCO channel in ms.
|
||||
*/
|
||||
private static final int START_STOP_SCO_TIMEOUT = 10000;
|
||||
|
||||
/**
|
||||
* Time between polls in ms.
|
||||
*/
|
||||
@@ -319,6 +325,32 @@ public class BluetoothTestUtils extends Assert {
|
||||
}
|
||||
}
|
||||
|
||||
private class StartStopScoReceiver extends FlagReceiver {
|
||||
private static final int STATE_CONNECTED_FLAG = 1;
|
||||
private static final int STATE_DISCONNECTED_FLAG = 1 << 1;
|
||||
|
||||
public StartStopScoReceiver(int expectedFlags) {
|
||||
super(expectedFlags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED.equals(intent.getAction())) {
|
||||
int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
|
||||
AudioManager.SCO_AUDIO_STATE_ERROR);
|
||||
assertNotSame(AudioManager.SCO_AUDIO_STATE_ERROR, state);
|
||||
switch(state) {
|
||||
case AudioManager.SCO_AUDIO_STATE_CONNECTED:
|
||||
setFiredFlag(STATE_CONNECTED_FLAG);
|
||||
break;
|
||||
case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:
|
||||
setFiredFlag(STATE_DISCONNECTED_FLAG);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private BluetoothProfile.ServiceListener mServiceListener =
|
||||
new BluetoothProfile.ServiceListener() {
|
||||
public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
||||
@@ -1268,6 +1300,103 @@ public class BluetoothTestUtils extends Assert {
|
||||
BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a SCO channel using {@link android.media.AudioManager#startBluetoothSco()} and checks
|
||||
* to make sure that the channel is opened and that the correct actions were broadcast.
|
||||
*
|
||||
* @param adapter The BT adapter.
|
||||
* @param device The remote device.
|
||||
*/
|
||||
public void startSco(BluetoothAdapter adapter, BluetoothDevice device) {
|
||||
startStopSco(adapter, device, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes a SCO channel using {@link android.media.AudioManager#stopBluetoothSco()} and checks
|
||||
* to make sure that the channel is closed and that the correct actions were broadcast.
|
||||
*
|
||||
* @param adapter The BT adapter.
|
||||
* @param device The remote device.
|
||||
*/
|
||||
public void stopSco(BluetoothAdapter adapter, BluetoothDevice device) {
|
||||
startStopSco(adapter, device, false);
|
||||
}
|
||||
/**
|
||||
* Helper method for {@link #startSco(BluetoothAdapter, BluetoothDevice)} and
|
||||
* {@link #stopSco(BluetoothAdapter, BluetoothDevice)}.
|
||||
*
|
||||
* @param adapter The BT adapter.
|
||||
* @param device The remote device.
|
||||
* @param isStart Whether the SCO channel should be opened.
|
||||
*/
|
||||
private void startStopSco(BluetoothAdapter adapter, BluetoothDevice device, boolean isStart) {
|
||||
long start = -1;
|
||||
int mask;
|
||||
String methodName;
|
||||
|
||||
if (isStart) {
|
||||
methodName = "startSco()";
|
||||
mask = StartStopScoReceiver.STATE_CONNECTED_FLAG;
|
||||
} else {
|
||||
methodName = "stopSco()";
|
||||
mask = StartStopScoReceiver.STATE_DISCONNECTED_FLAG;
|
||||
}
|
||||
|
||||
if (!adapter.isEnabled()) {
|
||||
fail(String.format("%s bluetooth not enabled: device=%s, start=%b", methodName, device,
|
||||
isStart));
|
||||
}
|
||||
|
||||
if (!adapter.getBondedDevices().contains(device)) {
|
||||
fail(String.format("%s device not paired: device=%s, start=%b", methodName, device,
|
||||
isStart));
|
||||
}
|
||||
|
||||
AudioManager manager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
assertNotNull(manager);
|
||||
|
||||
if (!manager.isBluetoothScoAvailableOffCall()) {
|
||||
fail(String.format("%s device does not support SCO: device=%s, start=%b", methodName,
|
||||
device, isStart));
|
||||
}
|
||||
|
||||
boolean isScoOn = manager.isBluetoothScoOn();
|
||||
if (isStart == isScoOn) {
|
||||
return;
|
||||
}
|
||||
|
||||
StartStopScoReceiver receiver = getStartStopScoReceiver(mask);
|
||||
start = System.currentTimeMillis();
|
||||
if (isStart) {
|
||||
manager.startBluetoothSco();
|
||||
} else {
|
||||
manager.stopBluetoothSco();
|
||||
}
|
||||
|
||||
long s = System.currentTimeMillis();
|
||||
while (System.currentTimeMillis() - s < START_STOP_SCO_TIMEOUT) {
|
||||
isScoOn = manager.isBluetoothScoOn();
|
||||
if ((isStart == isScoOn) &&
|
||||
(receiver.getFiredFlags() & mask) == mask) {
|
||||
long finish = receiver.getCompletedTime();
|
||||
if (start != -1 && finish != -1) {
|
||||
writeOutput(String.format("%s completed in %d ms", methodName,
|
||||
(finish - start)));
|
||||
} else {
|
||||
writeOutput(String.format("%s completed", methodName));
|
||||
}
|
||||
removeReceiver(receiver);
|
||||
return;
|
||||
}
|
||||
sleep(POLL_TIME);
|
||||
}
|
||||
|
||||
int firedFlags = receiver.getFiredFlags();
|
||||
removeReceiver(receiver);
|
||||
fail(String.format("%s timeout: start=%b (expected %b), flags=0x%x (expected 0x%x)",
|
||||
methodName, isScoOn, isStart, firedFlags, mask));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a string to the logcat and a file if a file has been specified in the constructor.
|
||||
*
|
||||
@@ -1336,6 +1465,13 @@ public class BluetoothTestUtils extends Assert {
|
||||
return receiver;
|
||||
}
|
||||
|
||||
private StartStopScoReceiver getStartStopScoReceiver(int expectedFlags) {
|
||||
String[] actions = {AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED};
|
||||
StartStopScoReceiver receiver = new StartStopScoReceiver(expectedFlags);
|
||||
addReceiver(receiver, actions);
|
||||
return receiver;
|
||||
}
|
||||
|
||||
private void removeReceiver(BroadcastReceiver receiver) {
|
||||
mContext.unregisterReceiver(receiver);
|
||||
mReceivers.remove(receiver);
|
||||
|
||||
Reference in New Issue
Block a user