FileDocCategorySizeDatePackage
BluetoothTestUtils.javaAPI DocAndroid 5.1 API60493Thu Mar 12 22:22:12 GMT 2015android.bluetooth

BluetoothTestUtils

public class BluetoothTestUtils extends Assert

Fields Summary
private static final int
ENABLE_DISABLE_TIMEOUT
Timeout for enable/disable in ms.
private static final int
DISCOVERABLE_UNDISCOVERABLE_TIMEOUT
Timeout for discoverable/undiscoverable in ms.
private static final int
START_STOP_SCAN_TIMEOUT
Timeout for starting/stopping a scan in ms.
private static final int
PAIR_UNPAIR_TIMEOUT
Timeout for pair/unpair in ms.
private static final int
CONNECT_DISCONNECT_PROFILE_TIMEOUT
Timeout for connecting/disconnecting a profile in ms.
private static final int
START_STOP_SCO_TIMEOUT
Timeout to start or stop a SCO channel in ms.
private static final int
CONNECT_PROXY_TIMEOUT
Timeout to connect a profile proxy in ms.
private static final int
POLL_TIME
Time between polls in ms.
private BluetoothProfile.ServiceListener
mServiceListener
private List
mReceivers
private BufferedWriter
mOutputWriter
private String
mTag
private String
mOutputFile
private android.content.Context
mContext
private BluetoothA2dp
mA2dp
private BluetoothHeadset
mHeadset
private BluetoothInputDevice
mInput
private android.bluetooth.BluetoothPan
mPan
Constructors Summary
public BluetoothTestUtils(android.content.Context context, String tag)
Creates a utility instance for testing Bluetooth.

param
context The context of the application using the utility.
param
tag The log tag of the application using the utility.


                                     
         
        this(context, tag, null);
    
public BluetoothTestUtils(android.content.Context context, String tag, String outputFile)
Creates a utility instance for testing Bluetooth.

param
context The context of the application using the utility.
param
tag The log tag of the application using the utility.
param
outputFile The path to an output file if the utility is to write results to a separate file.

        mContext = context;
        mTag = tag;
        mOutputFile = outputFile;

        if (mOutputFile == null) {
            mOutputWriter = null;
        } else {
            try {
                mOutputWriter = new BufferedWriter(new FileWriter(new File(
                        Environment.getExternalStorageDirectory(), mOutputFile), true));
            } catch (IOException e) {
                Log.w(mTag, "Test output file could not be opened", e);
                mOutputWriter = null;
            }
        }
    
Methods Summary
public voidacceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, byte[] pin)
Accepts a pairing with a remote device and checks to make sure that the devices are paired and that the correct actions were broadcast.

param
adapter The BT adapter.
param
device The remote device.
param
passkey The pairing passkey if pairing requires a passkey. Any value if not.
param
pin The pairing pin if pairing requires a pin. Any value if not.

        pairOrAcceptPair(adapter, device, passkey, pin, false);
    
private voidaddReceiver(android.content.BroadcastReceiver receiver, java.lang.String[] actions)

        IntentFilter filter = new IntentFilter();
        for (String action: actions) {
            filter.addAction(action);
        }
        mContext.registerReceiver(receiver, filter);
        mReceivers.add(receiver);
    
public voidclose()
Closes the utility instance and unregisters any BroadcastReceivers.

        while (!mReceivers.isEmpty()) {
            mContext.unregisterReceiver(mReceivers.remove(0));
        }

        if (mOutputWriter != null) {
            try {
                mOutputWriter.close();
            } catch (IOException e) {
                Log.w(mTag, "Test output file could not be closed", e);
            }
        }
    
public voidconnectPan(BluetoothAdapter adapter, BluetoothDevice device)
Connects the PANU to a remote NAP and checks to make sure that the PANU is connected and that the correct actions were broadcast.

param
adapter The BT adapter.
param
device The remote device.

        connectPanOrIncomingPanConnection(adapter, device, true);
    
private voidconnectPanOrIncomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device, boolean connect)
Helper method used by {@link #connectPan(BluetoothAdapter, BluetoothDevice)} and {@link #incomingPanConnection(BluetoothAdapter, BluetoothDevice)} to either connect to a remote NAP or verify that a remote device connected to the local NAP.

param
adapter The BT adapter.
param
device The remote device.
param
connect If the method should initiate the connection (is PANU)

        long start = -1;
        int mask, role;
        String methodName;

        if (connect) {
            methodName = String.format("connectPan(device=%s)", device);
            mask = (ConnectProfileReceiver.STATE_CONNECTED_FLAG |
                    ConnectProfileReceiver.STATE_CONNECTING_FLAG);
            role = BluetoothPan.LOCAL_PANU_ROLE;
        } else {
            methodName = String.format("incomingPanConnection(device=%s)", device);
            mask = ConnectProfileReceiver.STATE_CONNECTED_FLAG;
            role = BluetoothPan.LOCAL_NAP_ROLE;
        }

        if (!adapter.isEnabled()) {
            fail(String.format("%s bluetooth not enabled", methodName));
        }

        if (!adapter.getBondedDevices().contains(device)) {
            fail(String.format("%s device not paired", methodName));
        }

        mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
        assertNotNull(mPan);
        ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);

        int state = mPan.getConnectionState(device);
        switch (state) {
            case BluetoothPan.STATE_CONNECTED:
                removeReceiver(receiver);
                return;
            case BluetoothPan.STATE_CONNECTING:
                mask = 0; // Don't check for received intents since we might have missed them.
                break;
            case BluetoothPan.STATE_DISCONNECTED:
            case BluetoothPan.STATE_DISCONNECTING:
                start = System.currentTimeMillis();
                if (role == BluetoothPan.LOCAL_PANU_ROLE) {
                    Log.i("BT", "connect to pan");
                    assertTrue(mPan.connect(device));
                }
                break;
            default:
                removeReceiver(receiver);
                fail(String.format("%s invalid state: state=%d", methodName, state));
        }

        long s = System.currentTimeMillis();
        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
            state = mPan.getConnectionState(device);
            if (state == BluetoothPan.STATE_CONNECTED
                    && (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: state=%d (expected %d), flags=0x%x (expected 0x%s)",
                methodName, state, BluetoothPan.STATE_CONNECTED, firedFlags, mask));
    
public voidconnectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile, java.lang.String methodName)
Connects a profile from the local device to a remote device and checks to make sure that the profile is connected and that the correct actions were broadcast.

