Loading core/tests/coretests/AndroidManifest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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" /> Loading core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java +30 −0 Original line number Diff line number Diff line Loading @@ -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); } } core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java +11 −0 Original line number Diff line number Diff line Loading @@ -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>] \ Loading @@ -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 = ""; Loading Loading @@ -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; Loading Loading @@ -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)); Loading core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java +136 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. */ Loading Loading @@ -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) { Loading Loading @@ -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. * Loading Loading @@ -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); Loading Loading
core/tests/coretests/AndroidManifest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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" /> Loading
core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java +30 −0 Original line number Diff line number Diff line Loading @@ -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); } }
core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java +11 −0 Original line number Diff line number Diff line Loading @@ -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>] \ Loading @@ -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 = ""; Loading Loading @@ -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; Loading Loading @@ -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)); Loading
core/tests/coretests/src/android/bluetooth/BluetoothTestUtils.java +136 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. */ Loading Loading @@ -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) { Loading Loading @@ -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. * Loading Loading @@ -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); Loading