2 * Copyright (C) 2010 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package android.bluetooth;
19 import android.bluetooth.BluetoothPan;
20 import android.bluetooth.BluetoothProfile;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.media.AudioManager;
26 import android.os.Environment;
27 import android.util.Log;
29 import junit.framework.Assert;
31 import java.io.BufferedWriter;
33 import java.io.FileWriter;
34 import java.io.IOException;
35 import java.util.ArrayList;
36 import java.util.List;
39 public class BluetoothTestUtils extends Assert {
41 /** Timeout for enable/disable in ms. */
42 private static final int ENABLE_DISABLE_TIMEOUT = 20000;
43 /** Timeout for discoverable/undiscoverable in ms. */
44 private static final int DISCOVERABLE_UNDISCOVERABLE_TIMEOUT = 5000;
45 /** Timeout for starting/stopping a scan in ms. */
46 private static final int START_STOP_SCAN_TIMEOUT = 5000;
47 /** Timeout for pair/unpair in ms. */
48 private static final int PAIR_UNPAIR_TIMEOUT = 20000;
49 /** Timeout for connecting/disconnecting a profile in ms. */
50 private static final int CONNECT_DISCONNECT_PROFILE_TIMEOUT = 20000;
51 /** Timeout to start or stop a SCO channel in ms. */
52 private static final int START_STOP_SCO_TIMEOUT = 10000;
53 /** Timeout to connect a profile proxy in ms. */
54 private static final int CONNECT_PROXY_TIMEOUT = 5000;
55 /** Time between polls in ms. */
56 private static final int POLL_TIME = 100;
58 private abstract class FlagReceiver extends BroadcastReceiver {
59 private int mExpectedFlags = 0;
60 private int mFiredFlags = 0;
61 private long mCompletedTime = -1;
63 public FlagReceiver(int expectedFlags) {
64 mExpectedFlags = expectedFlags;
67 public int getFiredFlags() {
73 public long getCompletedTime() {
75 return mCompletedTime;
79 protected void setFiredFlag(int flag) {
82 if ((mFiredFlags & mExpectedFlags) == mExpectedFlags) {
83 mCompletedTime = System.currentTimeMillis();
89 private class BluetoothReceiver extends FlagReceiver {
90 private static final int DISCOVERY_STARTED_FLAG = 1;
91 private static final int DISCOVERY_FINISHED_FLAG = 1 << 1;
92 private static final int SCAN_MODE_NONE_FLAG = 1 << 2;
93 private static final int SCAN_MODE_CONNECTABLE_FLAG = 1 << 3;
94 private static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG = 1 << 4;
95 private static final int STATE_OFF_FLAG = 1 << 5;
96 private static final int STATE_TURNING_ON_FLAG = 1 << 6;
97 private static final int STATE_ON_FLAG = 1 << 7;
98 private static final int STATE_TURNING_OFF_FLAG = 1 << 8;
100 public BluetoothReceiver(int expectedFlags) {
101 super(expectedFlags);
105 public void onReceive(Context context, Intent intent) {
106 if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(intent.getAction())) {
107 setFiredFlag(DISCOVERY_STARTED_FLAG);
108 } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(intent.getAction())) {
109 setFiredFlag(DISCOVERY_FINISHED_FLAG);
110 } else if (BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(intent.getAction())) {
111 int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, -1);
112 assertNotSame(-1, mode);
114 case BluetoothAdapter.SCAN_MODE_NONE:
115 setFiredFlag(SCAN_MODE_NONE_FLAG);
117 case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
118 setFiredFlag(SCAN_MODE_CONNECTABLE_FLAG);
120 case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
121 setFiredFlag(SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG);
124 } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
125 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
126 assertNotSame(-1, state);
128 case BluetoothAdapter.STATE_OFF:
129 setFiredFlag(STATE_OFF_FLAG);
131 case BluetoothAdapter.STATE_TURNING_ON:
132 setFiredFlag(STATE_TURNING_ON_FLAG);
134 case BluetoothAdapter.STATE_ON:
135 setFiredFlag(STATE_ON_FLAG);
137 case BluetoothAdapter.STATE_TURNING_OFF:
138 setFiredFlag(STATE_TURNING_OFF_FLAG);
145 private class PairReceiver extends FlagReceiver {
146 private static final int STATE_BONDED_FLAG = 1;
147 private static final int STATE_BONDING_FLAG = 1 << 1;
148 private static final int STATE_NONE_FLAG = 1 << 2;
150 private BluetoothDevice mDevice;
151 private int mPasskey;
154 public PairReceiver(BluetoothDevice device, int passkey, byte[] pin, int expectedFlags) {
155 super(expectedFlags);
163 public void onReceive(Context context, Intent intent) {
164 if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))) {
168 if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction())) {
169 int varient = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, -1);
170 assertNotSame(-1, varient);
172 case BluetoothDevice.PAIRING_VARIANT_PIN:
173 case BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS:
174 mDevice.setPin(mPin);
176 case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
177 mDevice.setPasskey(mPasskey);
179 case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
180 case BluetoothDevice.PAIRING_VARIANT_CONSENT:
181 mDevice.setPairingConfirmation(true);
183 case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT:
184 mDevice.setRemoteOutOfBandData();
187 } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())) {
188 int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
189 assertNotSame(-1, state);
191 case BluetoothDevice.BOND_NONE:
192 setFiredFlag(STATE_NONE_FLAG);
194 case BluetoothDevice.BOND_BONDING:
195 setFiredFlag(STATE_BONDING_FLAG);
197 case BluetoothDevice.BOND_BONDED:
198 setFiredFlag(STATE_BONDED_FLAG);
205 private class ConnectProfileReceiver extends FlagReceiver {
206 private static final int STATE_DISCONNECTED_FLAG = 1;
207 private static final int STATE_CONNECTING_FLAG = 1 << 1;
208 private static final int STATE_CONNECTED_FLAG = 1 << 2;
209 private static final int STATE_DISCONNECTING_FLAG = 1 << 3;
211 private BluetoothDevice mDevice;
212 private int mProfile;
213 private String mConnectionAction;
215 public ConnectProfileReceiver(BluetoothDevice device, int profile, int expectedFlags) {
216 super(expectedFlags);
222 case BluetoothProfile.A2DP:
223 mConnectionAction = BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED;
225 case BluetoothProfile.HEADSET:
226 mConnectionAction = BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED;
228 case BluetoothProfile.INPUT_DEVICE:
229 mConnectionAction = BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED;
231 case BluetoothProfile.PAN:
232 mConnectionAction = BluetoothPan.ACTION_CONNECTION_STATE_CHANGED;
235 mConnectionAction = null;
240 public void onReceive(Context context, Intent intent) {
241 if (mConnectionAction != null && mConnectionAction.equals(intent.getAction())) {
242 if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))) {
246 int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
247 assertNotSame(-1, state);
249 case BluetoothProfile.STATE_DISCONNECTED:
250 setFiredFlag(STATE_DISCONNECTED_FLAG);
252 case BluetoothProfile.STATE_CONNECTING:
253 setFiredFlag(STATE_CONNECTING_FLAG);
255 case BluetoothProfile.STATE_CONNECTED:
256 setFiredFlag(STATE_CONNECTED_FLAG);
258 case BluetoothProfile.STATE_DISCONNECTING:
259 setFiredFlag(STATE_DISCONNECTING_FLAG);
266 private class ConnectPanReceiver extends ConnectProfileReceiver {
269 public ConnectPanReceiver(BluetoothDevice device, int role, int expectedFlags) {
270 super(device, BluetoothProfile.PAN, expectedFlags);
276 public void onReceive(Context context, Intent intent) {
277 if (mRole != intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, -1)) {
281 super.onReceive(context, intent);
285 private class StartStopScoReceiver extends FlagReceiver {
286 private static final int STATE_CONNECTED_FLAG = 1;
287 private static final int STATE_DISCONNECTED_FLAG = 1 << 1;
289 public StartStopScoReceiver(int expectedFlags) {
290 super(expectedFlags);
294 public void onReceive(Context context, Intent intent) {
295 if (AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED.equals(intent.getAction())) {
296 int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
297 AudioManager.SCO_AUDIO_STATE_ERROR);
298 assertNotSame(AudioManager.SCO_AUDIO_STATE_ERROR, state);
300 case AudioManager.SCO_AUDIO_STATE_CONNECTED:
301 setFiredFlag(STATE_CONNECTED_FLAG);
303 case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:
304 setFiredFlag(STATE_DISCONNECTED_FLAG);
311 private BluetoothProfile.ServiceListener mServiceListener =
312 new BluetoothProfile.ServiceListener() {
314 public void onServiceConnected(int profile, BluetoothProfile proxy) {
315 synchronized (this) {
317 case BluetoothProfile.A2DP:
318 mA2dp = (BluetoothA2dp) proxy;
320 case BluetoothProfile.HEADSET:
321 mHeadset = (BluetoothHeadset) proxy;
323 case BluetoothProfile.INPUT_DEVICE:
324 mInput = (BluetoothInputDevice) proxy;
326 case BluetoothProfile.PAN:
327 mPan = (BluetoothPan) proxy;
334 public void onServiceDisconnected(int profile) {
335 synchronized (this) {
337 case BluetoothProfile.A2DP:
340 case BluetoothProfile.HEADSET:
343 case BluetoothProfile.INPUT_DEVICE:
346 case BluetoothProfile.PAN:
354 private List<BroadcastReceiver> mReceivers = new ArrayList<BroadcastReceiver>();
356 private BufferedWriter mOutputWriter;
358 private String mOutputFile;
360 private Context mContext;
361 private BluetoothA2dp mA2dp = null;
362 private BluetoothHeadset mHeadset = null;
363 private BluetoothInputDevice mInput = null;
364 private BluetoothPan mPan = null;
367 * Creates a utility instance for testing Bluetooth.
369 * @param context The context of the application using the utility.
370 * @param tag The log tag of the application using the utility.
372 public BluetoothTestUtils(Context context, String tag) {
373 this(context, tag, null);
377 * Creates a utility instance for testing Bluetooth.
379 * @param context The context of the application using the utility.
380 * @param tag The log tag of the application using the utility.
381 * @param outputFile The path to an output file if the utility is to write results to a
384 public BluetoothTestUtils(Context context, String tag, String outputFile) {
387 mOutputFile = outputFile;
389 if (mOutputFile == null) {
390 mOutputWriter = null;
393 mOutputWriter = new BufferedWriter(new FileWriter(new File(
394 Environment.getExternalStorageDirectory(), mOutputFile), true));
395 } catch (IOException e) {
396 Log.w(mTag, "Test output file could not be opened", e);
397 mOutputWriter = null;
403 * Closes the utility instance and unregisters any BroadcastReceivers.
405 public void close() {
406 while (!mReceivers.isEmpty()) {
407 mContext.unregisterReceiver(mReceivers.remove(0));
410 if (mOutputWriter != null) {
412 mOutputWriter.close();
413 } catch (IOException e) {
414 Log.w(mTag, "Test output file could not be closed", e);
420 * Enables Bluetooth and checks to make sure that Bluetooth was turned on and that the correct
421 * actions were broadcast.
423 * @param adapter The BT adapter.
425 public void enable(BluetoothAdapter adapter) {
426 int mask = (BluetoothReceiver.STATE_TURNING_ON_FLAG | BluetoothReceiver.STATE_ON_FLAG
427 | BluetoothReceiver.SCAN_MODE_CONNECTABLE_FLAG);
429 BluetoothReceiver receiver = getBluetoothReceiver(mask);
431 int state = adapter.getState();
433 case BluetoothAdapter.STATE_ON:
434 assertTrue(adapter.isEnabled());
435 removeReceiver(receiver);
437 case BluetoothAdapter.STATE_TURNING_ON:
438 assertFalse(adapter.isEnabled());
439 mask = 0; // Don't check for received intents since we might have missed them.
441 case BluetoothAdapter.STATE_OFF:
442 assertFalse(adapter.isEnabled());
443 start = System.currentTimeMillis();
444 assertTrue(adapter.enable());
446 case BluetoothAdapter.STATE_TURNING_OFF:
447 start = System.currentTimeMillis();
448 assertTrue(adapter.enable());
451 removeReceiver(receiver);
452 fail(String.format("enable() invalid state: state=%d", state));
455 long s = System.currentTimeMillis();
456 while (System.currentTimeMillis() - s < ENABLE_DISABLE_TIMEOUT) {
457 state = adapter.getState();
458 if (state == BluetoothAdapter.STATE_ON
459 && (receiver.getFiredFlags() & mask) == mask) {
460 assertTrue(adapter.isEnabled());
461 long finish = receiver.getCompletedTime();
462 if (start != -1 && finish != -1) {
463 writeOutput(String.format("enable() completed in %d ms", (finish - start)));
465 writeOutput("enable() completed");
467 removeReceiver(receiver);
473 int firedFlags = receiver.getFiredFlags();
474 removeReceiver(receiver);
475 fail(String.format("enable() timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
476 state, BluetoothAdapter.STATE_ON, firedFlags, mask));
480 * Disables Bluetooth and checks to make sure that Bluetooth was turned off and that the correct
481 * actions were broadcast.
483 * @param adapter The BT adapter.
485 public void disable(BluetoothAdapter adapter) {
486 int mask = (BluetoothReceiver.STATE_TURNING_OFF_FLAG | BluetoothReceiver.STATE_OFF_FLAG
487 | BluetoothReceiver.SCAN_MODE_NONE_FLAG);
489 BluetoothReceiver receiver = getBluetoothReceiver(mask);
491 int state = adapter.getState();
493 case BluetoothAdapter.STATE_OFF:
494 assertFalse(adapter.isEnabled());
495 removeReceiver(receiver);
497 case BluetoothAdapter.STATE_TURNING_ON:
498 assertFalse(adapter.isEnabled());
499 start = System.currentTimeMillis();
501 case BluetoothAdapter.STATE_ON:
502 assertTrue(adapter.isEnabled());
503 start = System.currentTimeMillis();
504 assertTrue(adapter.disable());
506 case BluetoothAdapter.STATE_TURNING_OFF:
507 assertFalse(adapter.isEnabled());
508 mask = 0; // Don't check for received intents since we might have missed them.
511 removeReceiver(receiver);
512 fail(String.format("disable() invalid state: state=%d", state));
515 long s = System.currentTimeMillis();
516 while (System.currentTimeMillis() - s < ENABLE_DISABLE_TIMEOUT) {
517 state = adapter.getState();
518 if (state == BluetoothAdapter.STATE_OFF
519 && (receiver.getFiredFlags() & mask) == mask) {
520 assertFalse(adapter.isEnabled());
521 long finish = receiver.getCompletedTime();
522 if (start != -1 && finish != -1) {
523 writeOutput(String.format("disable() completed in %d ms", (finish - start)));
525 writeOutput("disable() completed");
527 removeReceiver(receiver);
533 int firedFlags = receiver.getFiredFlags();
534 removeReceiver(receiver);
535 fail(String.format("disable() timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
536 state, BluetoothAdapter.STATE_OFF, firedFlags, mask));
540 * Puts the local device into discoverable mode and checks to make sure that the local device
541 * is in discoverable mode and that the correct actions were broadcast.
543 * @param adapter The BT adapter.
545 public void discoverable(BluetoothAdapter adapter) {
546 int mask = BluetoothReceiver.SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG;
548 if (!adapter.isEnabled()) {
549 fail("discoverable() bluetooth not enabled");
552 int scanMode = adapter.getScanMode();
553 if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
557 BluetoothReceiver receiver = getBluetoothReceiver(mask);
559 assertEquals(BluetoothAdapter.SCAN_MODE_CONNECTABLE, scanMode);
560 long start = System.currentTimeMillis();
561 assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE));
563 while (System.currentTimeMillis() - start < DISCOVERABLE_UNDISCOVERABLE_TIMEOUT) {
564 scanMode = adapter.getScanMode();
565 if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE
566 && (receiver.getFiredFlags() & mask) == mask) {
567 writeOutput(String.format("discoverable() completed in %d ms",
568 (receiver.getCompletedTime() - start)));
569 removeReceiver(receiver);
575 int firedFlags = receiver.getFiredFlags();
576 removeReceiver(receiver);
577 fail(String.format("discoverable() timeout: scanMode=%d (expected %d), flags=0x%x "
578 + "(expected 0x%x)", scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE,
583 * Puts the local device into connectable only mode and checks to make sure that the local
584 * device is in in connectable mode and that the correct actions were broadcast.
586 * @param adapter The BT adapter.
588 public void undiscoverable(BluetoothAdapter adapter) {
589 int mask = BluetoothReceiver.SCAN_MODE_CONNECTABLE_FLAG;
591 if (!adapter.isEnabled()) {
592 fail("undiscoverable() bluetooth not enabled");
595 int scanMode = adapter.getScanMode();
596 if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
600 BluetoothReceiver receiver = getBluetoothReceiver(mask);
602 assertEquals(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, scanMode);
603 long start = System.currentTimeMillis();
604 assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE));
606 while (System.currentTimeMillis() - start < DISCOVERABLE_UNDISCOVERABLE_TIMEOUT) {
607 scanMode = adapter.getScanMode();
608 if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE
609 && (receiver.getFiredFlags() & mask) == mask) {
610 writeOutput(String.format("undiscoverable() completed in %d ms",
611 (receiver.getCompletedTime() - start)));
612 removeReceiver(receiver);
618 int firedFlags = receiver.getFiredFlags();
619 removeReceiver(receiver);
620 fail(String.format("undiscoverable() timeout: scanMode=%d (expected %d), flags=0x%x "
621 + "(expected 0x%x)", scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE, firedFlags,
626 * Starts a scan for remote devices and checks to make sure that the local device is scanning
627 * and that the correct actions were broadcast.
629 * @param adapter The BT adapter.
631 public void startScan(BluetoothAdapter adapter) {
632 int mask = BluetoothReceiver.DISCOVERY_STARTED_FLAG;
634 if (!adapter.isEnabled()) {
635 fail("startScan() bluetooth not enabled");
638 if (adapter.isDiscovering()) {
642 BluetoothReceiver receiver = getBluetoothReceiver(mask);
644 long start = System.currentTimeMillis();
645 assertTrue(adapter.startDiscovery());
647 while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) {
648 if (adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) {
649 writeOutput(String.format("startScan() completed in %d ms",
650 (receiver.getCompletedTime() - start)));
651 removeReceiver(receiver);
657 int firedFlags = receiver.getFiredFlags();
658 removeReceiver(receiver);
659 fail(String.format("startScan() timeout: isDiscovering=%b, flags=0x%x (expected 0x%x)",
660 adapter.isDiscovering(), firedFlags, mask));
664 * Stops a scan for remote devices and checks to make sure that the local device is not scanning
665 * and that the correct actions were broadcast.
667 * @param adapter The BT adapter.
669 public void stopScan(BluetoothAdapter adapter) {
670 int mask = BluetoothReceiver.DISCOVERY_FINISHED_FLAG;
672 if (!adapter.isEnabled()) {
673 fail("stopScan() bluetooth not enabled");
676 if (!adapter.isDiscovering()) {
680 BluetoothReceiver receiver = getBluetoothReceiver(mask);
682 long start = System.currentTimeMillis();
683 assertTrue(adapter.cancelDiscovery());
685 while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) {
686 if (!adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) {
687 writeOutput(String.format("stopScan() completed in %d ms",
688 (receiver.getCompletedTime() - start)));
689 removeReceiver(receiver);
695 int firedFlags = receiver.getFiredFlags();
696 removeReceiver(receiver);
697 fail(String.format("stopScan() timeout: isDiscovering=%b, flags=0x%x (expected 0x%x)",
698 adapter.isDiscovering(), firedFlags, mask));
703 * Enables PAN tethering on the local device and checks to make sure that tethering is enabled.
705 * @param adapter The BT adapter.
707 public void enablePan(BluetoothAdapter adapter) {
708 if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
711 long start = System.currentTimeMillis();
712 mPan.setBluetoothTethering(true);
713 long stop = System.currentTimeMillis();
714 assertTrue(mPan.isTetheringOn());
716 writeOutput(String.format("enablePan() completed in %d ms", (stop - start)));
720 * Disables PAN tethering on the local device and checks to make sure that tethering is
723 * @param adapter The BT adapter.
725 public void disablePan(BluetoothAdapter adapter) {
726 if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
729 long start = System.currentTimeMillis();
730 mPan.setBluetoothTethering(false);
731 long stop = System.currentTimeMillis();
732 assertFalse(mPan.isTetheringOn());
734 writeOutput(String.format("disablePan() completed in %d ms", (stop - start)));
738 * Initiates a pairing with a remote device and checks to make sure that the devices are paired
739 * and that the correct actions were broadcast.
741 * @param adapter The BT adapter.
742 * @param device The remote device.
743 * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
744 * @param pin The pairing pin if pairing requires a pin. Any value if not.
746 public void pair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, byte[] pin) {
747 pairOrAcceptPair(adapter, device, passkey, pin, true);
751 * Accepts a pairing with a remote device and checks to make sure that the devices are paired
752 * and that the correct actions were broadcast.
754 * @param adapter The BT adapter.
755 * @param device The remote device.
756 * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
757 * @param pin The pairing pin if pairing requires a pin. Any value if not.
759 public void acceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey,
761 pairOrAcceptPair(adapter, device, passkey, pin, false);
765 * Helper method used by {@link #pair(BluetoothAdapter, BluetoothDevice, int, byte[])} and
766 * {@link #acceptPair(BluetoothAdapter, BluetoothDevice, int, byte[])} to either pair or accept
769 * @param adapter The BT adapter.
770 * @param device The remote device.
771 * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
772 * @param pin The pairing pin if pairing requires a pin. Any value if not.
773 * @param shouldPair Whether to pair or accept the pair.
775 private void pairOrAcceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey,
776 byte[] pin, boolean shouldPair) {
777 int mask = PairReceiver.STATE_BONDING_FLAG | PairReceiver.STATE_BONDED_FLAG;
781 methodName = String.format("pair(device=%s)", device);
783 methodName = String.format("acceptPair(device=%s)", device);
786 if (!adapter.isEnabled()) {
787 fail(String.format("%s bluetooth not enabled", methodName));
790 PairReceiver receiver = getPairReceiver(device, passkey, pin, mask);
792 int state = device.getBondState();
794 case BluetoothDevice.BOND_NONE:
795 assertFalse(adapter.getBondedDevices().contains(device));
796 start = System.currentTimeMillis();
798 assertTrue(device.createBond());
801 case BluetoothDevice.BOND_BONDING:
802 mask = 0; // Don't check for received intents since we might have missed them.
804 case BluetoothDevice.BOND_BONDED:
805 assertTrue(adapter.getBondedDevices().contains(device));
808 removeReceiver(receiver);
809 fail(String.format("%s invalid state: state=%d", methodName, state));
812 long s = System.currentTimeMillis();
813 while (System.currentTimeMillis() - s < PAIR_UNPAIR_TIMEOUT) {
814 state = device.getBondState();
815 if (state == BluetoothDevice.BOND_BONDED && (receiver.getFiredFlags() & mask) == mask) {
816 assertTrue(adapter.getBondedDevices().contains(device));
817 long finish = receiver.getCompletedTime();
818 if (start != -1 && finish != -1) {
819 writeOutput(String.format("%s completed in %d ms", methodName,
822 writeOutput(String.format("%s completed", methodName));
824 removeReceiver(receiver);
830 int firedFlags = receiver.getFiredFlags();
831 removeReceiver(receiver);
832 fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
833 methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask));
837 * Deletes a pairing with a remote device and checks to make sure that the devices are unpaired
838 * and that the correct actions were broadcast.
840 * @param adapter The BT adapter.
841 * @param device The remote device.
843 public void unpair(BluetoothAdapter adapter, BluetoothDevice device) {
844 int mask = PairReceiver.STATE_NONE_FLAG;
846 String methodName = String.format("unpair(device=%s)", device);
848 if (!adapter.isEnabled()) {
849 fail(String.format("%s bluetooth not enabled", methodName));
852 PairReceiver receiver = getPairReceiver(device, 0, null, mask);
854 int state = device.getBondState();
856 case BluetoothDevice.BOND_NONE:
857 assertFalse(adapter.getBondedDevices().contains(device));
858 removeReceiver(receiver);
860 case BluetoothDevice.BOND_BONDING:
861 start = System.currentTimeMillis();
862 assertTrue(device.removeBond());
864 case BluetoothDevice.BOND_BONDED:
865 assertTrue(adapter.getBondedDevices().contains(device));
866 start = System.currentTimeMillis();
867 assertTrue(device.removeBond());
870 removeReceiver(receiver);
871 fail(String.format("%s invalid state: state=%d", methodName, state));
874 long s = System.currentTimeMillis();
875 while (System.currentTimeMillis() - s < PAIR_UNPAIR_TIMEOUT) {
876 if (device.getBondState() == BluetoothDevice.BOND_NONE
877 && (receiver.getFiredFlags() & mask) == mask) {
878 assertFalse(adapter.getBondedDevices().contains(device));
879 long finish = receiver.getCompletedTime();
880 if (start != -1 && finish != -1) {
881 writeOutput(String.format("%s completed in %d ms", methodName,
884 writeOutput(String.format("%s completed", methodName));
886 removeReceiver(receiver);
891 int firedFlags = receiver.getFiredFlags();
892 removeReceiver(receiver);
893 fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
894 methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask));
898 * Deletes all pairings of remote devices
899 * @param adapter the BT adapter
901 public void unpairAll(BluetoothAdapter adapter) {
902 Set<BluetoothDevice> devices = adapter.getBondedDevices();
903 for (BluetoothDevice device : devices) {
904 unpair(adapter, device);
909 * Connects a profile from the local device to a remote device and checks to make sure that the
910 * profile is connected and that the correct actions were broadcast.
912 * @param adapter The BT adapter.
913 * @param device The remote device.
914 * @param profile The profile to connect. One of {@link BluetoothProfile#A2DP},
915 * {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#INPUT_DEVICE}.
916 * @param methodName The method name to printed in the logs. If null, will be
917 * "connectProfile(profile=<profile>, device=<device>)"
919 public void connectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile,
921 if (methodName == null) {
922 methodName = String.format("connectProfile(profile=%d, device=%s)", profile, device);
924 int mask = (ConnectProfileReceiver.STATE_CONNECTING_FLAG
925 | ConnectProfileReceiver.STATE_CONNECTED_FLAG);
928 if (!adapter.isEnabled()) {
929 fail(String.format("%s bluetooth not enabled", methodName));
932 if (!adapter.getBondedDevices().contains(device)) {
933 fail(String.format("%s device not paired", methodName));
936 BluetoothProfile proxy = connectProxy(adapter, profile);
937 assertNotNull(proxy);
939 ConnectProfileReceiver receiver = getConnectProfileReceiver(device, profile, mask);
941 int state = proxy.getConnectionState(device);
943 case BluetoothProfile.STATE_CONNECTED:
944 removeReceiver(receiver);
946 case BluetoothProfile.STATE_CONNECTING:
947 mask = 0; // Don't check for received intents since we might have missed them.
949 case BluetoothProfile.STATE_DISCONNECTED:
950 case BluetoothProfile.STATE_DISCONNECTING:
951 start = System.currentTimeMillis();
952 if (profile == BluetoothProfile.A2DP) {
953 assertTrue(((BluetoothA2dp)proxy).connect(device));
954 } else if (profile == BluetoothProfile.HEADSET) {
955 assertTrue(((BluetoothHeadset)proxy).connect(device));
956 } else if (profile == BluetoothProfile.INPUT_DEVICE) {
957 assertTrue(((BluetoothInputDevice)proxy).connect(device));
961 removeReceiver(receiver);
962 fail(String.format("%s invalid state: state=%d", methodName, state));
965 long s = System.currentTimeMillis();
966 while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
967 state = proxy.getConnectionState(device);
968 if (state == BluetoothProfile.STATE_CONNECTED
969 && (receiver.getFiredFlags() & mask) == mask) {
970 long finish = receiver.getCompletedTime();
971 if (start != -1 && finish != -1) {
972 writeOutput(String.format("%s completed in %d ms", methodName,
975 writeOutput(String.format("%s completed", methodName));
977 removeReceiver(receiver);
983 int firedFlags = receiver.getFiredFlags();
984 removeReceiver(receiver);
985 fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
986 methodName, state, BluetoothProfile.STATE_CONNECTED, firedFlags, mask));
990 * Disconnects a profile between the local device and a remote device and checks to make sure
991 * that the profile is disconnected and that the correct actions were broadcast.
993 * @param adapter The BT adapter.
994 * @param device The remote device.
995 * @param profile The profile to disconnect. One of {@link BluetoothProfile#A2DP},
996 * {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#INPUT_DEVICE}.
997 * @param methodName The method name to printed in the logs. If null, will be
998 * "connectProfile(profile=<profile>, device=<device>)"
1000 public void disconnectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile,
1001 String methodName) {
1002 if (methodName == null) {
1003 methodName = String.format("disconnectProfile(profile=%d, device=%s)", profile, device);
1005 int mask = (ConnectProfileReceiver.STATE_DISCONNECTING_FLAG
1006 | ConnectProfileReceiver.STATE_DISCONNECTED_FLAG);
1009 if (!adapter.isEnabled()) {
1010 fail(String.format("%s bluetooth not enabled", methodName));
1013 if (!adapter.getBondedDevices().contains(device)) {
1014 fail(String.format("%s device not paired", methodName));
1017 BluetoothProfile proxy = connectProxy(adapter, profile);
1018 assertNotNull(proxy);
1020 ConnectProfileReceiver receiver = getConnectProfileReceiver(device, profile, mask);
1022 int state = proxy.getConnectionState(device);
1024 case BluetoothProfile.STATE_CONNECTED:
1025 case BluetoothProfile.STATE_CONNECTING:
1026 start = System.currentTimeMillis();
1027 if (profile == BluetoothProfile.A2DP) {
1028 assertTrue(((BluetoothA2dp)proxy).disconnect(device));
1029 } else if (profile == BluetoothProfile.HEADSET) {
1030 assertTrue(((BluetoothHeadset)proxy).disconnect(device));
1031 } else if (profile == BluetoothProfile.INPUT_DEVICE) {
1032 assertTrue(((BluetoothInputDevice)proxy).disconnect(device));
1035 case BluetoothProfile.STATE_DISCONNECTED:
1036 removeReceiver(receiver);
1038 case BluetoothProfile.STATE_DISCONNECTING:
1039 mask = 0; // Don't check for received intents since we might have missed them.
1042 removeReceiver(receiver);
1043 fail(String.format("%s invalid state: state=%d", methodName, state));
1046 long s = System.currentTimeMillis();
1047 while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
1048 state = proxy.getConnectionState(device);
1049 if (state == BluetoothProfile.STATE_DISCONNECTED
1050 && (receiver.getFiredFlags() & mask) == mask) {
1051 long finish = receiver.getCompletedTime();
1052 if (start != -1 && finish != -1) {
1053 writeOutput(String.format("%s completed in %d ms", methodName,
1056 writeOutput(String.format("%s completed", methodName));
1058 removeReceiver(receiver);
1064 int firedFlags = receiver.getFiredFlags();
1065 removeReceiver(receiver);
1066 fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
1067 methodName, state, BluetoothProfile.STATE_DISCONNECTED, firedFlags, mask));
1071 * Connects the PANU to a remote NAP and checks to make sure that the PANU is connected and that
1072 * the correct actions were broadcast.
1074 * @param adapter The BT adapter.
1075 * @param device The remote device.
1077 public void connectPan(BluetoothAdapter adapter, BluetoothDevice device) {
1078 connectPanOrIncomingPanConnection(adapter, device, true);
1082 * Checks that a remote PANU connects to the local NAP correctly and that the correct actions
1085 * @param adapter The BT adapter.
1086 * @param device The remote device.
1088 public void incomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device) {
1089 connectPanOrIncomingPanConnection(adapter, device, false);
1093 * Helper method used by {@link #connectPan(BluetoothAdapter, BluetoothDevice)} and
1094 * {@link #incomingPanConnection(BluetoothAdapter, BluetoothDevice)} to either connect to a
1095 * remote NAP or verify that a remote device connected to the local NAP.
1097 * @param adapter The BT adapter.
1098 * @param device The remote device.
1099 * @param connect If the method should initiate the connection (is PANU)
1101 private void connectPanOrIncomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device,
1108 methodName = String.format("connectPan(device=%s)", device);
1109 mask = (ConnectProfileReceiver.STATE_CONNECTED_FLAG |
1110 ConnectProfileReceiver.STATE_CONNECTING_FLAG);
1111 role = BluetoothPan.LOCAL_PANU_ROLE;
1113 methodName = String.format("incomingPanConnection(device=%s)", device);
1114 mask = ConnectProfileReceiver.STATE_CONNECTED_FLAG;
1115 role = BluetoothPan.LOCAL_NAP_ROLE;
1118 if (!adapter.isEnabled()) {
1119 fail(String.format("%s bluetooth not enabled", methodName));
1122 if (!adapter.getBondedDevices().contains(device)) {
1123 fail(String.format("%s device not paired", methodName));
1126 mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
1127 assertNotNull(mPan);
1128 ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
1130 int state = mPan.getConnectionState(device);
1132 case BluetoothPan.STATE_CONNECTED:
1133 removeReceiver(receiver);
1135 case BluetoothPan.STATE_CONNECTING:
1136 mask = 0; // Don't check for received intents since we might have missed them.
1138 case BluetoothPan.STATE_DISCONNECTED:
1139 case BluetoothPan.STATE_DISCONNECTING:
1140 start = System.currentTimeMillis();
1141 if (role == BluetoothPan.LOCAL_PANU_ROLE) {
1142 Log.i("BT", "connect to pan");
1143 assertTrue(mPan.connect(device));
1147 removeReceiver(receiver);
1148 fail(String.format("%s invalid state: state=%d", methodName, state));
1151 long s = System.currentTimeMillis();
1152 while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
1153 state = mPan.getConnectionState(device);
1154 if (state == BluetoothPan.STATE_CONNECTED
1155 && (receiver.getFiredFlags() & mask) == mask) {
1156 long finish = receiver.getCompletedTime();
1157 if (start != -1 && finish != -1) {
1158 writeOutput(String.format("%s completed in %d ms", methodName,
1161 writeOutput(String.format("%s completed", methodName));
1163 removeReceiver(receiver);
1169 int firedFlags = receiver.getFiredFlags();
1170 removeReceiver(receiver);
1171 fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)",
1172 methodName, state, BluetoothPan.STATE_CONNECTED, firedFlags, mask));
1176 * Disconnects the PANU from a remote NAP and checks to make sure that the PANU is disconnected
1177 * and that the correct actions were broadcast.
1179 * @param adapter The BT adapter.
1180 * @param device The remote device.
1182 public void disconnectPan(BluetoothAdapter adapter, BluetoothDevice device) {
1183 disconnectFromRemoteOrVerifyConnectNap(adapter, device, true);
1187 * Checks that a remote PANU disconnects from the local NAP correctly and that the correct
1188 * actions were broadcast.
1190 * @param adapter The BT adapter.
1191 * @param device The remote device.
1193 public void incomingPanDisconnection(BluetoothAdapter adapter, BluetoothDevice device) {
1194 disconnectFromRemoteOrVerifyConnectNap(adapter, device, false);
1198 * Helper method used by {@link #disconnectPan(BluetoothAdapter, BluetoothDevice)} and
1199 * {@link #incomingPanDisconnection(BluetoothAdapter, BluetoothDevice)} to either disconnect
1200 * from a remote NAP or verify that a remote device disconnected from the local NAP.
1202 * @param adapter The BT adapter.
1203 * @param device The remote device.
1204 * @param disconnect Whether the method should connect or verify.
1206 private void disconnectFromRemoteOrVerifyConnectNap(BluetoothAdapter adapter,
1207 BluetoothDevice device, boolean disconnect) {
1213 methodName = String.format("disconnectPan(device=%s)", device);
1214 mask = (ConnectProfileReceiver.STATE_DISCONNECTED_FLAG |
1215 ConnectProfileReceiver.STATE_DISCONNECTING_FLAG);
1216 role = BluetoothPan.LOCAL_PANU_ROLE;
1218 methodName = String.format("incomingPanDisconnection(device=%s)", device);
1219 mask = ConnectProfileReceiver.STATE_DISCONNECTED_FLAG;
1220 role = BluetoothPan.LOCAL_NAP_ROLE;
1223 if (!adapter.isEnabled()) {
1224 fail(String.format("%s bluetooth not enabled", methodName));
1227 if (!adapter.getBondedDevices().contains(device)) {
1228 fail(String.format("%s device not paired", methodName));
1231 mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
1232 assertNotNull(mPan);
1233 ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
1235 int state = mPan.getConnectionState(device);
1237 case BluetoothPan.STATE_CONNECTED:
1238 case BluetoothPan.STATE_CONNECTING:
1239 start = System.currentTimeMillis();
1240 if (role == BluetoothPan.LOCAL_PANU_ROLE) {
1241 assertTrue(mPan.disconnect(device));
1244 case BluetoothPan.STATE_DISCONNECTED:
1245 removeReceiver(receiver);
1247 case BluetoothPan.STATE_DISCONNECTING:
1248 mask = 0; // Don't check for received intents since we might have missed them.
1251 removeReceiver(receiver);
1252 fail(String.format("%s invalid state: state=%d", methodName, state));
1255 long s = System.currentTimeMillis();
1256 while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
1257 state = mPan.getConnectionState(device);
1258 if (state == BluetoothInputDevice.STATE_DISCONNECTED
1259 && (receiver.getFiredFlags() & mask) == mask) {
1260 long finish = receiver.getCompletedTime();
1261 if (start != -1 && finish != -1) {
1262 writeOutput(String.format("%s completed in %d ms", methodName,
1265 writeOutput(String.format("%s completed", methodName));
1267 removeReceiver(receiver);
1273 int firedFlags = receiver.getFiredFlags();
1274 removeReceiver(receiver);
1275 fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)",
1276 methodName, state, BluetoothInputDevice.STATE_DISCONNECTED, firedFlags, mask));
1280 * Opens a SCO channel using {@link android.media.AudioManager#startBluetoothSco()} and checks
1281 * to make sure that the channel is opened and that the correct actions were broadcast.
1283 * @param adapter The BT adapter.
1284 * @param device The remote device.
1286 public void startSco(BluetoothAdapter adapter, BluetoothDevice device) {
1287 startStopSco(adapter, device, true);
1291 * Closes a SCO channel using {@link android.media.AudioManager#stopBluetoothSco()} and checks
1292 * to make sure that the channel is closed and that the correct actions were broadcast.
1294 * @param adapter The BT adapter.
1295 * @param device The remote device.
1297 public void stopSco(BluetoothAdapter adapter, BluetoothDevice device) {
1298 startStopSco(adapter, device, false);
1301 * Helper method for {@link #startSco(BluetoothAdapter, BluetoothDevice)} and
1302 * {@link #stopSco(BluetoothAdapter, BluetoothDevice)}.
1304 * @param adapter The BT adapter.
1305 * @param device The remote device.
1306 * @param isStart Whether the SCO channel should be opened.
1308 private void startStopSco(BluetoothAdapter adapter, BluetoothDevice device, boolean isStart) {
1314 methodName = String.format("startSco(device=%s)", device);
1315 mask = StartStopScoReceiver.STATE_CONNECTED_FLAG;
1317 methodName = String.format("stopSco(device=%s)", device);
1318 mask = StartStopScoReceiver.STATE_DISCONNECTED_FLAG;
1321 if (!adapter.isEnabled()) {
1322 fail(String.format("%s bluetooth not enabled", methodName));
1325 if (!adapter.getBondedDevices().contains(device)) {
1326 fail(String.format("%s device not paired", methodName));
1329 AudioManager manager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
1330 assertNotNull(manager);
1332 if (!manager.isBluetoothScoAvailableOffCall()) {
1333 fail(String.format("%s device does not support SCO", methodName));
1336 boolean isScoOn = manager.isBluetoothScoOn();
1337 if (isStart == isScoOn) {
1341 StartStopScoReceiver receiver = getStartStopScoReceiver(mask);
1342 start = System.currentTimeMillis();
1344 manager.startBluetoothSco();
1346 manager.stopBluetoothSco();
1349 long s = System.currentTimeMillis();
1350 while (System.currentTimeMillis() - s < START_STOP_SCO_TIMEOUT) {
1351 isScoOn = manager.isBluetoothScoOn();
1352 if (isStart == isScoOn && (receiver.getFiredFlags() & mask) == mask) {
1353 long finish = receiver.getCompletedTime();
1354 if (start != -1 && finish != -1) {
1355 writeOutput(String.format("%s completed in %d ms", methodName,
1358 writeOutput(String.format("%s completed", methodName));
1360 removeReceiver(receiver);
1366 int firedFlags = receiver.getFiredFlags();
1367 removeReceiver(receiver);
1368 fail(String.format("%s timeout: on=%b (expected %b), flags=0x%x (expected 0x%x)",
1369 methodName, isScoOn, isStart, firedFlags, mask));
1373 * Writes a string to the logcat and a file if a file has been specified in the constructor.
1375 * @param s The string to be written.
1377 public void writeOutput(String s) {
1379 if (mOutputWriter == null) {
1383 mOutputWriter.write(s + "\n");
1384 mOutputWriter.flush();
1385 } catch (IOException e) {
1386 Log.w(mTag, "Could not write to output file", e);
1390 private void addReceiver(BroadcastReceiver receiver, String[] actions) {
1391 IntentFilter filter = new IntentFilter();
1392 for (String action: actions) {
1393 filter.addAction(action);
1395 mContext.registerReceiver(receiver, filter);
1396 mReceivers.add(receiver);
1399 private BluetoothReceiver getBluetoothReceiver(int expectedFlags) {
1400 String[] actions = {
1401 BluetoothAdapter.ACTION_DISCOVERY_FINISHED,
1402 BluetoothAdapter.ACTION_DISCOVERY_STARTED,
1403 BluetoothAdapter.ACTION_SCAN_MODE_CHANGED,
1404 BluetoothAdapter.ACTION_STATE_CHANGED};
1405 BluetoothReceiver receiver = new BluetoothReceiver(expectedFlags);
1406 addReceiver(receiver, actions);
1410 private PairReceiver getPairReceiver(BluetoothDevice device, int passkey, byte[] pin,
1411 int expectedFlags) {
1412 String[] actions = {
1413 BluetoothDevice.ACTION_PAIRING_REQUEST,
1414 BluetoothDevice.ACTION_BOND_STATE_CHANGED};
1415 PairReceiver receiver = new PairReceiver(device, passkey, pin, expectedFlags);
1416 addReceiver(receiver, actions);
1420 private ConnectProfileReceiver getConnectProfileReceiver(BluetoothDevice device, int profile,
1421 int expectedFlags) {
1422 String[] actions = {
1423 BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED,
1424 BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED,
1425 BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED};
1426 ConnectProfileReceiver receiver = new ConnectProfileReceiver(device, profile,
1428 addReceiver(receiver, actions);
1432 private ConnectPanReceiver getConnectPanReceiver(BluetoothDevice device, int role,
1433 int expectedFlags) {
1434 String[] actions = {BluetoothPan.ACTION_CONNECTION_STATE_CHANGED};
1435 ConnectPanReceiver receiver = new ConnectPanReceiver(device, role, expectedFlags);
1436 addReceiver(receiver, actions);
1440 private StartStopScoReceiver getStartStopScoReceiver(int expectedFlags) {
1441 String[] actions = {AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED};
1442 StartStopScoReceiver receiver = new StartStopScoReceiver(expectedFlags);
1443 addReceiver(receiver, actions);
1447 private void removeReceiver(BroadcastReceiver receiver) {
1448 mContext.unregisterReceiver(receiver);
1449 mReceivers.remove(receiver);
1452 private BluetoothProfile connectProxy(BluetoothAdapter adapter, int profile) {
1454 case BluetoothProfile.A2DP:
1455 if (mA2dp != null) {
1459 case BluetoothProfile.HEADSET:
1460 if (mHeadset != null) {
1464 case BluetoothProfile.INPUT_DEVICE:
1465 if (mInput != null) {
1469 case BluetoothProfile.PAN:
1477 adapter.getProfileProxy(mContext, mServiceListener, profile);
1478 long s = System.currentTimeMillis();
1480 case BluetoothProfile.A2DP:
1481 while (mA2dp == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
1485 case BluetoothProfile.HEADSET:
1486 while (mHeadset == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
1490 case BluetoothProfile.INPUT_DEVICE:
1491 while (mInput == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
1495 case BluetoothProfile.PAN:
1496 while (mPan == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
1505 private void sleep(long time) {
1508 } catch (InterruptedException e) {