param
adapter The BT adapter.
param
device The remote device.
param
profile The profile to connect. One of {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#INPUT_DEVICE}.
param
methodName The method name to printed in the logs. If null, will be "connectProfile(profile=<profile>, device=<device>)"

        if (methodName == null) {
            methodName = String.format("connectProfile(profile=%d, device=%s)", profile, device);
        }
        int mask = (ConnectProfileReceiver.STATE_CONNECTING_FLAG
                | ConnectProfileReceiver.STATE_CONNECTED_FLAG);
        long start = -1;

        if (!adapter.isEnabled()) {
            fail(String.format("%s bluetooth not enabled", methodName));
        }

        if (!adapter.getBondedDevices().contains(device)) {
            fail(String.format("%s device not paired", methodName));
        }

        BluetoothProfile proxy = connectProxy(adapter, profile);
        assertNotNull(proxy);

        ConnectProfileReceiver receiver = getConnectProfileReceiver(device, profile, mask);

        int state = proxy.getConnectionState(device);
        switch (state) {
            case BluetoothProfile.STATE_CONNECTED:
                removeReceiver(receiver);
                return;
            case BluetoothProfile.STATE_CONNECTING:
                mask = 0; // Don't check for received intents since we might have missed them.
                break;
            case BluetoothProfile.STATE_DISCONNECTED:
            case BluetoothProfile.STATE_DISCONNECTING:
                start = System.currentTimeMillis();
                if (profile == BluetoothProfile.A2DP) {
                    assertTrue(((BluetoothA2dp)proxy).connect(device));
                } else if (profile == BluetoothProfile.HEADSET) {
                    assertTrue(((BluetoothHeadset)proxy).connect(device));
                } else if (profile == BluetoothProfile.INPUT_DEVICE) {
                    assertTrue(((BluetoothInputDevice)proxy).connect(device));
                }
                break;
            default:
                removeReceiver(receiver);
                fail(String.format("%s invalid state: state=%d", methodName, state));
        }

        long s = System.currentTimeMillis();
        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
            state = proxy.getConnectionState(device);
            if (state == BluetoothProfile.STATE_CONNECTED
                    && (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: state=%d (expected %d), flags=0x%x (expected 0x%x)",
                methodName, state, BluetoothProfile.STATE_CONNECTED, firedFlags, mask));
    
private android.bluetooth.BluetoothProfileconnectProxy(BluetoothAdapter adapter, int profile)

        switch (profile) {
            case BluetoothProfile.A2DP:
                if (mA2dp != null) {
                    return mA2dp;
                }
                break;
            case BluetoothProfile.HEADSET:
                if (mHeadset != null) {
                    return mHeadset;
                }
                break;
            case BluetoothProfile.INPUT_DEVICE:
                if (mInput != null) {
                    return mInput;
                }
                break;
            case BluetoothProfile.PAN:
                if (mPan != null) {
                    return mPan;
                }
                break;
            default:
                return null;
        }
        adapter.getProfileProxy(mContext, mServiceListener, profile);
        long s = System.currentTimeMillis();
        switch (profile) {
            case BluetoothProfile.A2DP:
                while (mA2dp == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
                    sleep(POLL_TIME);
                }
                return mA2dp;
            case BluetoothProfile.HEADSET:
                while (mHeadset == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
                    sleep(POLL_TIME);
                }
                return mHeadset;
            case BluetoothProfile.INPUT_DEVICE:
                while (mInput == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
                    sleep(POLL_TIME);
                }
                return mInput;
            case BluetoothProfile.PAN:
                while (mPan == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
                    sleep(POLL_TIME);
                }
                return mPan;
            default:
                return null;
        }
    
public voiddisable(BluetoothAdapter adapter)
Disables Bluetooth and checks to make sure that Bluetooth was turned off and that the correct actions were broadcast.

param
adapter The BT adapter.

        int mask = (BluetoothReceiver.STATE_TURNING_OFF_FLAG | BluetoothReceiver.STATE_OFF_FLAG
                | BluetoothReceiver.SCAN_MODE_NONE_FLAG);
        long start = -1;
        BluetoothReceiver receiver = getBluetoothReceiver(mask);

        int state = adapter.getState();
        switch (state) {
            case BluetoothAdapter.STATE_OFF:
                assertFalse(adapter.isEnabled());
                removeReceiver(receiver);
                return;
            case BluetoothAdapter.STATE_TURNING_ON:
                assertFalse(adapter.isEnabled());
                start = System.currentTimeMillis();
                break;
            case BluetoothAdapter.STATE_ON:
                assertTrue(adapter.isEnabled());
                start = System.currentTimeMillis();
                assertTrue(adapter.disable());
                break;
            case BluetoothAdapter.STATE_TURNING_OFF:
                assertFalse(adapter.isEnabled());
                mask = 0; // Don't check for received intents since we might have missed them.
                break;
            default:
                removeReceiver(receiver);
                fail(String.format("disable() invalid state: state=%d", state));
        }

        long s = System.currentTimeMillis();
        while (System.currentTimeMillis() - s < ENABLE_DISABLE_TIMEOUT) {
            state = adapter.getState();
            if (state == BluetoothAdapter.STATE_OFF
                    && (receiver.getFiredFlags() & mask) == mask) {
                assertFalse(adapter.isEnabled());
                long finish = receiver.getCompletedTime();
                if (start != -1 && finish != -1) {
                    writeOutput(String.format("disable() completed in %d ms", (finish - start)));
                } else {
                    writeOutput("disable() completed");
                }
                removeReceiver(receiver);
                return;
            }
            sleep(POLL_TIME);
        }

        int firedFlags = receiver.getFiredFlags();
        removeReceiver(receiver);
        fail(String.format("disable() timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
                state, BluetoothAdapter.STATE_OFF, firedFlags, mask));
    
public voiddisablePan(BluetoothAdapter adapter)
Disables PAN tethering on the local device and checks to make sure that tethering is disabled.

param
adapter The BT adapter.

        if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
        assertNotNull(mPan);

        long start = System.currentTimeMillis();
        mPan.setBluetoothTethering(false);
        long stop = System.currentTimeMillis();
        assertFalse(mPan.isTetheringOn());

        writeOutput(String.format("disablePan() completed in %d ms", (stop - start)));
    
private voiddisconnectFromRemoteOrVerifyConnectNap(BluetoothAdapter adapter, BluetoothDevice device, boolean disconnect)
Helper method used by {@link #disconnectPan(BluetoothAdapter, BluetoothDevice)} and {@link #incomingPanDisconnection(BluetoothAdapter, BluetoothDevice)} to either disconnect from a remote NAP or verify that a remote device disconnected from the local NAP.

param
adapter The BT adapter.
param
device The remote device.
param
disconnect Whether the method should connect or verify.

        long start = -1;
        int mask, role;
        String methodName;

        if (disconnect) {
            methodName = String.format("disconnectPan(device=%s)", device);
            mask = (ConnectProfileReceiver.STATE_DISCONNECTED_FLAG |
                    ConnectProfileReceiver.STATE_DISCONNECTING_FLAG);
            role = BluetoothPan.LOCAL_PANU_ROLE;
        } else {
            methodName = String.format("incomingPanDisconnection(device=%s)", device);
            mask = ConnectProfileReceiver.STATE_DISCONNECTED_FLAG;
            role = BluetoothPan.LOCAL_NAP_ROLE;
        }

        if (!adapter.isEnabled()) {
            fail(String.format("%s bluetooth not enabled", methodName));
        }

        if (!adapter.getBondedDevices().contains(device)) {
            fail(String.format("%s device not paired", methodName));
        }

        mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
        assertNotNull(mPan);
        ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);

        int state = mPan.getConnectionState(device);
        switch (state) {
            case BluetoothPan.STATE_CONNECTED:
            case BluetoothPan.STATE_CONNECTING:
                start = System.currentTimeMillis();
                if (role == BluetoothPan.LOCAL_PANU_ROLE) {
                    assertTrue(mPan.disconnect(device));
                }
                break;
            case BluetoothPan.STATE_DISCONNECTED:
                removeReceiver(receiver);
                return;
            case BluetoothPan.STATE_DISCONNECTING:
                mask = 0; // Don't check for received intents since we might have missed them.
                break;
            default:
                removeReceiver(receiver);
                fail(String.format("%s invalid state: state=%d", methodName, state));
        }

        long s = System.currentTimeMillis();
        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
            state = mPan.getConnectionState(device);
            if (state == BluetoothInputDevice.STATE_DISCONNECTED
                    && (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: state=%d (expected %d), flags=0x%x (expected 0x%s)",
                methodName, state, BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
    
public voiddisconnectPan(BluetoothAdapter adapter, BluetoothDevice device)
Disconnects the PANU from a remote NAP and checks to make sure that the PANU is disconnected and that the correct actions were broadcast.

param
adapter The BT adapter.
param
device The remote device.

        disconnectFromRemoteOrVerifyConnectNap(adapter, device, true);
    
public voiddisconnectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile, java.lang.String methodName)
Disconnects a profile between the local device and a remote device and checks to make sure that the profile is disconnected and that the correct actions were broadcast.

param
adapter The BT adapter.
param
device The remote device.
param
profile The profile to disconnect. One of {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#INPUT_DEVICE}.
param
methodName The method name to printed in the logs. If null, will be "connectProfile(profile=<profile>, device=<device>)"

        if (methodName == null) {
            methodName = String.format("disconnectProfile(profile=%d, device=%s)", profile, device);
        }
        int mask = (ConnectProfileReceiver.STATE_DISCONNECTING_FLAG
                | ConnectProfileReceiver.STATE_DISCONNECTED_FLAG);
        long start = -1;

        if (!adapter.isEnabled()) {
            fail(String.format("%s bluetooth not enabled", methodName));
        }

        if (!adapter.getBondedDevices().contains(device)) {
            fail(String.format("%s device not paired", methodName));
        }

        BluetoothProfile proxy = connectProxy(adapter, profile);
        assertNotNull(proxy);

        ConnectProfileReceiver receiver = getConnectProfileReceiver(device, profile, mask);

        int state = proxy.getConnectionState(device);
        switch (state) {
            case BluetoothProfile.STATE_CONNECTED:
            case BluetoothProfile.STATE_CONNECTING:
                start = System.currentTimeMillis();
                if (profile == BluetoothProfile.A2DP) {
                    assertTrue(((BluetoothA2dp)proxy).disconnect(device));
                } else if (profile == BluetoothProfile.HEADSET) {
                    assertTrue(((BluetoothHeadset)proxy).disconnect(device));
                } else if (profile == BluetoothProfile.INPUT_DEVICE) {
                    assertTrue(((BluetoothInputDevice)proxy).disconnect(device));
                }
                break;
            case BluetoothProfile.STATE_DISCONNECTED:
                removeReceiver(receiver);
                return;
            case BluetoothProfile.STATE_DISCONNECTING:
                mask = 0; // Don't check for received intents since we might have missed them.
                break;
            default:
                removeReceiver(receiver);
                fail(String.format("%s invalid state: state=%d", methodName, state));
        }

        long s = System.currentTimeMillis();
        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
            state = proxy.getConnectionState(device);
            if (state == BluetoothProfile.STATE_DISCONNECTED
                    && (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: state=%d (expected %d), flags=0x%x (expected 0x%x)",
                methodName, state, BluetoothProfile.STATE_DISCONNECTED, firedFlags, mask));
    
public voiddiscoverable(BluetoothAdapter adapter)
Puts the local device into discoverable mode and checks to make sure that the local device is in discoverable mode and that the correct actions were broadcast.

param
adapter The BT adapter.

        int mask = BluetoothReceiver.SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG;

        if (!adapter.isEnabled()) {
            fail("discoverable() bluetooth not enabled");
        }

        int scanMode = adapter.getScanMode();
        if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
            return;
        }

        BluetoothReceiver receiver = getBluetoothReceiver(mask);

        assertEquals(BluetoothAdapter.SCAN_MODE_CONNECTABLE, scanMode);
        long start = System.currentTimeMillis();
        assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE));

        while (System.currentTimeMillis() - start < DISCOVERABLE_UNDISCOVERABLE_TIMEOUT) {
            scanMode = adapter.getScanMode();
            if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE
                    && (receiver.getFiredFlags() & mask) == mask) {
                writeOutput(String.format("discoverable() completed in %d ms",
                        (receiver.getCompletedTime() - start)));
                removeReceiver(receiver);
                return;
            }
            sleep(POLL_TIME);
        }

        int firedFlags = receiver.getFiredFlags();
        removeReceiver(receiver);
        fail(String.format("discoverable() timeout: scanMode=%d (expected %d), flags=0x%x "
                + "(expected 0x%x)", scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE,
                firedFlags, mask));
    
