1185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe/*
2185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe * Copyright (C) 2010 The Android Open Source Project
3185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe *
4185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe * Licensed under the Apache License, Version 2.0 (the "License");
5185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe * you may not use this file except in compliance with the License.
6185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe * You may obtain a copy of the License at
7185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe *
8185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe *      http://www.apache.org/licenses/LICENSE-2.0
9185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe *
10185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe * Unless required by applicable law or agreed to in writing, software
11185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe * distributed under the License is distributed on an "AS IS" BASIS,
12185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe * See the License for the specific language governing permissions and
14185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe * limitations under the License.
15185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe */
16185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
17185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowepackage android.bluetooth;
18185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
1974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganeshimport android.bluetooth.BluetoothPan;
2074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganeshimport android.bluetooth.BluetoothProfile;
21185a0b04c611a287cbd866d27b0ceff77f12d97bEric Roweimport android.content.BroadcastReceiver;
22185a0b04c611a287cbd866d27b0ceff77f12d97bEric Roweimport android.content.Context;
23185a0b04c611a287cbd866d27b0ceff77f12d97bEric Roweimport android.content.Intent;
24185a0b04c611a287cbd866d27b0ceff77f12d97bEric Roweimport android.content.IntentFilter;
25835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Roweimport android.media.AudioManager;
26185a0b04c611a287cbd866d27b0ceff77f12d97bEric Roweimport android.os.Environment;
27185a0b04c611a287cbd866d27b0ceff77f12d97bEric Roweimport android.util.Log;
28185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
29185a0b04c611a287cbd866d27b0ceff77f12d97bEric Roweimport junit.framework.Assert;
30185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
31185a0b04c611a287cbd866d27b0ceff77f12d97bEric Roweimport java.io.BufferedWriter;
32185a0b04c611a287cbd866d27b0ceff77f12d97bEric Roweimport java.io.File;
33185a0b04c611a287cbd866d27b0ceff77f12d97bEric Roweimport java.io.FileWriter;
34185a0b04c611a287cbd866d27b0ceff77f12d97bEric Roweimport java.io.IOException;
35826af6266c79d76b81fe850b9cd3d351597e4adbEric Roweimport java.util.ArrayList;
36826af6266c79d76b81fe850b9cd3d351597e4adbEric Roweimport java.util.List;
3703800b8873f70223dcfcf396a3762775dfc1a8abGuang Zhuimport java.util.Set;
38f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavatiimport java.util.concurrent.Semaphore;
39f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavatiimport java.util.concurrent.TimeUnit;
40185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
41185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowepublic class BluetoothTestUtils extends Assert {
42185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
432b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe    /** Timeout for enable/disable in ms. */
44207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe    private static final int ENABLE_DISABLE_TIMEOUT = 20000;
452b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe    /** Timeout for discoverable/undiscoverable in ms. */
46207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe    private static final int DISCOVERABLE_UNDISCOVERABLE_TIMEOUT = 5000;
472b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe    /** Timeout for starting/stopping a scan in ms. */
48207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe    private static final int START_STOP_SCAN_TIMEOUT = 5000;
492b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe    /** Timeout for pair/unpair in ms. */
50207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe    private static final int PAIR_UNPAIR_TIMEOUT = 20000;
512b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe    /** Timeout for connecting/disconnecting a profile in ms. */
52207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe    private static final int CONNECT_DISCONNECT_PROFILE_TIMEOUT = 20000;
532b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe    /** Timeout to start or stop a SCO channel in ms. */
54835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe    private static final int START_STOP_SCO_TIMEOUT = 10000;
552b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe    /** Timeout to connect a profile proxy in ms. */
562b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe    private static final int CONNECT_PROXY_TIMEOUT = 5000;
572b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe    /** Time between polls in ms. */
58185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    private static final int POLL_TIME = 100;
59185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
60826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    private abstract class FlagReceiver extends BroadcastReceiver {
61826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private int mExpectedFlags = 0;
62826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private int mFiredFlags = 0;
63826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private long mCompletedTime = -1;
64185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
65826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        public FlagReceiver(int expectedFlags) {
66826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            mExpectedFlags = expectedFlags;
67826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
68185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
69826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        public int getFiredFlags() {
70826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            synchronized (this) {
71826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                return mFiredFlags;
72826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            }
73826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
74185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
75826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        public long getCompletedTime() {
76826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            synchronized (this) {
77826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                return mCompletedTime;
78826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            }
79826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
80826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
81826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        protected void setFiredFlag(int flag) {
82826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            synchronized (this) {
83826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                mFiredFlags |= flag;
845d0ed7b952667a1506585683c9eb5fe5ed7f0af2Eric Rowe                if ((mFiredFlags & mExpectedFlags) == mExpectedFlags) {
85826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    mCompletedTime = System.currentTimeMillis();
86826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                }
87826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            }
88826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
89826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    }
90826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
91826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    private class BluetoothReceiver extends FlagReceiver {
92826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private static final int DISCOVERY_STARTED_FLAG = 1;
93826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private static final int DISCOVERY_FINISHED_FLAG = 1 << 1;
94826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private static final int SCAN_MODE_NONE_FLAG = 1 << 2;
95826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private static final int SCAN_MODE_CONNECTABLE_FLAG = 1 << 3;
96826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG = 1 << 4;
97826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private static final int STATE_OFF_FLAG = 1 << 5;
98826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private static final int STATE_TURNING_ON_FLAG = 1 << 6;
99826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private static final int STATE_ON_FLAG = 1 << 7;
100826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private static final int STATE_TURNING_OFF_FLAG = 1 << 8;
101826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
102826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        public BluetoothReceiver(int expectedFlags) {
103826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            super(expectedFlags);
104826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
105185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
106185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        @Override
107185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        public void onReceive(Context context, Intent intent) {
108826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(intent.getAction())) {
109826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                setFiredFlag(DISCOVERY_STARTED_FLAG);
110826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(intent.getAction())) {
111826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                setFiredFlag(DISCOVERY_FINISHED_FLAG);
112826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            } else if (BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(intent.getAction())) {
113826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, -1);
114826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                assertNotSame(-1, mode);
115826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                switch (mode) {
116826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothAdapter.SCAN_MODE_NONE:
117826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        setFiredFlag(SCAN_MODE_NONE_FLAG);
118826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
119826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
120826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        setFiredFlag(SCAN_MODE_CONNECTABLE_FLAG);
121826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
122826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
123826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        setFiredFlag(SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG);
124826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
125826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                }
126826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
127826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
128826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                assertNotSame(-1, state);
129826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                switch (state) {
130826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothAdapter.STATE_OFF:
131826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        setFiredFlag(STATE_OFF_FLAG);
132826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
133826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothAdapter.STATE_TURNING_ON:
134826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        setFiredFlag(STATE_TURNING_ON_FLAG);
135826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
136826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothAdapter.STATE_ON:
137826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        setFiredFlag(STATE_ON_FLAG);
138826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
139826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothAdapter.STATE_TURNING_OFF:
140826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        setFiredFlag(STATE_TURNING_OFF_FLAG);
141826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
142185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe                }
143185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            }
144185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
145826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    }
146185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
147826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    private class PairReceiver extends FlagReceiver {
148826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private static final int STATE_BONDED_FLAG = 1;
149826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private static final int STATE_BONDING_FLAG = 1 << 1;
150826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private static final int STATE_NONE_FLAG = 1 << 2;
151826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
152826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private BluetoothDevice mDevice;
153826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private int mPasskey;
154826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private byte[] mPin;
155826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
156826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        public PairReceiver(BluetoothDevice device, int passkey, byte[] pin, int expectedFlags) {
157826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            super(expectedFlags);
158826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
159826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            mDevice = device;
160826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            mPasskey = passkey;
161826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            mPin = pin;
162826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
163826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
164826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        @Override
165826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        public void onReceive(Context context, Intent intent) {
166826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))) {
167826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                return;
168826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            }
169826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
170826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction())) {
171826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                int varient = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, -1);
172826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                assertNotSame(-1, varient);
173b49aa60829ab8fadec2f4c0661271100691d8225Eric Rowe                switch (varient) {
174826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothDevice.PAIRING_VARIANT_PIN:
1753b3d1fea94318a4892fbd4353269749af417a81aCasper Bonde                    case BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS:
176826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        mDevice.setPin(mPin);
177826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
178826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
179826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        mDevice.setPasskey(mPasskey);
180826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
181826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
182826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothDevice.PAIRING_VARIANT_CONSENT:
183826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        mDevice.setPairingConfirmation(true);
184826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
185826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT:
186826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        mDevice.setRemoteOutOfBandData();
187826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
188826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                }
189826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())) {
190826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
191826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                assertNotSame(-1, state);
192826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                switch (state) {
193826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothDevice.BOND_NONE:
194826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        setFiredFlag(STATE_NONE_FLAG);
195826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
196826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothDevice.BOND_BONDING:
197826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        setFiredFlag(STATE_BONDING_FLAG);
198826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
199826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothDevice.BOND_BONDED:
200826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        setFiredFlag(STATE_BONDED_FLAG);
201826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
202826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                }
203826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            }
204826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
205826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    }
206826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
207826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    private class ConnectProfileReceiver extends FlagReceiver {
208826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private static final int STATE_DISCONNECTED_FLAG = 1;
209826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private static final int STATE_CONNECTING_FLAG = 1 << 1;
210826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private static final int STATE_CONNECTED_FLAG = 1 << 2;
211826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private static final int STATE_DISCONNECTING_FLAG = 1 << 3;
212826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
213826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private BluetoothDevice mDevice;
214826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private int mProfile;
215826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        private String mConnectionAction;
216826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
217826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        public ConnectProfileReceiver(BluetoothDevice device, int profile, int expectedFlags) {
218826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            super(expectedFlags);
219826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
220826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            mDevice = device;
221826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            mProfile = profile;
222826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
223b49aa60829ab8fadec2f4c0661271100691d8225Eric Rowe            switch (mProfile) {
224826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                case BluetoothProfile.A2DP:
225826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    mConnectionAction = BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED;
226826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    break;
227826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                case BluetoothProfile.HEADSET:
228826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    mConnectionAction = BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED;
229826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    break;
230c26c76c63d933f8057f795d05624f91b811c8c71Hansong Zhang                case BluetoothProfile.HID_HOST:
231c26c76c63d933f8057f795d05624f91b811c8c71Hansong Zhang                    mConnectionAction = BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED;
2324ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                    break;
2332b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                case BluetoothProfile.PAN:
2342b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    mConnectionAction = BluetoothPan.ACTION_CONNECTION_STATE_CHANGED;
2352b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    break;
236826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                default:
237826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    mConnectionAction = null;
238826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            }
239826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
240826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
241826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        @Override
242826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        public void onReceive(Context context, Intent intent) {
243826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            if (mConnectionAction != null && mConnectionAction.equals(intent.getAction())) {
244826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))) {
245826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    return;
246826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                }
247826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
248826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
249826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                assertNotSame(-1, state);
250826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                switch (state) {
251826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothProfile.STATE_DISCONNECTED:
252826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        setFiredFlag(STATE_DISCONNECTED_FLAG);
253826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
254826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothProfile.STATE_CONNECTING:
255826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        setFiredFlag(STATE_CONNECTING_FLAG);
256826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
257826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothProfile.STATE_CONNECTED:
258826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        setFiredFlag(STATE_CONNECTED_FLAG);
259826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
260826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothProfile.STATE_DISCONNECTING:
261826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        setFiredFlag(STATE_DISCONNECTING_FLAG);
262826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
263826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                }
264826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            }
265826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
266826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    }
267826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
2682b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe    private class ConnectPanReceiver extends ConnectProfileReceiver {
2697e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        private int mRole;
2707e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
2717e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        public ConnectPanReceiver(BluetoothDevice device, int role, int expectedFlags) {
2722b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            super(device, BluetoothProfile.PAN, expectedFlags);
2737e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
2747e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            mRole = role;
2757e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        }
2767e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
2777e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        @Override
2787e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        public void onReceive(Context context, Intent intent) {
2792b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            if (mRole != intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, -1)) {
2807e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                return;
2817e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            }
2827e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
2832b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            super.onReceive(context, intent);
2847e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        }
2857e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    }
2867e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
287835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe    private class StartStopScoReceiver extends FlagReceiver {
288835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        private static final int STATE_CONNECTED_FLAG = 1;
289835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        private static final int STATE_DISCONNECTED_FLAG = 1 << 1;
290835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe
291835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        public StartStopScoReceiver(int expectedFlags) {
292835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe            super(expectedFlags);
293835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        }
294835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe
295835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        @Override
296835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        public void onReceive(Context context, Intent intent) {
2977af75afb2c8608dbe73509036eefd3281d646a5fEric Rowe            if (AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED.equals(intent.getAction())) {
298835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
299835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                        AudioManager.SCO_AUDIO_STATE_ERROR);
300835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                assertNotSame(AudioManager.SCO_AUDIO_STATE_ERROR, state);
301835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                switch(state) {
302835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                    case AudioManager.SCO_AUDIO_STATE_CONNECTED:
303835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                        setFiredFlag(STATE_CONNECTED_FLAG);
304835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                        break;
305835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                    case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:
306835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                        setFiredFlag(STATE_DISCONNECTED_FLAG);
307835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                        break;
308835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                }
309835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe            }
310835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        }
311835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe    }
312835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe
313826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    private BluetoothProfile.ServiceListener mServiceListener =
314826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            new BluetoothProfile.ServiceListener() {
3152b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        @Override
316826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        public void onServiceConnected(int profile, BluetoothProfile proxy) {
317185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            synchronized (this) {
318826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                switch (profile) {
319826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothProfile.A2DP:
320826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        mA2dp = (BluetoothA2dp) proxy;
321826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
322826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothProfile.HEADSET:
323826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        mHeadset = (BluetoothHeadset) proxy;
324826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
325c26c76c63d933f8057f795d05624f91b811c8c71Hansong Zhang                    case BluetoothProfile.HID_HOST:
326c26c76c63d933f8057f795d05624f91b811c8c71Hansong Zhang                        mInput = (BluetoothHidHost) proxy;
3274ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        break;
32874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                    case BluetoothProfile.PAN:
32974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        mPan = (BluetoothPan) proxy;
33074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        break;
331826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                }
332185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            }
333185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
334185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
3352b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        @Override
336826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        public void onServiceDisconnected(int profile) {
337185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            synchronized (this) {
338826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                switch (profile) {
339826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothProfile.A2DP:
340826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        mA2dp = null;
341826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
342826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    case BluetoothProfile.HEADSET:
343826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        mHeadset = null;
344826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        break;
345c26c76c63d933f8057f795d05624f91b811c8c71Hansong Zhang                    case BluetoothProfile.HID_HOST:
3464ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        mInput = null;
3474ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        break;
34874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                    case BluetoothProfile.PAN:
34974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        mPan = null;
35074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        break;
351826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                }
352185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            }
353185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
354826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    };
355826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
356826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    private List<BroadcastReceiver> mReceivers = new ArrayList<BroadcastReceiver>();
357826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
358826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    private BufferedWriter mOutputWriter;
359826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    private String mTag;
360826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    private String mOutputFile;
361185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
362826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    private Context mContext;
3632b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe    private BluetoothA2dp mA2dp = null;
3642b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe    private BluetoothHeadset mHeadset = null;
365c26c76c63d933f8057f795d05624f91b811c8c71Hansong Zhang    private BluetoothHidHost mInput = null;
3662b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe    private BluetoothPan mPan = null;
367185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
3687e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
3697e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Creates a utility instance for testing Bluetooth.
3707e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
3717e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param context The context of the application using the utility.
3727e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param tag The log tag of the application using the utility.
3737e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
374185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    public BluetoothTestUtils(Context context, String tag) {
375185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        this(context, tag, null);
376185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    }
377185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
3787e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
3797e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Creates a utility instance for testing Bluetooth.
3807e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
3817e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param context The context of the application using the utility.
3827e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param tag The log tag of the application using the utility.
3837e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param outputFile The path to an output file if the utility is to write results to a
3847e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *        separate file.
3857e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
386185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    public BluetoothTestUtils(Context context, String tag, String outputFile) {
387185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        mContext = context;
388185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        mTag = tag;
389185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        mOutputFile = outputFile;
390185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
391185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        if (mOutputFile == null) {
392185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            mOutputWriter = null;
393185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        } else {
394185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            try {
395185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe                mOutputWriter = new BufferedWriter(new FileWriter(new File(
396185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe                        Environment.getExternalStorageDirectory(), mOutputFile), true));
397185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            } catch (IOException e) {
398185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe                Log.w(mTag, "Test output file could not be opened", e);
399185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe                mOutputWriter = null;
400185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            }
401185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
402185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    }
403185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
4047e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
4057e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Closes the utility instance and unregisters any BroadcastReceivers.
4067e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
407185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    public void close() {
408826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        while (!mReceivers.isEmpty()) {
409826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            mContext.unregisterReceiver(mReceivers.remove(0));
410826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
411185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
412185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        if (mOutputWriter != null) {
413185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            try {
414185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe                mOutputWriter.close();
415185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            } catch (IOException e) {
416185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe                Log.w(mTag, "Test output file could not be closed", e);
417185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            }
418185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
419185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    }
420185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
4217e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
4227e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Enables Bluetooth and checks to make sure that Bluetooth was turned on and that the correct
4237e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * actions were broadcast.
4247e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
4257e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
4267e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
427185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    public void enable(BluetoothAdapter adapter) {
4286570340f713d0c716ce4860f6f43d1efa230242aSharvil Nanavati        writeOutput("Enabling Bluetooth adapter.");
4296570340f713d0c716ce4860f6f43d1efa230242aSharvil Nanavati        assertFalse(adapter.isEnabled());
430571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        int btState = adapter.getState();
431571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        final Semaphore completionSemaphore = new Semaphore(0);
432571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        final BroadcastReceiver receiver = new BroadcastReceiver() {
433571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou            @Override
434571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou            public void onReceive(Context context, Intent intent) {
435571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou                final String action = intent.getAction();
436571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou                if (!BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
437571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou                    return;
438571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou                }
439571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou                final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
440571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou                        BluetoothAdapter.ERROR);
441571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou                if (state == BluetoothAdapter.STATE_ON) {
442571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou                    completionSemaphore.release();
443185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe                }
444185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            }
445571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        };
446185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
447571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
448571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        mContext.registerReceiver(receiver, filter);
449571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        assertTrue(adapter.enable());
450571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        boolean success = false;
451571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        try {
452571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou            success = completionSemaphore.tryAcquire(ENABLE_DISABLE_TIMEOUT, TimeUnit.MILLISECONDS);
453571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou            writeOutput(String.format("enable() completed in 0 ms"));
454571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        } catch (final InterruptedException e) {
455571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou            // This should never happen but just in case it does, the test will fail anyway.
456571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        }
457571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        mContext.unregisterReceiver(receiver);
458571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        if (!success) {
459571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou            fail(String.format("enable() timeout: state=%d (expected %d)", btState,
460571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou                    BluetoothAdapter.STATE_ON));
461571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        }
462185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    }
463185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
4647e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
4657e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Disables Bluetooth and checks to make sure that Bluetooth was turned off and that the correct
4667e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * actions were broadcast.
4677e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
4687e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
4697e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
470185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    public void disable(BluetoothAdapter adapter) {
4716570340f713d0c716ce4860f6f43d1efa230242aSharvil Nanavati        writeOutput("Disabling Bluetooth adapter.");
4726570340f713d0c716ce4860f6f43d1efa230242aSharvil Nanavati        assertTrue(adapter.isEnabled());
473571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        int btState = adapter.getState();
474571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        final Semaphore completionSemaphore = new Semaphore(0);
475571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        final BroadcastReceiver receiver = new BroadcastReceiver() {
476571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou            @Override
477571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou            public void onReceive(Context context, Intent intent) {
478571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou                final String action = intent.getAction();
479571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou                if (!BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
480571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou                    return;
481571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou                }
482571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou                final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
483571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou                        BluetoothAdapter.ERROR);
484571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou                if (state == BluetoothAdapter.STATE_OFF) {
485571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou                    completionSemaphore.release();
486185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe                }
487185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            }
488571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        };
489185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
490571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
491571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        mContext.registerReceiver(receiver, filter);
492571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        assertTrue(adapter.disable());
493571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        boolean success = false;
494571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        try {
495571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou            success = completionSemaphore.tryAcquire(ENABLE_DISABLE_TIMEOUT, TimeUnit.MILLISECONDS);
496571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou            writeOutput(String.format("disable() completed in 0 ms"));
497571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        } catch (final InterruptedException e) {
498571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou            // This should never happen but just in case it does, the test will fail anyway.
499571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        }
500571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        mContext.unregisterReceiver(receiver);
501571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        if (!success) {
502571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou            fail(String.format("disable() timeout: state=%d (expected %d)", btState,
503571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou                    BluetoothAdapter.STATE_OFF));
504571a4a97cde06766921335d352fdff2a7b335a58Yuchao Zhou        }
505185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    }
506185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
5077e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
5087e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Puts the local device into discoverable mode and checks to make sure that the local device
5097e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * is in discoverable mode and that the correct actions were broadcast.
5107e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
5117e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
5127e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
513185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    public void discoverable(BluetoothAdapter adapter) {
514185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        if (!adapter.isEnabled()) {
515185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            fail("discoverable() bluetooth not enabled");
516185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
517185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
518185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        int scanMode = adapter.getScanMode();
519f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        if (scanMode != BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
520185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            return;
521185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
522185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
523f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        final Semaphore completionSemaphore = new Semaphore(0);
524f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        final BroadcastReceiver receiver = new BroadcastReceiver() {
525f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati            @Override
526f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati            public void onReceive(Context context, Intent intent) {
527f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                final String action = intent.getAction();
528f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                if (!BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action)) {
529f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                    return;
530f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                }
531f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                final int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE,
532f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                        BluetoothAdapter.SCAN_MODE_NONE);
533f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                if (mode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
534f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                    completionSemaphore.release();
535f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                }
536f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati            }
537f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        };
538826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
539f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
540f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        mContext.registerReceiver(receiver, filter);
541185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE));
542f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        boolean success = false;
543f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        try {
544f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati            success = completionSemaphore.tryAcquire(DISCOVERABLE_UNDISCOVERABLE_TIMEOUT,
545f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                    TimeUnit.MILLISECONDS);
546957abc831866470c5344750d70d2462e8676c4a7Sharvil Nanavati            writeOutput(String.format("discoverable() completed in 0 ms"));
547f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        } catch (final InterruptedException e) {
548f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati            // This should never happen but just in case it does, the test will fail anyway.
549f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        }
550f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        mContext.unregisterReceiver(receiver);
551f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        if (!success) {
552f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati            fail(String.format("discoverable() timeout: scanMode=%d (expected %d)", scanMode,
553f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                    BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE));
554185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
555185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    }
556185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
5577e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
5587e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Puts the local device into connectable only mode and checks to make sure that the local
5597e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * device is in in connectable mode and that the correct actions were broadcast.
5607e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
5617e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
5627e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
563185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    public void undiscoverable(BluetoothAdapter adapter) {
564185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        if (!adapter.isEnabled()) {
565185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            fail("undiscoverable() bluetooth not enabled");
566185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
567185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
568185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        int scanMode = adapter.getScanMode();
569f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        if (scanMode != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
570185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            return;
571185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
572185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
573f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        final Semaphore completionSemaphore = new Semaphore(0);
574f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        final BroadcastReceiver receiver = new BroadcastReceiver() {
575f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati            @Override
576f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati            public void onReceive(Context context, Intent intent) {
577f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                final String action = intent.getAction();
578f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                if (!BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action)) {
579f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                    return;
580f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                }
581f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                final int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE,
582f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                        BluetoothAdapter.SCAN_MODE_NONE);
583f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                if (mode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
584f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                    completionSemaphore.release();
585f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                }
586f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati            }
587f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        };
588826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
589f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
590f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        mContext.registerReceiver(receiver, filter);
591185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE));
592f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        boolean success = false;
593f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        try {
594f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati            success = completionSemaphore.tryAcquire(DISCOVERABLE_UNDISCOVERABLE_TIMEOUT,
595f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                    TimeUnit.MILLISECONDS);
596957abc831866470c5344750d70d2462e8676c4a7Sharvil Nanavati            writeOutput(String.format("undiscoverable() completed in 0 ms"));
597f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        } catch (InterruptedException e) {
598f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati            // This should never happen but just in case it does, the test will fail anyway.
599f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        }
600f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        mContext.unregisterReceiver(receiver);
601f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati        if (!success) {
602f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati            fail(String.format("undiscoverable() timeout: scanMode=%d (expected %d)", scanMode,
603f6aebbe4bd8a1999383b3eb485bf5d21ec5867d8Sharvil Nanavati                    BluetoothAdapter.SCAN_MODE_CONNECTABLE));
604185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
605185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    }
606185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
6077e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
6087e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Starts a scan for remote devices and checks to make sure that the local device is scanning
6097e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * and that the correct actions were broadcast.
6107e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
6117e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
6127e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
613185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    public void startScan(BluetoothAdapter adapter) {
614826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        int mask = BluetoothReceiver.DISCOVERY_STARTED_FLAG;
615185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
616185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        if (!adapter.isEnabled()) {
617185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            fail("startScan() bluetooth not enabled");
618185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
619185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
620185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        if (adapter.isDiscovering()) {
621185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            return;
622185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
623185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
624826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        BluetoothReceiver receiver = getBluetoothReceiver(mask);
625826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
626826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        long start = System.currentTimeMillis();
627185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        assertTrue(adapter.startDiscovery());
628185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
629207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe        while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) {
630826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            if (adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) {
631185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe                writeOutput(String.format("startScan() completed in %d ms",
632826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        (receiver.getCompletedTime() - start)));
633826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                removeReceiver(receiver);
634185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe                return;
635185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            }
636185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            sleep(POLL_TIME);
637185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
638185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
639826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        int firedFlags = receiver.getFiredFlags();
640826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        removeReceiver(receiver);
641185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        fail(String.format("startScan() timeout: isDiscovering=%b, flags=0x%x (expected 0x%x)",
642185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe                adapter.isDiscovering(), firedFlags, mask));
643185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    }
644185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
6457e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
6467e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Stops a scan for remote devices and checks to make sure that the local device is not scanning
6477e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * and that the correct actions were broadcast.
6487e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
6497e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
6507e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
651185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    public void stopScan(BluetoothAdapter adapter) {
652826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        int mask = BluetoothReceiver.DISCOVERY_FINISHED_FLAG;
653185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
654185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        if (!adapter.isEnabled()) {
655185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            fail("stopScan() bluetooth not enabled");
656185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
657185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
658185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        if (!adapter.isDiscovering()) {
659185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            return;
660185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
661185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
662826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        BluetoothReceiver receiver = getBluetoothReceiver(mask);
663826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
664826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        long start = System.currentTimeMillis();
665efc1d16374955f04d713c770ab47d90d190afe83Albert Mojir        assertTrue(adapter.cancelDiscovery());
666185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
667207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe        while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) {
668826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            if (!adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) {
669185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe                writeOutput(String.format("stopScan() completed in %d ms",
670826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                        (receiver.getCompletedTime() - start)));
671826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                removeReceiver(receiver);
672185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe                return;
673185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            }
674185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            sleep(POLL_TIME);
675185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
676185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
677826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        int firedFlags = receiver.getFiredFlags();
678826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        removeReceiver(receiver);
679185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        fail(String.format("stopScan() timeout: isDiscovering=%b, flags=0x%x (expected 0x%x)",
680185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe                adapter.isDiscovering(), firedFlags, mask));
681185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
682185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    }
683185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
6847e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
6857e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Enables PAN tethering on the local device and checks to make sure that tethering is enabled.
6867e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
6877e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
6887e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
6897e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    public void enablePan(BluetoothAdapter adapter) {
69074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
69174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        assertNotNull(mPan);
6927e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
6937e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        long start = System.currentTimeMillis();
69474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        mPan.setBluetoothTethering(true);
6957e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        long stop = System.currentTimeMillis();
69674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        assertTrue(mPan.isTetheringOn());
6977e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
6987e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        writeOutput(String.format("enablePan() completed in %d ms", (stop - start)));
6997e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    }
7007e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
7017e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
7027e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Disables PAN tethering on the local device and checks to make sure that tethering is
7037e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * disabled.
7047e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
7057e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
7067e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
7077e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    public void disablePan(BluetoothAdapter adapter) {
70874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
70974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        assertNotNull(mPan);
7107e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
7117e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        long start = System.currentTimeMillis();
71274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        mPan.setBluetoothTethering(false);
7137e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        long stop = System.currentTimeMillis();
71474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        assertFalse(mPan.isTetheringOn());
7157e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
7167e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        writeOutput(String.format("disablePan() completed in %d ms", (stop - start)));
7177e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    }
7187e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
7197e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
7207e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Initiates a pairing with a remote device and checks to make sure that the devices are paired
7217e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * and that the correct actions were broadcast.
7227e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
7237e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
7247e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param device The remote device.
7257e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
7267e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param pin The pairing pin if pairing requires a pin. Any value if not.
7277e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
728826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    public void pair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, byte[] pin) {
72923c067692be74c4fcd50cea48f9d469ba5288213Eric Rowe        pairOrAcceptPair(adapter, device, passkey, pin, true);
73023c067692be74c4fcd50cea48f9d469ba5288213Eric Rowe    }
73123c067692be74c4fcd50cea48f9d469ba5288213Eric Rowe
7327e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
7337e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Accepts a pairing with a remote device and checks to make sure that the devices are paired
7347e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * and that the correct actions were broadcast.
7357e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
7367e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
7377e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param device The remote device.
7387e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
7397e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param pin The pairing pin if pairing requires a pin. Any value if not.
7407e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
74123c067692be74c4fcd50cea48f9d469ba5288213Eric Rowe    public void acceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey,
74223c067692be74c4fcd50cea48f9d469ba5288213Eric Rowe            byte[] pin) {
74323c067692be74c4fcd50cea48f9d469ba5288213Eric Rowe        pairOrAcceptPair(adapter, device, passkey, pin, false);
74423c067692be74c4fcd50cea48f9d469ba5288213Eric Rowe    }
74523c067692be74c4fcd50cea48f9d469ba5288213Eric Rowe
7467e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
7477e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Helper method used by {@link #pair(BluetoothAdapter, BluetoothDevice, int, byte[])} and
7487e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * {@link #acceptPair(BluetoothAdapter, BluetoothDevice, int, byte[])} to either pair or accept
7497e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * a pairing request.
7507e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
7517e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
7527e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param device The remote device.
7537e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
7547e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param pin The pairing pin if pairing requires a pin. Any value if not.
7557e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param shouldPair Whether to pair or accept the pair.
7567e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
75723c067692be74c4fcd50cea48f9d469ba5288213Eric Rowe    private void pairOrAcceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey,
7587e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            byte[] pin, boolean shouldPair) {
759826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        int mask = PairReceiver.STATE_BONDING_FLAG | PairReceiver.STATE_BONDED_FLAG;
760826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        long start = -1;
7612b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        String methodName;
7622b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        if (shouldPair) {
7632b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            methodName = String.format("pair(device=%s)", device);
7642b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        } else {
7652b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            methodName = String.format("acceptPair(device=%s)", device);
7662b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        }
767826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
768826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        if (!adapter.isEnabled()) {
7692b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            fail(String.format("%s bluetooth not enabled", methodName));
770826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
771826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
772826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        PairReceiver receiver = getPairReceiver(device, passkey, pin, mask);
773826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
774826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        int state = device.getBondState();
775826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        switch (state) {
776826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            case BluetoothDevice.BOND_NONE:
777826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                assertFalse(adapter.getBondedDevices().contains(device));
778826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                start = System.currentTimeMillis();
7797e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                if (shouldPair) {
78023c067692be74c4fcd50cea48f9d469ba5288213Eric Rowe                    assertTrue(device.createBond());
78123c067692be74c4fcd50cea48f9d469ba5288213Eric Rowe                }
782826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                break;
783826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            case BluetoothDevice.BOND_BONDING:
784826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                mask = 0; // Don't check for received intents since we might have missed them.
785826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                break;
786826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            case BluetoothDevice.BOND_BONDED:
787826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                assertTrue(adapter.getBondedDevices().contains(device));
788826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                return;
789826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            default:
790826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                removeReceiver(receiver);
7912b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                fail(String.format("%s invalid state: state=%d", methodName, state));
792826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
793826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
794826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        long s = System.currentTimeMillis();
795207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe        while (System.currentTimeMillis() - s < PAIR_UNPAIR_TIMEOUT) {
796826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            state = device.getBondState();
797207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe            if (state == BluetoothDevice.BOND_BONDED && (receiver.getFiredFlags() & mask) == mask) {
798826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                assertTrue(adapter.getBondedDevices().contains(device));
799207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                long finish = receiver.getCompletedTime();
800207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                if (start != -1 && finish != -1) {
8012b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    writeOutput(String.format("%s completed in %d ms", methodName,
8022b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                            (finish - start)));
803207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                } else {
8042b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    writeOutput(String.format("%s completed", methodName));
805826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                }
806207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                removeReceiver(receiver);
807207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                return;
808826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            }
809826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            sleep(POLL_TIME);
810826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
811826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
812826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        int firedFlags = receiver.getFiredFlags();
813826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        removeReceiver(receiver);
8142b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
8152b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask));
816826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    }
817826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
8187e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
8197e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Deletes a pairing with a remote device and checks to make sure that the devices are unpaired
8207e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * and that the correct actions were broadcast.
8217e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
8227e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
8237e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param device The remote device.
8247e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
825826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    public void unpair(BluetoothAdapter adapter, BluetoothDevice device) {
826826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        int mask = PairReceiver.STATE_NONE_FLAG;
827826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        long start = -1;
8282b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        String methodName = String.format("unpair(device=%s)", device);
829826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
830826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        if (!adapter.isEnabled()) {
8312b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            fail(String.format("%s bluetooth not enabled", methodName));
832826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
833826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
834826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        PairReceiver receiver = getPairReceiver(device, 0, null, mask);
835826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
836826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        int state = device.getBondState();
837826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        switch (state) {
838826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            case BluetoothDevice.BOND_NONE:
839826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                assertFalse(adapter.getBondedDevices().contains(device));
840826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                removeReceiver(receiver);
841826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                return;
842826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            case BluetoothDevice.BOND_BONDING:
843826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                start = System.currentTimeMillis();
844826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                assertTrue(device.removeBond());
845826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                break;
846826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            case BluetoothDevice.BOND_BONDED:
847826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                assertTrue(adapter.getBondedDevices().contains(device));
848826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                start = System.currentTimeMillis();
849826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                assertTrue(device.removeBond());
850826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                break;
851826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            default:
852826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                removeReceiver(receiver);
8532b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                fail(String.format("%s invalid state: state=%d", methodName, state));
854826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
855826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
856826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        long s = System.currentTimeMillis();
857207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe        while (System.currentTimeMillis() - s < PAIR_UNPAIR_TIMEOUT) {
858207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe            if (device.getBondState() == BluetoothDevice.BOND_NONE
859207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                    && (receiver.getFiredFlags() & mask) == mask) {
860826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                assertFalse(adapter.getBondedDevices().contains(device));
861207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                long finish = receiver.getCompletedTime();
862207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                if (start != -1 && finish != -1) {
8632b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    writeOutput(String.format("%s completed in %d ms", methodName,
8642b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                            (finish - start)));
865207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                } else {
8662b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    writeOutput(String.format("%s completed", methodName));
867826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                }
868207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                removeReceiver(receiver);
869207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                return;
870826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            }
871826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
872826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
873826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        int firedFlags = receiver.getFiredFlags();
874826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        removeReceiver(receiver);
8752b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
8762b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask));
877826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    }
878826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
8797e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
88003800b8873f70223dcfcf396a3762775dfc1a8abGuang Zhu     * Deletes all pairings of remote devices
88103800b8873f70223dcfcf396a3762775dfc1a8abGuang Zhu     * @param adapter the BT adapter
88203800b8873f70223dcfcf396a3762775dfc1a8abGuang Zhu     */
88303800b8873f70223dcfcf396a3762775dfc1a8abGuang Zhu    public void unpairAll(BluetoothAdapter adapter) {
88403800b8873f70223dcfcf396a3762775dfc1a8abGuang Zhu        Set<BluetoothDevice> devices = adapter.getBondedDevices();
88503800b8873f70223dcfcf396a3762775dfc1a8abGuang Zhu        for (BluetoothDevice device : devices) {
88603800b8873f70223dcfcf396a3762775dfc1a8abGuang Zhu            unpair(adapter, device);
88703800b8873f70223dcfcf396a3762775dfc1a8abGuang Zhu        }
88803800b8873f70223dcfcf396a3762775dfc1a8abGuang Zhu    }
88903800b8873f70223dcfcf396a3762775dfc1a8abGuang Zhu
89003800b8873f70223dcfcf396a3762775dfc1a8abGuang Zhu    /**
8917e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Connects a profile from the local device to a remote device and checks to make sure that the
8927e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * profile is connected and that the correct actions were broadcast.
8937e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
8947e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
8957e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param device The remote device.
8962b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe     * @param profile The profile to connect. One of {@link BluetoothProfile#A2DP},
897c26c76c63d933f8057f795d05624f91b811c8c71Hansong Zhang     * {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#HID_HOST}.
8982b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe     * @param methodName The method name to printed in the logs.  If null, will be
8992b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe     * "connectProfile(profile=&lt;profile&gt;, device=&lt;device&gt;)"
9007e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
9012b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe    public void connectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile,
9022b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            String methodName) {
9032b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        if (methodName == null) {
9042b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            methodName = String.format("connectProfile(profile=%d, device=%s)", profile, device);
9052b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        }
906826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        int mask = (ConnectProfileReceiver.STATE_CONNECTING_FLAG
907826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                | ConnectProfileReceiver.STATE_CONNECTED_FLAG);
908826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        long start = -1;
909826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
910826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        if (!adapter.isEnabled()) {
9112b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            fail(String.format("%s bluetooth not enabled", methodName));
912826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
913826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
914826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        if (!adapter.getBondedDevices().contains(device)) {
9152b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            fail(String.format("%s device not paired", methodName));
916826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
917826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
918826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        BluetoothProfile proxy = connectProxy(adapter, profile);
9192b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        assertNotNull(proxy);
920826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
921826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        ConnectProfileReceiver receiver = getConnectProfileReceiver(device, profile, mask);
922826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
923826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        int state = proxy.getConnectionState(device);
924826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        switch (state) {
925826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            case BluetoothProfile.STATE_CONNECTED:
926826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                removeReceiver(receiver);
927826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                return;
928826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            case BluetoothProfile.STATE_CONNECTING:
929826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                mask = 0; // Don't check for received intents since we might have missed them.
930826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                break;
931826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            case BluetoothProfile.STATE_DISCONNECTED:
932826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            case BluetoothProfile.STATE_DISCONNECTING:
933826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                start = System.currentTimeMillis();
934f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh                if (profile == BluetoothProfile.A2DP) {
935f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh                    assertTrue(((BluetoothA2dp)proxy).connect(device));
936f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh                } else if (profile == BluetoothProfile.HEADSET) {
937f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh                    assertTrue(((BluetoothHeadset)proxy).connect(device));
938c26c76c63d933f8057f795d05624f91b811c8c71Hansong Zhang                } else if (profile == BluetoothProfile.HID_HOST) {
939c26c76c63d933f8057f795d05624f91b811c8c71Hansong Zhang                    assertTrue(((BluetoothHidHost)proxy).connect(device));
940f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh                }
941826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                break;
942826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            default:
943826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                removeReceiver(receiver);
9442b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                fail(String.format("%s invalid state: state=%d", methodName, state));
945826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
946826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
947826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        long s = System.currentTimeMillis();
948207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
949826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            state = proxy.getConnectionState(device);
950207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe            if (state == BluetoothProfile.STATE_CONNECTED
951207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                    && (receiver.getFiredFlags() & mask) == mask) {
952207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                long finish = receiver.getCompletedTime();
953207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                if (start != -1 && finish != -1) {
9542b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    writeOutput(String.format("%s completed in %d ms", methodName,
9552b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                            (finish - start)));
956207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                } else {
9572b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    writeOutput(String.format("%s completed", methodName));
958826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                }
959207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                removeReceiver(receiver);
960207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                return;
961826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            }
962826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            sleep(POLL_TIME);
963826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
964826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
965826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        int firedFlags = receiver.getFiredFlags();
966826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        removeReceiver(receiver);
9672b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
9682b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                methodName, state, BluetoothProfile.STATE_CONNECTED, firedFlags, mask));
969826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    }
970826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
9717e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
9727e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Disconnects a profile between the local device and a remote device and checks to make sure
9737e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * that the profile is disconnected and that the correct actions were broadcast.
9747e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
9757e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
9767e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param device The remote device.
9772b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe     * @param profile The profile to disconnect. One of {@link BluetoothProfile#A2DP},
978c26c76c63d933f8057f795d05624f91b811c8c71Hansong Zhang     * {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#HID_HOST}.
9792b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe     * @param methodName The method name to printed in the logs.  If null, will be
9802b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe     * "connectProfile(profile=&lt;profile&gt;, device=&lt;device&gt;)"
9817e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
9822b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe    public void disconnectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile,
9832b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            String methodName) {
9842b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        if (methodName == null) {
9852b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            methodName = String.format("disconnectProfile(profile=%d, device=%s)", profile, device);
9862b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        }
987826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        int mask = (ConnectProfileReceiver.STATE_DISCONNECTING_FLAG
988826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                | ConnectProfileReceiver.STATE_DISCONNECTED_FLAG);
989826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        long start = -1;
990826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
991826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        if (!adapter.isEnabled()) {
9922b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            fail(String.format("%s bluetooth not enabled", methodName));
993826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
994826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
995826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        if (!adapter.getBondedDevices().contains(device)) {
9962b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            fail(String.format("%s device not paired", methodName));
997826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
998826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
999826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        BluetoothProfile proxy = connectProxy(adapter, profile);
10002b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        assertNotNull(proxy);
1001826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
1002826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        ConnectProfileReceiver receiver = getConnectProfileReceiver(device, profile, mask);
1003826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
1004826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        int state = proxy.getConnectionState(device);
1005826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        switch (state) {
1006826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            case BluetoothProfile.STATE_CONNECTED:
1007826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            case BluetoothProfile.STATE_CONNECTING:
1008826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                start = System.currentTimeMillis();
1009f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh                if (profile == BluetoothProfile.A2DP) {
1010f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh                    assertTrue(((BluetoothA2dp)proxy).disconnect(device));
1011f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh                } else if (profile == BluetoothProfile.HEADSET) {
1012f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh                    assertTrue(((BluetoothHeadset)proxy).disconnect(device));
1013c26c76c63d933f8057f795d05624f91b811c8c71Hansong Zhang                } else if (profile == BluetoothProfile.HID_HOST) {
1014c26c76c63d933f8057f795d05624f91b811c8c71Hansong Zhang                    assertTrue(((BluetoothHidHost)proxy).disconnect(device));
1015f8789167e903b637b1dbe8f710e7c66c4cfd74fdJaikumar Ganesh                }
1016826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                break;
1017826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            case BluetoothProfile.STATE_DISCONNECTED:
1018826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                removeReceiver(receiver);
1019826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                return;
1020826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            case BluetoothProfile.STATE_DISCONNECTING:
1021826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                mask = 0; // Don't check for received intents since we might have missed them.
1022826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                break;
1023826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            default:
1024826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                removeReceiver(receiver);
10252b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                fail(String.format("%s invalid state: state=%d", methodName, state));
1026826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
1027826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
1028826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        long s = System.currentTimeMillis();
1029207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
1030826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            state = proxy.getConnectionState(device);
1031207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe            if (state == BluetoothProfile.STATE_DISCONNECTED
1032207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                    && (receiver.getFiredFlags() & mask) == mask) {
1033207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                long finish = receiver.getCompletedTime();
1034207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                if (start != -1 && finish != -1) {
10352b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    writeOutput(String.format("%s completed in %d ms", methodName,
10362b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                            (finish - start)));
1037207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                } else {
10382b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    writeOutput(String.format("%s completed", methodName));
1039826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                }
1040207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                removeReceiver(receiver);
1041207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                return;
1042826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            }
1043826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            sleep(POLL_TIME);
1044826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
1045826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
1046826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        int firedFlags = receiver.getFiredFlags();
1047826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        removeReceiver(receiver);
10482b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
10492b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                methodName, state, BluetoothProfile.STATE_DISCONNECTED, firedFlags, mask));
1050826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    }
1051826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
10527e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
10537e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Connects the PANU to a remote NAP and checks to make sure that the PANU is connected and that
10547e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * the correct actions were broadcast.
10557e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
10567e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
10577e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param device The remote device.
10587e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
10597e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    public void connectPan(BluetoothAdapter adapter, BluetoothDevice device) {
10607e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        connectPanOrIncomingPanConnection(adapter, device, true);
10617e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    }
10627e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
10637e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
10647e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Checks that a remote PANU connects to the local NAP correctly and that the correct actions
10657e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * were broadcast.
10667e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
10677e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
10687e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param device The remote device.
10697e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
10707e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    public void incomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device) {
10717e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        connectPanOrIncomingPanConnection(adapter, device, false);
10727e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    }
10737e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
10747e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
10757e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Helper method used by {@link #connectPan(BluetoothAdapter, BluetoothDevice)} and
10767e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * {@link #incomingPanConnection(BluetoothAdapter, BluetoothDevice)} to either connect to a
10777e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * remote NAP or verify that a remote device connected to the local NAP.
10787e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
10797e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
10807e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param device The remote device.
10817e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param connect If the method should initiate the connection (is PANU)
10827e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
10837e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    private void connectPanOrIncomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device,
10847e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            boolean connect) {
10857e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        long start = -1;
10867e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        int mask, role;
10877e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        String methodName;
10887e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
10897e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        if (connect) {
10902b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            methodName = String.format("connectPan(device=%s)", device);
10912b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            mask = (ConnectProfileReceiver.STATE_CONNECTED_FLAG |
10922b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    ConnectProfileReceiver.STATE_CONNECTING_FLAG);
10937e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            role = BluetoothPan.LOCAL_PANU_ROLE;
10947e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        } else {
10952b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            methodName = String.format("incomingPanConnection(device=%s)", device);
10962b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            mask = ConnectProfileReceiver.STATE_CONNECTED_FLAG;
10977e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            role = BluetoothPan.LOCAL_NAP_ROLE;
10987e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        }
10997e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
11007e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        if (!adapter.isEnabled()) {
11012b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            fail(String.format("%s bluetooth not enabled", methodName));
11027e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        }
11037e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
11047e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        if (!adapter.getBondedDevices().contains(device)) {
11052b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            fail(String.format("%s device not paired", methodName));
11067e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        }
11077e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
11082b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
110974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        assertNotNull(mPan);
11107e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
11117e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
111274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        int state = mPan.getConnectionState(device);
11137e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        switch (state) {
11147e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            case BluetoothPan.STATE_CONNECTED:
11157e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                removeReceiver(receiver);
11167e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                return;
11177e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            case BluetoothPan.STATE_CONNECTING:
11187e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                mask = 0; // Don't check for received intents since we might have missed them.
11197e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                break;
11207e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            case BluetoothPan.STATE_DISCONNECTED:
11217e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            case BluetoothPan.STATE_DISCONNECTING:
11227e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                start = System.currentTimeMillis();
11237e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                if (role == BluetoothPan.LOCAL_PANU_ROLE) {
11247e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                    Log.i("BT", "connect to pan");
112574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                    assertTrue(mPan.connect(device));
11267e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                }
11277e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                break;
11287e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            default:
11297e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                removeReceiver(receiver);
11302b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                fail(String.format("%s invalid state: state=%d", methodName, state));
11317e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        }
11327e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
11337e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        long s = System.currentTimeMillis();
11347e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
113574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            state = mPan.getConnectionState(device);
11367e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            if (state == BluetoothPan.STATE_CONNECTED
11377e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                    && (receiver.getFiredFlags() & mask) == mask) {
11387e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                long finish = receiver.getCompletedTime();
11397e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                if (start != -1 && finish != -1) {
11402b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    writeOutput(String.format("%s completed in %d ms", methodName,
11412b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                            (finish - start)));
11427e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                } else {
11432b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    writeOutput(String.format("%s completed", methodName));
11447e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                }
11457e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                removeReceiver(receiver);
11467e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                return;
11477e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            }
11487e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            sleep(POLL_TIME);
11497e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        }
11507e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
11517e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        int firedFlags = receiver.getFiredFlags();
11527e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        removeReceiver(receiver);
11532b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)",
11542b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                methodName, state, BluetoothPan.STATE_CONNECTED, firedFlags, mask));
11557e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    }
11567e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
11577e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
11587e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Disconnects the PANU from a remote NAP and checks to make sure that the PANU is disconnected
11597e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * and that the correct actions were broadcast.
11607e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
11617e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
11627e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param device The remote device.
11637e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
11647e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    public void disconnectPan(BluetoothAdapter adapter, BluetoothDevice device) {
11657e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        disconnectFromRemoteOrVerifyConnectNap(adapter, device, true);
11667e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    }
11677e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
11687e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
11697e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Checks that a remote PANU disconnects from the local NAP correctly and that the correct
11707e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * actions were broadcast.
11717e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
11727e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
11737e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param device The remote device.
11747e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
11757e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    public void incomingPanDisconnection(BluetoothAdapter adapter, BluetoothDevice device) {
11767e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        disconnectFromRemoteOrVerifyConnectNap(adapter, device, false);
11777e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    }
11787e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
11797e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
11807e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Helper method used by {@link #disconnectPan(BluetoothAdapter, BluetoothDevice)} and
11817e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * {@link #incomingPanDisconnection(BluetoothAdapter, BluetoothDevice)} to either disconnect
11827e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * from a remote NAP or verify that a remote device disconnected from the local NAP.
11837e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
11847e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param adapter The BT adapter.
11857e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param device The remote device.
11867e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param disconnect Whether the method should connect or verify.
11877e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
11887e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    private void disconnectFromRemoteOrVerifyConnectNap(BluetoothAdapter adapter,
11897e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            BluetoothDevice device, boolean disconnect) {
11907e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        long start = -1;
11917e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        int mask, role;
11927e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        String methodName;
11937e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
11947e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        if (disconnect) {
11952b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            methodName = String.format("disconnectPan(device=%s)", device);
11962b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            mask = (ConnectProfileReceiver.STATE_DISCONNECTED_FLAG |
11972b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    ConnectProfileReceiver.STATE_DISCONNECTING_FLAG);
11987e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            role = BluetoothPan.LOCAL_PANU_ROLE;
11997e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        } else {
12002b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            methodName = String.format("incomingPanDisconnection(device=%s)", device);
12012b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            mask = ConnectProfileReceiver.STATE_DISCONNECTED_FLAG;
12027e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            role = BluetoothPan.LOCAL_NAP_ROLE;
12037e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        }
12047e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
12057e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        if (!adapter.isEnabled()) {
12062b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            fail(String.format("%s bluetooth not enabled", methodName));
12077e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        }
12087e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
12097e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        if (!adapter.getBondedDevices().contains(device)) {
12102b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            fail(String.format("%s device not paired", methodName));
12117e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        }
12127e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
12132b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
121474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        assertNotNull(mPan);
12157e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
12167e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
121774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        int state = mPan.getConnectionState(device);
12187e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        switch (state) {
121974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            case BluetoothPan.STATE_CONNECTED:
122074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            case BluetoothPan.STATE_CONNECTING:
12217e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                start = System.currentTimeMillis();
12227e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                if (role == BluetoothPan.LOCAL_PANU_ROLE) {
122374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                    assertTrue(mPan.disconnect(device));
12247e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                }
12257e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                break;
122674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            case BluetoothPan.STATE_DISCONNECTED:
12277e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                removeReceiver(receiver);
12287e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                return;
122974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            case BluetoothPan.STATE_DISCONNECTING:
12307e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                mask = 0; // Don't check for received intents since we might have missed them.
12317e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                break;
12327e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            default:
12337e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                removeReceiver(receiver);
12342b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                fail(String.format("%s invalid state: state=%d", methodName, state));
12357e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        }
12367e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
12377e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        long s = System.currentTimeMillis();
12387e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
123974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            state = mPan.getConnectionState(device);
1240c26c76c63d933f8057f795d05624f91b811c8c71Hansong Zhang            if (state == BluetoothHidHost.STATE_DISCONNECTED
12417e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                    && (receiver.getFiredFlags() & mask) == mask) {
12427e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                long finish = receiver.getCompletedTime();
12437e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                if (start != -1 && finish != -1) {
12442b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    writeOutput(String.format("%s completed in %d ms", methodName,
12452b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                            (finish - start)));
12467e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                } else {
12472b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    writeOutput(String.format("%s completed", methodName));
12487e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                }
12497e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                removeReceiver(receiver);
12507e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe                return;
12517e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            }
12527e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            sleep(POLL_TIME);
12537e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        }
12547e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
12557e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        int firedFlags = receiver.getFiredFlags();
12567e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        removeReceiver(receiver);
12572b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)",
1258c26c76c63d933f8057f795d05624f91b811c8c71Hansong Zhang                methodName, state, BluetoothHidHost.STATE_DISCONNECTED, firedFlags, mask));
12597e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    }
12607e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
12617e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    /**
1262835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     * Opens a SCO channel using {@link android.media.AudioManager#startBluetoothSco()} and checks
1263835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     * to make sure that the channel is opened and that the correct actions were broadcast.
1264835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     *
1265835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     * @param adapter The BT adapter.
1266835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     * @param device The remote device.
1267835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     */
1268835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe    public void startSco(BluetoothAdapter adapter, BluetoothDevice device) {
1269835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        startStopSco(adapter, device, true);
1270835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe    }
1271835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe
1272835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe    /**
1273835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     * Closes a SCO channel using {@link android.media.AudioManager#stopBluetoothSco()} and checks
1274835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     *  to make sure that the channel is closed and that the correct actions were broadcast.
1275835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     *
1276835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     * @param adapter The BT adapter.
1277835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     * @param device The remote device.
1278835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     */
1279835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe    public void stopSco(BluetoothAdapter adapter, BluetoothDevice device) {
1280835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        startStopSco(adapter, device, false);
1281835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe    }
1282835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe    /**
1283835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     * Helper method for {@link #startSco(BluetoothAdapter, BluetoothDevice)} and
1284835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     * {@link #stopSco(BluetoothAdapter, BluetoothDevice)}.
1285835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     *
1286835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     * @param adapter The BT adapter.
1287835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     * @param device The remote device.
1288835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     * @param isStart Whether the SCO channel should be opened.
1289835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe     */
1290835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe    private void startStopSco(BluetoothAdapter adapter, BluetoothDevice device, boolean isStart) {
1291835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        long start = -1;
1292835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        int mask;
1293835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        String methodName;
1294835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe
1295835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        if (isStart) {
12962b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            methodName = String.format("startSco(device=%s)", device);
1297835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe            mask = StartStopScoReceiver.STATE_CONNECTED_FLAG;
1298835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        } else {
12992b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            methodName = String.format("stopSco(device=%s)", device);
1300835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe            mask = StartStopScoReceiver.STATE_DISCONNECTED_FLAG;
1301835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        }
1302835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe
1303835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        if (!adapter.isEnabled()) {
13042b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            fail(String.format("%s bluetooth not enabled", methodName));
1305835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        }
1306835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe
1307835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        if (!adapter.getBondedDevices().contains(device)) {
13082b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            fail(String.format("%s device not paired", methodName));
1309835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        }
1310835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe
1311835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        AudioManager manager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
1312835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        assertNotNull(manager);
1313835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe
1314835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        if (!manager.isBluetoothScoAvailableOffCall()) {
13152b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            fail(String.format("%s device does not support SCO", methodName));
1316835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        }
1317835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe
1318835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        boolean isScoOn = manager.isBluetoothScoOn();
1319835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        if (isStart == isScoOn) {
1320835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe            return;
1321835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        }
1322835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe
1323835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        StartStopScoReceiver receiver = getStartStopScoReceiver(mask);
1324835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        start = System.currentTimeMillis();
1325835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        if (isStart) {
1326835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe            manager.startBluetoothSco();
1327835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        } else {
1328835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe            manager.stopBluetoothSco();
1329835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        }
1330835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe
1331835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        long s = System.currentTimeMillis();
1332835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        while (System.currentTimeMillis() - s < START_STOP_SCO_TIMEOUT) {
1333835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe            isScoOn = manager.isBluetoothScoOn();
13342b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            if (isStart == isScoOn && (receiver.getFiredFlags() & mask) == mask) {
1335835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                long finish = receiver.getCompletedTime();
1336835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                if (start != -1 && finish != -1) {
1337835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                    writeOutput(String.format("%s completed in %d ms", methodName,
1338835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                            (finish - start)));
1339835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                } else {
1340835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                    writeOutput(String.format("%s completed", methodName));
1341835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                }
1342835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                removeReceiver(receiver);
1343835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                return;
1344835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe            }
1345835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe            sleep(POLL_TIME);
1346835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        }
1347835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe
1348835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        int firedFlags = receiver.getFiredFlags();
1349835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        removeReceiver(receiver);
13502b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        fail(String.format("%s timeout: on=%b (expected %b), flags=0x%x (expected 0x%x)",
1351835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe                methodName, isScoOn, isStart, firedFlags, mask));
1352835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe    }
1353835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe
1354835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe    /**
13557e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * Writes a string to the logcat and a file if a file has been specified in the constructor.
13567e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     *
13577e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     * @param s The string to be written.
13587e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe     */
1359185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    public void writeOutput(String s) {
1360185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        Log.i(mTag, s);
1361185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        if (mOutputWriter == null) {
1362185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            return;
1363185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
1364185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        try {
1365185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            mOutputWriter.write(s + "\n");
1366185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            mOutputWriter.flush();
1367185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        } catch (IOException e) {
1368185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            Log.w(mTag, "Could not write to output file", e);
1369185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
1370185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    }
1371185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe
1372207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe    private void addReceiver(BroadcastReceiver receiver, String[] actions) {
1373826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        IntentFilter filter = new IntentFilter();
1374207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe        for (String action: actions) {
1375207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe            filter.addAction(action);
1376207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe        }
1377826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        mContext.registerReceiver(receiver, filter);
1378826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        mReceivers.add(receiver);
1379207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe    }
1380207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe
1381207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe    private BluetoothReceiver getBluetoothReceiver(int expectedFlags) {
1382207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe        String[] actions = {
1383207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                BluetoothAdapter.ACTION_DISCOVERY_FINISHED,
1384207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                BluetoothAdapter.ACTION_DISCOVERY_STARTED,
1385207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                BluetoothAdapter.ACTION_SCAN_MODE_CHANGED,
1386207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                BluetoothAdapter.ACTION_STATE_CHANGED};
1387207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe        BluetoothReceiver receiver = new BluetoothReceiver(expectedFlags);
1388207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe        addReceiver(receiver, actions);
1389826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        return receiver;
1390826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    }
1391826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
1392826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    private PairReceiver getPairReceiver(BluetoothDevice device, int passkey, byte[] pin,
1393826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            int expectedFlags) {
1394207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe        String[] actions = {
1395207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                BluetoothDevice.ACTION_PAIRING_REQUEST,
1396207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                BluetoothDevice.ACTION_BOND_STATE_CHANGED};
1397826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        PairReceiver receiver = new PairReceiver(device, passkey, pin, expectedFlags);
1398207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe        addReceiver(receiver, actions);
1399826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        return receiver;
1400826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    }
1401826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
1402826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    private ConnectProfileReceiver getConnectProfileReceiver(BluetoothDevice device, int profile,
1403826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            int expectedFlags) {
1404207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe        String[] actions = {
1405207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe                BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED,
14064ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED,
1407c26c76c63d933f8057f795d05624f91b811c8c71Hansong Zhang                BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED};
1408826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        ConnectProfileReceiver receiver = new ConnectProfileReceiver(device, profile,
1409826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                expectedFlags);
1410207c0a58012d5ce102760f33b5918d8b38c2af6bEric Rowe        addReceiver(receiver, actions);
1411826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        return receiver;
1412826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    }
1413826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
14147e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    private ConnectPanReceiver getConnectPanReceiver(BluetoothDevice device, int role,
14157e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe            int expectedFlags) {
141674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        String[] actions = {BluetoothPan.ACTION_CONNECTION_STATE_CHANGED};
14177e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        ConnectPanReceiver receiver = new ConnectPanReceiver(device, role, expectedFlags);
14187e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        addReceiver(receiver, actions);
14197e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe        return receiver;
14207e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe    }
14217e4d0c0982cb28a86bf3d45c3b316ec7eab1e017Eric Rowe
1422835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe    private StartStopScoReceiver getStartStopScoReceiver(int expectedFlags) {
1423fca8e9d919443449807f87203609e53a64368f6bEric Rowe        String[] actions = {AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED};
1424835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        StartStopScoReceiver receiver = new StartStopScoReceiver(expectedFlags);
1425835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        addReceiver(receiver, actions);
1426835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe        return receiver;
1427835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe    }
1428835d8ee61ecddcd3fdc0aadf500d05b914ca375fEric Rowe
1429826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    private void removeReceiver(BroadcastReceiver receiver) {
1430826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        mContext.unregisterReceiver(receiver);
1431826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        mReceivers.remove(receiver);
1432826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    }
1433826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
1434826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    private BluetoothProfile connectProxy(BluetoothAdapter adapter, int profile) {
14352b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        switch (profile) {
14362b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            case BluetoothProfile.A2DP:
14372b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                if (mA2dp != null) {
14382b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    return mA2dp;
14392b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                }
14402b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                break;
14412b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            case BluetoothProfile.HEADSET:
14422b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                if (mHeadset != null) {
14432b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    return mHeadset;
14442b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                }
14452b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                break;
1446c26c76c63d933f8057f795d05624f91b811c8c71Hansong Zhang            case BluetoothProfile.HID_HOST:
14472b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                if (mInput != null) {
14482b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    return mInput;
14492b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                }
14502b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                break;
14512b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            case BluetoothProfile.PAN:
14522b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                if (mPan != null) {
14532b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                    return mPan;
14542b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                }
14552b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                break;
14562b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe            default:
14572b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe                return null;
14582b1fb45fabcb6f6e6edfd1a7a8e394928a27afe8Eric Rowe        }
1459826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        adapter.getProfileProxy(mContext, mServiceListener, profile);
1460826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        long s = System.currentTimeMillis();
1461826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        switch (profile) {
1462826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            case BluetoothProfile.A2DP:
14634ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                while (mA2dp == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
1464826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    sleep(POLL_TIME);
1465826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                }
1466826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                return mA2dp;
1467826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            case BluetoothProfile.HEADSET:
14684ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                while (mHeadset == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
1469826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                    sleep(POLL_TIME);
1470826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                }
1471826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                return mHeadset;
1472c26c76c63d933f8057f795d05624f91b811c8c71Hansong Zhang            case BluetoothProfile.HID_HOST:
14734ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                while (mInput == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
14744ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                    sleep(POLL_TIME);
14754ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                }
14764ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                return mInput;
147774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            case BluetoothProfile.PAN:
147874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                while (mPan == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
147974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                    sleep(POLL_TIME);
148074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                }
148174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                return mPan;
1482826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe            default:
1483826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe                return null;
1484826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe        }
1485826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe    }
1486826af6266c79d76b81fe850b9cd3d351597e4adbEric Rowe
1487185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    private void sleep(long time) {
1488185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        try {
1489185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe            Thread.sleep(time);
1490185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        } catch (InterruptedException e) {
1491185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe        }
1492185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe    }
1493185a0b04c611a287cbd866d27b0ceff77f12d97bEric Rowe}
1494