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:
Eric Rowe
2011-02-28 15:22:26 -08:00
parent 6c113a14ca
commit 835d8ee61e
4 changed files with 178 additions and 0 deletions

View File

@@ -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" />

View File

@@ -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);
}
}

View File

@@ -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));

View File

@@ -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);