public voidenable(BluetoothAdapter adapter)
Enables Bluetooth and checks to make sure that Bluetooth was turned on and that the correct actions were broadcast.

param
adapter The BT adapter.

        int mask = (BluetoothReceiver.STATE_TURNING_ON_FLAG | BluetoothReceiver.STATE_ON_FLAG
                | BluetoothReceiver.SCAN_MODE_CONNECTABLE_FLAG);
        long start = -1;
        BluetoothReceiver receiver = getBluetoothReceiver(mask);

        int state = adapter.getState();
        switch (state) {
            case BluetoothAdapter.STATE_ON:
                assertTrue(adapter.isEnabled());
                removeReceiver(receiver);
                return;
            case BluetoothAdapter.STATE_TURNING_ON:
                assertFalse(adapter.isEnabled());
                mask = 0; // Don't check for received intents since we might have missed them.
                break;
            case BluetoothAdapter.STATE_OFF:
                assertFalse(adapter.isEnabled());
                start = System.currentTimeMillis();
                assertTrue(adapter.enable());
                break;
            case BluetoothAdapter.STATE_TURNING_OFF:
                start = System.currentTimeMillis();
                assertTrue(adapter.enable());
                break;
            default:
                removeReceiver(receiver);
                fail(String.format("enable() invalid state: state=%d", state));
        }

        long s = System.currentTimeMillis();
        while (System.currentTimeMillis() - s < ENABLE_DISABLE_TIMEOUT) {
            state = adapter.getState();
            if (state == BluetoothAdapter.STATE_ON
                    && (receiver.getFiredFlags() & mask) == mask) {
                assertTrue(adapter.isEnabled());
                long finish = receiver.getCompletedTime();
                if (start != -1 && finish != -1) {
                    writeOutput(String.format("enable() completed in %d ms", (finish - start)));
                } else {
                    writeOutput("enable() completed");
                }
                removeReceiver(receiver);
                return;
            }
            sleep(POLL_TIME);
        }

        int firedFlags = receiver.getFiredFlags();
        removeReceiver(receiver);
        fail(String.format("enable() timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
                state, BluetoothAdapter.STATE_ON, firedFlags, mask));
    
