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

Commit 99cf1e0c authored by Eric Rowe's avatar Eric Rowe Committed by Android (Google) Code Review
Browse files

Merge "Add test cases for AudioManager SCO methods."

parents 29f87f76 835d8ee6
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);