Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 835d8ee6 authored by Eric Rowe's avatar Eric Rowe
Browse files

Add test cases for AudioManager SCO methods.

Add test cases for AudioManager.startBluetoothSco() and
AudioManager.stopBluetoothSco()

Bug: http://b/3292864
Change-Id: I743c8d732270262fbaaff79a53d43cedcd5de528
parent 6c113a14
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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" />
+30 −0
Original line number Diff line number Diff line
@@ -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);
    }
}
+11 −0
Original line number Diff line number Diff line
@@ -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));
+136 −0
Original line number Diff line number Diff line
@@ -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);