public voidenablePan(BluetoothAdapter adapter)
Enables PAN tethering on the local device and checks to make sure that tethering is enabled.

param
adapter The BT adapter.

        if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
        assertNotNull(mPan);

        long start = System.currentTimeMillis();
        mPan.setBluetoothTethering(true);
        long stop = System.currentTimeMillis();
        assertTrue(mPan.isTetheringOn());

        writeOutput(String.format("enablePan() completed in %d ms", (stop - start)));
    
private android.bluetooth.BluetoothTestUtils$BluetoothReceivergetBluetoothReceiver(int expectedFlags)

        String[] actions = {
                BluetoothAdapter.ACTION_DISCOVERY_FINISHED,
                BluetoothAdapter.ACTION_DISCOVERY_STARTED,
                BluetoothAdapter.ACTION_SCAN_MODE_CHANGED,
                BluetoothAdapter.ACTION_STATE_CHANGED};
        BluetoothReceiver receiver = new BluetoothReceiver(expectedFlags);
        addReceiver(receiver, actions);
        return receiver;
    
private android.bluetooth.BluetoothTestUtils$ConnectPanReceivergetConnectPanReceiver(BluetoothDevice device, int role, int expectedFlags)

        String[] actions = {BluetoothPan.ACTION_CONNECTION_STATE_CHANGED};
        ConnectPanReceiver receiver = new ConnectPanReceiver(device, role, expectedFlags);
        addReceiver(receiver, actions);
        return receiver;
    
private android.bluetooth.BluetoothTestUtils$ConnectProfileReceivergetConnectProfileReceiver(BluetoothDevice device, int profile, int expectedFlags)

        String[] actions = {
                BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED,
                BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED,
                BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED};
        ConnectProfileReceiver receiver = new ConnectProfileReceiver(device, profile,
                expectedFlags);
        addReceiver(receiver, actions);
        return receiver;
    
private android.bluetooth.BluetoothTestUtils$PairReceivergetPairReceiver(BluetoothDevice device, int passkey, byte[] pin, int expectedFlags)

        String[] actions = {
                BluetoothDevice.ACTION_PAIRING_REQUEST,
                BluetoothDevice.ACTION_BOND_STATE_CHANGED};
        PairReceiver receiver = new PairReceiver(device, passkey, pin, expectedFlags);
        addReceiver(receiver, actions);
        return receiver;
    
private android.bluetooth.BluetoothTestUtils$StartStopScoReceivergetStartStopScoReceiver(int expectedFlags)

        String[] actions = {AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED};
        StartStopScoReceiver receiver = new StartStopScoReceiver(expectedFlags);
        addReceiver(receiver, actions);
        return receiver;
    
public voidincomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device)
Checks that a remote PANU connects to the local NAP correctly and that the correct actions were broadcast.

param
adapter The BT adapter.
param
device The remote device.

        connectPanOrIncomingPanConnection(adapter, device, false);
    
public voidincomingPanDisconnection(BluetoothAdapter adapter, BluetoothDevice device)
Checks that a remote PANU disconnects from the local NAP correctly and that the correct actions were broadcast.

param
adapter The BT adapter.
param
device The remote device.

        disconnectFromRemoteOrVerifyConnectNap(adapter, device, false);
    
public voidpair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, byte[] pin)
Initiates a pairing with a remote device and checks to make sure that the devices are paired and that the correct actions were broadcast.

param
adapter The BT adapter.
param
device The remote device.
param
passkey The pairing passkey if pairing requires a passkey. Any value if not.
param
pin The pairing pin if pairing requires a pin. Any value if not.

        pairOrAcceptPair(adapter, device, passkey, pin, true);
    
private voidpairOrAcceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, byte[] pin, boolean shouldPair)
Helper method used by {@link #pair(BluetoothAdapter, BluetoothDevice, int, byte[])} and {@link #acceptPair(BluetoothAdapter, BluetoothDevice, int, byte[])} to either pair or accept a pairing request.

param
adapter The BT adapter.
param
device The remote device.
param
passkey The pairing passkey if pairing requires a passkey. Any value if not.
param
pin The pairing pin if pairing requires a pin. Any value if not.
param
shouldPair Whether to pair or accept the pair.

        int mask = PairReceiver.STATE_BONDING_FLAG | PairReceiver.STATE_BONDED_FLAG;
        long start = -1;
        String methodName;
        if (shouldPair) {
            methodName = String.format("pair(device=%s)", device);
        } else {
            methodName = String.format("acceptPair(device=%s)", device);
        }

        if (!adapter.isEnabled()) {
            fail(String.format("%s bluetooth not enabled", methodName));
        }

        PairReceiver receiver = getPairReceiver(device, passkey, pin, mask);

        int state = device.getBondState();
        switch (state) {
            case BluetoothDevice.BOND_NONE:
                assertFalse(adapter.getBondedDevices().contains(device));
                start = System.currentTimeMillis();
                if (shouldPair) {
                    assertTrue(device.createBond());
                }
                break;
            case BluetoothDevice.BOND_BONDING:
                mask = 0; // Don't check for received intents since we might have missed them.
                break;
            case BluetoothDevice.BOND_BONDED:
                assertTrue(adapter.getBondedDevices().contains(device));
                return;
            default:
                removeReceiver(receiver);
                fail(String.format("%s invalid state: state=%d", methodName, state));
        }

        long s = System.currentTimeMillis();
        while (System.currentTimeMillis() - s < PAIR_UNPAIR_TIMEOUT) {
            state = device.getBondState();
            if (state == BluetoothDevice.BOND_BONDED && (receiver.getFiredFlags() & mask) == mask) {
                assertTrue(adapter.getBondedDevices().contains(device));
                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: state=%d (expected %d), flags=0x%x (expected 0x%x)",
                methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask));
    
private voidremoveReceiver(android.content.BroadcastReceiver receiver)

        mContext.unregisterReceiver(receiver);
        mReceivers.remove(receiver);
    
private voidsleep(long time)

        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
        }
    
public voidstartScan(BluetoothAdapter adapter)
Starts a scan for remote devices and checks to make sure that the local device is scanning and that the correct actions were broadcast.

param
adapter The BT adapter.

        int mask = BluetoothReceiver.DISCOVERY_STARTED_FLAG;

        if (!adapter.isEnabled()) {
            fail("startScan() bluetooth not enabled");
        }

        if (adapter.isDiscovering()) {
            return;
        }

        BluetoothReceiver receiver = getBluetoothReceiver(mask);

        long start = System.currentTimeMillis();
        assertTrue(adapter.startDiscovery());

        while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) {
            if (adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) {
                writeOutput(String.format("startScan() completed in %d ms",
                        (receiver.getCompletedTime() - start)));
                removeReceiver(receiver);
                return;
            }
            sleep(POLL_TIME);
        }

        int firedFlags = receiver.getFiredFlags();
        removeReceiver(receiver);
        fail(String.format("startScan() timeout: isDiscovering=%b, flags=0x%x (expected 0x%x)",
                adapter.isDiscovering(), firedFlags, mask));
    
public voidstartSco(BluetoothAdapter adapter, BluetoothDevice device)
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.

        startStopSco(adapter, device, true);
    
private voidstartStopSco(BluetoothAdapter adapter, BluetoothDevice device, boolean isStart)
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.

        long start = -1;
        int mask;
        String methodName;

        if (isStart) {
            methodName = String.format("startSco(device=%s)", device);
            mask = StartStopScoReceiver.STATE_CONNECTED_FLAG;
        } else {
            methodName = String.format("stopSco(device=%s)", device);
            mask = StartStopScoReceiver.STATE_DISCONNECTED_FLAG;
        }

        if (!adapter.isEnabled()) {
            fail(String.format("%s bluetooth not enabled", methodName));
        }

        if (!adapter.getBondedDevices().contains(device)) {
            fail(String.format("%s device not paired", methodName));
        }

        AudioManager manager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
        assertNotNull(manager);

        if (!manager.isBluetoothScoAvailableOffCall()) {
            fail(String.format("%s device does not support SCO", methodName));
        }

        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: on=%b (expected %b), flags=0x%x (expected 0x%x)",
                methodName, isScoOn, isStart, firedFlags, mask));
    
public voidstopScan(BluetoothAdapter adapter)
Stops a scan for remote devices and checks to make sure that the local device is not scanning and that the correct actions were broadcast.

param
adapter The BT adapter.

        int mask = BluetoothReceiver.DISCOVERY_FINISHED_FLAG;

        if (!adapter.isEnabled()) {
            fail("stopScan() bluetooth not enabled");
        }

        if (!adapter.isDiscovering()) {
            return;
        }

        BluetoothReceiver receiver = getBluetoothReceiver(mask);

        long start = System.currentTimeMillis();
        assertTrue(adapter.cancelDiscovery());

        while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) {
            if (!adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) {
                writeOutput(String.format("stopScan() completed in %d ms",
                        (receiver.getCompletedTime() - start)));
                removeReceiver(receiver);
                return;
            }
            sleep(POLL_TIME);
        }

        int firedFlags = receiver.getFiredFlags();
        removeReceiver(receiver);
        fail(String.format("stopScan() timeout: isDiscovering=%b, flags=0x%x (expected 0x%x)",
                adapter.isDiscovering(), firedFlags, mask));

    
public voidstopSco(BluetoothAdapter adapter, BluetoothDevice device)
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.

        startStopSco(adapter, device, false);
    
public voidundiscoverable(BluetoothAdapter adapter)
Puts the local device into connectable only mode and checks to make sure that the local device is in in connectable mode and that the correct actions were broadcast.

param
adapter The BT adapter.

        int mask = BluetoothReceiver.SCAN_MODE_CONNECTABLE_FLAG;

        if (!adapter.isEnabled()) {
            fail("undiscoverable() bluetooth not enabled");
        }

        int scanMode = adapter.getScanMode();
        if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
            return;
        }

        BluetoothReceiver receiver = getBluetoothReceiver(mask);

        assertEquals(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, scanMode);
        long start = System.currentTimeMillis();
        assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE));

        while (System.currentTimeMillis() - start < DISCOVERABLE_UNDISCOVERABLE_TIMEOUT) {
            scanMode = adapter.getScanMode();
            if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE
                    && (receiver.getFiredFlags() & mask) == mask) {
                writeOutput(String.format("undiscoverable() completed in %d ms",
                        (receiver.getCompletedTime() - start)));
                removeReceiver(receiver);
                return;
            }
            sleep(POLL_TIME);
        }

        int firedFlags = receiver.getFiredFlags();
        removeReceiver(receiver);
        fail(String.format("undiscoverable() timeout: scanMode=%d (expected %d), flags=0x%x "
                + "(expected 0x%x)", scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE, firedFlags,
                mask));
    
public voidunpair(BluetoothAdapter adapter, BluetoothDevice device)
Deletes a pairing with a remote device and checks to make sure that the devices are unpaired and that the correct actions were broadcast.

param
adapter The BT adapter.
param
device The remote device.

        int mask = PairReceiver.STATE_NONE_FLAG;
        long start = -1;
        String methodName = String.format("unpair(device=%s)", device);

        if (!adapter.isEnabled()) {
            fail(String.format("%s bluetooth not enabled", methodName));
        }

        PairReceiver receiver = getPairReceiver(device, 0, null, mask);

        int state = device.getBondState();
        switch (state) {
            case BluetoothDevice.BOND_NONE:
                assertFalse(adapter.getBondedDevices().contains(device));
                removeReceiver(receiver);
                return;
            case BluetoothDevice.BOND_BONDING:
                start = System.currentTimeMillis();
                assertTrue(device.removeBond());
                break;
            case BluetoothDevice.BOND_BONDED:
                assertTrue(adapter.getBondedDevices().contains(device));
                start = System.currentTimeMillis();
                assertTrue(device.removeBond());
                break;
            default:
                removeReceiver(receiver);
                fail(String.format("%s invalid state: state=%d", methodName, state));
        }

        long s = System.currentTimeMillis();
        while (System.currentTimeMillis() - s < PAIR_UNPAIR_TIMEOUT) {
            if (device.getBondState() == BluetoothDevice.BOND_NONE
                    && (receiver.getFiredFlags() & mask) == mask) {
                assertFalse(adapter.getBondedDevices().contains(device));
                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;
            }
        }

        int firedFlags = receiver.getFiredFlags();
        removeReceiver(receiver);
        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
                methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask));
    
public voidunpairAll(BluetoothAdapter adapter)
Deletes all pairings of remote devices

param
adapter the BT adapter

        Set<BluetoothDevice> devices = adapter.getBondedDevices();
        for (BluetoothDevice device : devices) {
            unpair(adapter, device);
        }
    
public voidwriteOutput(java.lang.String s)
Writes a string to the logcat and a file if a file has been specified in the constructor.

param
s The string to be written.

        Log.i(mTag, s);
        if (mOutputWriter == null) {
            return;
        }
        try {
            mOutputWriter.write(s + "\n");
            mOutputWriter.flush();
        } catch (IOException e) {
            Log.w(mTag, "Could not write to output file", e);
        }